├── .github ├── FUNDING.yml ├── tools │ ├── build-reproducible.sh │ ├── README.md │ └── reproducible.Dockerfile └── workflows │ ├── claude.yml │ ├── linux.yml │ ├── macos.yml │ └── release.yml ├── img ├── gf.png ├── gf_01.png └── luigi_example.png ├── san_ignore_list.txt ├── .gitignore ├── doc ├── release.md ├── profiler_instructions.txt ├── plugins.md ├── gdbf_profiling.c ├── contributing.md └── improvements.md ├── tests ├── reference_files │ └── test_input.cpp ├── re_gdb_tests.cpp ├── CMakeLists.txt ├── re_cpp_tests.cpp └── luigi_tests.cpp ├── deps └── include │ ├── boost │ ├── mp11 │ │ ├── mpl.hpp │ │ ├── version.hpp │ │ ├── detail │ │ │ ├── mp_list.hpp │ │ │ ├── mp_list_v.hpp │ │ │ ├── mp_value.hpp │ │ │ ├── mp_void.hpp │ │ │ ├── mp_is_list.hpp │ │ │ ├── mp_is_value_list.hpp │ │ │ ├── mp_front.hpp │ │ │ ├── mp_copy_if.hpp │ │ │ ├── mp_remove_if.hpp │ │ │ ├── mp_min_element.hpp │ │ │ ├── mp_rename.hpp │ │ │ ├── mp_map_find.hpp │ │ │ ├── mp_plus.hpp │ │ │ ├── mp_defer.hpp │ │ │ ├── mpl_common.hpp │ │ │ ├── config.hpp │ │ │ ├── mp_count.hpp │ │ │ └── mp_fold.hpp │ │ ├── mpl_list.hpp │ │ ├── mpl_tuple.hpp │ │ ├── integral.hpp │ │ ├── bind.hpp │ │ ├── integer_sequence.hpp │ │ ├── map.hpp │ │ ├── utility.hpp │ │ ├── function.hpp │ │ ├── set.hpp │ │ ├── tuple.hpp │ │ └── lambda.hpp │ └── mp11.hpp │ └── nlohmann │ ├── LICENSE.MIT │ └── json_fwd.hpp ├── examples ├── CMakeLists.txt ├── gdbf_testprog.cpp ├── gf2_config.ini ├── donut.cpp ├── tinyraytracer.cpp └── luigi_example.cpp ├── .dockerignore ├── src ├── re │ ├── misc.cpp │ ├── gdb.cpp │ ├── re.hpp │ └── cpp.cpp ├── main.cpp └── utils.hpp ├── .clang-format ├── LICENSE └── CMakeLists.txt /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: greg7mdp 2 | -------------------------------------------------------------------------------- /img/gf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greg7mdp/gf/HEAD/img/gf.png -------------------------------------------------------------------------------- /img/gf_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greg7mdp/gf/HEAD/img/gf_01.png -------------------------------------------------------------------------------- /img/luigi_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greg7mdp/gf/HEAD/img/luigi_example.png -------------------------------------------------------------------------------- /san_ignore_list.txt: -------------------------------------------------------------------------------- 1 | fun:_XlcAddCT 2 | fun:writev 3 | fun:XOpenDisplay 4 | fun:*UIInitialise* -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Executables 2 | *.exe 3 | *.out 4 | *.app 5 | 6 | # Build directories 7 | build 8 | build_* 9 | 10 | # Misc 11 | .vagrant 12 | .cache 13 | .emacs.desktop* 14 | .gdb_history 15 | compile_commands.json 16 | .aider* 17 | .env 18 | .gdbf 19 | -------------------------------------------------------------------------------- /doc/release.md: -------------------------------------------------------------------------------- 1 | ### Release process 2 | 3 | - commit, tag (`v0.7.0` for example) & push -T 4 | - update version in `gf.hpp` -> `#define GDBF_VERSION_MINOR 8` 5 | - create the new release on github using tag created above. 6 | - download the tar.gz from github, and use `sha256sum <...tar.gz>` to get the sha256 7 | -------------------------------------------------------------------------------- /tests/reference_files/test_input.cpp: -------------------------------------------------------------------------------- 1 | // Simple test file for clangd tests 2 | // Do not modify line numbers! 3 | #include 4 | 5 | struct MyStruct { 6 | std::string name; 7 | int value; 8 | }; 9 | 10 | void target_function() { 11 | // Definition at line 9 (0-indexed) 12 | } 13 | 14 | void caller() { 15 | MyStruct obj; 16 | obj.name = "test"; 17 | target_function(); // Call at line 16 (0-indexed: 15) 18 | } 19 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/mpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_MPL_HPP_INCLUDED 2 | #define BOOST_MP11_MPL_HPP_INCLUDED 3 | 4 | // Copyright 2017, 2019 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | 14 | #endif // #ifndef BOOST_MP11_MPL_HPP_INCLUDED 15 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/version.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_VERSION_HPP_INCLUDED 2 | #define BOOST_MP11_VERSION_HPP_INCLUDED 3 | 4 | // Copyright 2019 Peter Dimov 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | // Same format as BOOST_VERSION: 12 | // major * 100000 + minor * 100 + patch 13 | 14 | #define BOOST_MP11_VERSION 108800 15 | 16 | #endif // #ifndef BOOST_MP11_VERSION_HPP_INCLUDED 17 | -------------------------------------------------------------------------------- /tests/re_gdb_tests.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | #include 3 | 4 | #include 5 | #include // include cpp file as not a library 6 | #include 7 | 8 | namespace rng = std::ranges; 9 | namespace views = rng::views; 10 | 11 | regexp::gdb_impl gdb; 12 | 13 | TEST_CASE("match_stack_or_breakpoint_output") { 14 | CHECK(gdb.matches("Num ", debug_look_for::stack_or_breakpoint_output)); 15 | CHECK(gdb.matches("#2 ", debug_look_for::stack_or_breakpoint_output)); 16 | } 17 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB cpp "*.cpp") 2 | 3 | get_filename_component(dirname ${CMAKE_CURRENT_SOURCE_DIR} NAME) 4 | string(REPLACE " " "_" dirname ${dirname}) 5 | 6 | foreach(f IN LISTS cpp) 7 | get_filename_component(target ${f} NAME_WE) 8 | add_executable("${target}" "${f}") 9 | target_include_directories(${target} PRIVATE ${CMAKE_SOURCE_DIR}/deps/include ${CMAKE_SOURCE_DIR}/src) 10 | target_link_libraries(${target} luigi) 11 | set_target_properties("${target}" PROPERTIES OUTPUT_NAME "${target}" FOLDER "${dirname}") 12 | endforeach() 13 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB cpp "*.cpp") 2 | 3 | get_filename_component(dirname ${CMAKE_CURRENT_SOURCE_DIR} NAME) 4 | string(REPLACE " " "_" dirname ${dirname}) 5 | 6 | foreach(f IN LISTS cpp) 7 | get_filename_component(target ${f} NAME_WE) 8 | add_executable("${target}" "${f}") 9 | target_include_directories(${target} PRIVATE ${CMAKE_SOURCE_DIR}/deps/include ${CMAKE_SOURCE_DIR}/src) 10 | target_link_libraries(${target} luigi) 11 | set_target_properties("${target}" PROPERTIES OUTPUT_NAME "${target}" FOLDER "${dirname}") 12 | endforeach() 13 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_list.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_LIST_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_LIST_HPP_INCLUDED 3 | 4 | // Copyright 2015, 2016 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | namespace boost 12 | { 13 | namespace mp11 14 | { 15 | 16 | // mp_list 17 | template struct mp_list 18 | { 19 | }; 20 | 21 | } // namespace mp11 22 | } // namespace boost 23 | 24 | #endif // #ifndef BOOST_MP11_DETAIL_MP_LIST_HPP_INCLUDED 25 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_list_v.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_LIST_V_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_LIST_V_HPP_INCLUDED 3 | 4 | // Copyright 2023 Peter Dimov 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // http://www.boost.org/LICENSE_1_0.txt 7 | 8 | #include 9 | 10 | namespace boost 11 | { 12 | namespace mp11 13 | { 14 | 15 | #if defined(BOOST_MP11_HAS_TEMPLATE_AUTO) 16 | 17 | // mp_list_v 18 | template struct mp_list_v 19 | { 20 | }; 21 | 22 | #endif 23 | 24 | } // namespace mp11 25 | } // namespace boost 26 | 27 | #endif // #ifndef BOOST_MP11_DETAIL_MP_LIST_V_HPP_INCLUDED 28 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # Build directories 2 | build/ 3 | build_*/ 4 | build-reproducible/ 5 | .cache/ 6 | 7 | # IDE and editor files 8 | .vscode/ 9 | .idea/ 10 | *.swp 11 | *.swo 12 | *~ 13 | .DS_Store 14 | 15 | # Git 16 | .git/ 17 | .gitignore 18 | .gitattributes 19 | 20 | # Documentation (not needed for builds) 21 | doc/ 22 | *.md 23 | !.github/tools/README.md 24 | 25 | # CI/CD (but keep tools for Dockerfile) 26 | .github/workflows/ 27 | .github/actions/ 28 | 29 | # Examples (not needed for main binary) 30 | examples/ 31 | 32 | # Test binaries and outputs 33 | tests/ 34 | *.log 35 | 36 | # Package files 37 | *.deb 38 | *.tar.gz 39 | *.tar.zst 40 | 41 | # Temporary files 42 | *.tmp 43 | output/ 44 | -------------------------------------------------------------------------------- /src/re/misc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | using namespace ctre::literals; 10 | 11 | template 12 | auto replace(std::string_view subject, std::string_view replacement) -> std::string { 13 | std::ostringstream os; 14 | 15 | auto rng = ctre::split(subject); 16 | 17 | auto it = rng.begin(); 18 | const auto end = rng.end(); 19 | 20 | assert(it != end); 21 | os << *it++; 22 | 23 | while (it != end) { 24 | os << replacement; 25 | os << *it++; 26 | } 27 | 28 | return std::move(os).str(); 29 | } 30 | 31 | 32 | } -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_value.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_VALUE_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_VALUE_HPP_INCLUDED 3 | 4 | // Copyright 2023 Peter Dimov 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // https://www.boost.org/LICENSE_1_0.txt 7 | 8 | #include 9 | #include 10 | 11 | #if defined(BOOST_MP11_HAS_TEMPLATE_AUTO) 12 | 13 | namespace boost 14 | { 15 | namespace mp11 16 | { 17 | 18 | template using mp_value = std::integral_constant; 19 | 20 | } // namespace mp11 21 | } // namespace boost 22 | 23 | #endif // #if defined(BOOST_MP11_HAS_TEMPLATE_AUTO) 24 | 25 | #endif // #ifndef BOOST_MP11_DETAIL_MP_VALUE_HPP_INCLUDED 26 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/mpl_list.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_MPL_LIST_HPP_INCLUDED 2 | #define BOOST_MP11_MPL_LIST_HPP_INCLUDED 3 | 4 | // Copyright 2017, 2019 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | 13 | namespace boost 14 | { 15 | namespace mpl 16 | { 17 | 18 | template< typename Sequence > struct sequence_tag; 19 | 20 | template struct sequence_tag> 21 | { 22 | using type = aux::mp11_tag; 23 | }; 24 | 25 | } // namespace mpl 26 | } // namespace boost 27 | 28 | #endif // #ifndef BOOST_MP11_MPL_LIST_HPP_INCLUDED 29 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "gf.hpp" 2 | 3 | // -------------------------------------------------------------------------------- 4 | // define global variables here so gf.cpp can be dynamically reloaded with jet-live 5 | // -- all are singletons -- 6 | // -------------------------------------------------------------------------------- 7 | GDBF_Config gdbfc; 8 | Context ctx; 9 | BreakpointMgr s_breakpoint_mgr; 10 | 11 | // -------------------------------------------------------------------------------- 12 | int main(int argc, char** argv) { 13 | auto ui_ptr = ctx.gdbf_main(argc, argv); 14 | if (!ui_ptr) 15 | return 1; 16 | 17 | ui_ptr->message_loop(); 18 | 19 | ctx.kill_gdb(); 20 | ctx.save_user_info(); 21 | 22 | return 0; 23 | } -------------------------------------------------------------------------------- /deps/include/boost/mp11/mpl_tuple.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_MPL_TUPLE_HPP_INCLUDED 2 | #define BOOST_MP11_MPL_TUPLE_HPP_INCLUDED 3 | 4 | // Copyright 2017, 2019 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | 14 | namespace boost 15 | { 16 | namespace mpl 17 | { 18 | 19 | template< typename Sequence > struct sequence_tag; 20 | 21 | template struct sequence_tag> 22 | { 23 | using type = aux::mp11_tag; 24 | }; 25 | 26 | } // namespace mpl 27 | } // namespace boost 28 | 29 | #endif // #ifndef BOOST_MP11_MPL_TUPLE_HPP_INCLUDED 30 | -------------------------------------------------------------------------------- /deps/include/boost/mp11.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_HPP_INCLUDED 2 | #define BOOST_MP11_HPP_INCLUDED 3 | 4 | // Copyright 2015-2024 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #endif // #ifndef BOOST_MP11_HPP_INCLUDED 24 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | BraceWrapping: 3 | SplitEmptyFunction: false 4 | SplitEmptyRecord: false 5 | IndentWidth: 3 6 | ColumnLimit: 120 7 | PointerAlignment: Left 8 | AccessModifierOffset: -3 9 | AlwaysBreakTemplateDeclarations: Yes 10 | AlignArrayOfStructures: Left 11 | AlignConsecutiveAssignments: Consecutive 12 | AlignConsecutiveDeclarations: Consecutive 13 | AlignEscapedNewlines: Left 14 | AllowAllParametersOfDeclarationOnNextLine: false 15 | AllowShortBlocksOnASingleLine: Empty 16 | AllowShortFunctionsOnASingleLine: All 17 | BreakBeforeBraces: Custom 18 | BreakConstructorInitializers: BeforeComma 19 | BreakInheritanceList: BeforeComma 20 | ConstructorInitializerIndentWidth: 3 21 | ContinuationIndentWidth: 3 22 | MaxEmptyLinesToKeep: 3 23 | SortIncludes: Never 24 | IndentPPDirectives: BeforeHash -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_void.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_VOID_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_VOID_HPP_INCLUDED 3 | 4 | // Copyright 2015-2017 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | namespace boost 12 | { 13 | namespace mp11 14 | { 15 | 16 | // mp_void 17 | namespace detail 18 | { 19 | 20 | template struct mp_void_impl 21 | { 22 | using type = void; 23 | }; 24 | 25 | } // namespace detail 26 | 27 | template using mp_void = typename detail::mp_void_impl::type; 28 | 29 | } // namespace mp11 30 | } // namespace boost 31 | 32 | #endif // #ifndef BOOST_MP11_DETAIL_MP_VOID_HPP_INCLUDED 33 | -------------------------------------------------------------------------------- /tests/re_cpp_tests.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace rng = std::ranges; 9 | namespace views = rng::views; 10 | 11 | regexp::cpp_impl cpp; 12 | 13 | TEST_CASE("extract_debuggable_expressions") { 14 | 15 | std::string code = "aa::bb::result = aa::foo::bar(x + y) + a::b::c->x + arr[idx]->member.value * 2;"; 16 | auto e = cpp.debuggable_expressions(code); 17 | 18 | for (auto expected : { "x", "y", "arr", "arr[idx]", "idx", "a::b::c->x", "aa::bb::result" }) { 19 | CHECK(std::ranges::any_of(e, [&](auto sv){ return sv == expected; })); 20 | }; 21 | 22 | for (const auto& expr : e) { 23 | std::cout << "Debuggable expression: " << expr << '\n'; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_is_list.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_IS_LIST_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_IS_LIST_HPP_INCLUDED 3 | 4 | // Copyright 2015-2019 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | 13 | namespace boost 14 | { 15 | namespace mp11 16 | { 17 | 18 | // mp_is_list 19 | namespace detail 20 | { 21 | 22 | template struct mp_is_list_impl 23 | { 24 | using type = mp_false; 25 | }; 26 | 27 | template class L, class... T> struct mp_is_list_impl> 28 | { 29 | using type = mp_true; 30 | }; 31 | 32 | } // namespace detail 33 | 34 | template using mp_is_list = typename detail::mp_is_list_impl::type; 35 | 36 | } // namespace mp11 37 | } // namespace boost 38 | 39 | #endif // #ifndef BOOST_MP11_DETAIL_MP_IS_LIST_HPP_INCLUDED 40 | -------------------------------------------------------------------------------- /.github/tools/build-reproducible.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # Build reproducible gdbf binary using Docker 5 | # Usage: ./.github/tools/build-reproducible.sh [output-dir] 6 | 7 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 8 | REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" 9 | OUTPUT_DIR="${1:-$REPO_ROOT/build-reproducible}" 10 | 11 | echo "Building reproducible gdbf binary..." 12 | echo "Repository root: $REPO_ROOT" 13 | echo "Output directory: $OUTPUT_DIR" 14 | 15 | mkdir -p "$OUTPUT_DIR" 16 | 17 | # Build using Docker 18 | docker buildx build \ 19 | --file "$REPO_ROOT/.github/tools/reproducible.Dockerfile" \ 20 | --target exporter \ 21 | --output "type=local,dest=$OUTPUT_DIR" \ 22 | --build-arg "GDBF_BUILD_JOBS=$(nproc)" \ 23 | "$REPO_ROOT" 24 | 25 | echo "" 26 | echo "Build complete!" 27 | echo "Binary location: $OUTPUT_DIR/gdbf" 28 | echo "" 29 | echo "Binary info:" 30 | file "$OUTPUT_DIR/gdbf" 31 | echo "" 32 | echo "Size: $(du -h "$OUTPUT_DIR/gdbf" | cut -f1)" 33 | echo "" 34 | echo "Linked libraries:" 35 | ldd "$OUTPUT_DIR/gdbf" || true 36 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_is_value_list.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_IS_VALUE_LIST_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_IS_VALUE_LIST_HPP_INCLUDED 3 | 4 | // Copyright 2023 Peter Dimov 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // https://www.boost.org/LICENSE_1_0.txt 7 | 8 | #include 9 | #include 10 | 11 | namespace boost 12 | { 13 | namespace mp11 14 | { 15 | 16 | // mp_is_value_list 17 | namespace detail 18 | { 19 | 20 | template struct mp_is_value_list_impl 21 | { 22 | using type = mp_false; 23 | }; 24 | 25 | #if defined(BOOST_MP11_HAS_TEMPLATE_AUTO) 26 | 27 | template class L, auto... A> struct mp_is_value_list_impl> 28 | { 29 | using type = mp_true; 30 | }; 31 | 32 | #endif 33 | 34 | } // namespace detail 35 | 36 | template using mp_is_value_list = typename detail::mp_is_value_list_impl::type; 37 | 38 | } // namespace mp11 39 | } // namespace boost 40 | 41 | #endif // #ifndef BOOST_MP11_DETAIL_MP_IS_VALUE_LIST_HPP_INCLUDED 42 | -------------------------------------------------------------------------------- /deps/include/nlohmann/LICENSE.MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-2025 Niels Lohmann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-2025 Gregory Popovitch 4 | Copyright (c) 2019-2023 Nakst and other contributors (see README.md) 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 | -------------------------------------------------------------------------------- /.github/workflows/claude.yml: -------------------------------------------------------------------------------- 1 | name: Claude Code 2 | 3 | on: 4 | issue_comment: 5 | types: [created] 6 | pull_request_review_comment: 7 | types: [created] 8 | issues: 9 | types: [opened, assigned] 10 | pull_request_review: 11 | types: [submitted] 12 | 13 | jobs: 14 | claude: 15 | if: | 16 | (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || 17 | (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || 18 | (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || 19 | (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) 20 | runs-on: ubuntu-latest 21 | permissions: 22 | contents: read 23 | pull-requests: read 24 | issues: read 25 | id-token: write 26 | steps: 27 | - name: Checkout repository 28 | uses: actions/checkout@v4 29 | with: 30 | fetch-depth: 1 31 | 32 | - name: Run Claude Code 33 | id: claude 34 | uses: anthropics/claude-code-action@beta 35 | with: 36 | anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} 37 | 38 | -------------------------------------------------------------------------------- /examples/gdbf_testprog.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | int fib(int n) { 11 | if (n <= 1) 12 | return n; 13 | return fib(n - 1) + fib(n - 2); 14 | } 15 | 16 | struct A { 17 | int i = 1; 18 | string s = "one"; 19 | std::vector v = {1, 2, 3}; 20 | }; 21 | 22 | struct C { 23 | int i = 0; 24 | std::vector as = {{1, "one"}, {2, "two"}, {3, "three"}}; 25 | }; 26 | 27 | void check_variants() { 28 | std::variant v, w; 29 | v = 42; // v contains int 30 | [[maybe_unused]] int i = std::get(v); 31 | w = std::get(v); 32 | 33 | std::variant x("abc"); 34 | x = "def"; 35 | } 36 | 37 | int main(int argc, char** argv) { 38 | if (argc > 1) 39 | printf("%s\n", argv[1]); 40 | C c; 41 | check_variants(); 42 | std::vector v { 2, 3, 4 }; 43 | std::vector v2 { {2, "two", {}}, {3, "three", {}} }; 44 | int i = 1; 45 | A a; 46 | float f[] {3.14159f, 4.0f, 5.5f }; 47 | const char* s = "hello"; 48 | printf("%s fib(3)=%d\n", s, fib(3)); 49 | if (i < 3) 50 | i = (i + 1); 51 | 52 | int res = a.i + i + c.as[1].i - fib(1); 53 | 54 | return std::clamp(res, 0, 0); 55 | } 56 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_front.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_FRONT_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_FRONT_HPP_INCLUDED 3 | 4 | // Copyright 2015-2023 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | 14 | namespace boost 15 | { 16 | namespace mp11 17 | { 18 | 19 | // mp_front 20 | namespace detail 21 | { 22 | 23 | template struct mp_front_impl 24 | { 25 | // An error "no type named 'type'" here means that the argument to mp_front 26 | // is either not a list, or is an empty list 27 | }; 28 | 29 | template class L, class T1, class... T> struct mp_front_impl> 30 | { 31 | using type = T1; 32 | }; 33 | 34 | #if defined(BOOST_MP11_HAS_TEMPLATE_AUTO) 35 | 36 | template class L, auto A1, auto... A> struct mp_front_impl> 37 | { 38 | using type = mp_value; 39 | }; 40 | 41 | #endif 42 | 43 | } // namespace detail 44 | 45 | template using mp_front = typename detail::mp_front_impl::type; 46 | 47 | } // namespace mp11 48 | } // namespace boost 49 | 50 | #endif // #ifndef BOOST_MP11_DETAIL_MP_FRONT_HPP_INCLUDED 51 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/integral.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_INTEGRAL_HPP_INCLUDED 2 | #define BOOST_MP11_INTEGRAL_HPP_INCLUDED 3 | 4 | // Copyright 2015 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #if defined(_MSC_VER) || defined(__GNUC__) 17 | # pragma push_macro( "I" ) 18 | # undef I 19 | #endif 20 | 21 | namespace boost 22 | { 23 | namespace mp11 24 | { 25 | 26 | // mp_bool 27 | template using mp_bool = std::integral_constant; 28 | 29 | using mp_true = mp_bool; 30 | using mp_false = mp_bool; 31 | 32 | // mp_to_bool 33 | template using mp_to_bool = mp_bool( T::value )>; 34 | 35 | // mp_not 36 | template using mp_not = mp_bool< !T::value >; 37 | 38 | // mp_int 39 | template using mp_int = std::integral_constant; 40 | 41 | // mp_size_t 42 | template using mp_size_t = std::integral_constant; 43 | 44 | } // namespace mp11 45 | } // namespace boost 46 | 47 | #if defined(_MSC_VER) || defined(__GNUC__) 48 | # pragma pop_macro( "I" ) 49 | #endif 50 | 51 | #endif // #ifndef BOOST_MP11_INTEGRAL_HPP_INCLUDED 52 | -------------------------------------------------------------------------------- /.github/workflows/linux.yml: -------------------------------------------------------------------------------- 1 | name: Linux 2 | 3 | on: 4 | push: 5 | pull_request: 6 | branches: [ main ] 7 | 8 | jobs: 9 | build: 10 | runs-on: ${{ matrix.os }} 11 | strategy: 12 | matrix: 13 | os: [ubuntu-24.04] 14 | compiler: [g++-13] 15 | build_type: [Release] 16 | ## compiler: [g++, clang++-18] 17 | ## build_type: [Debug, Release] 18 | standard: [23] 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v4 22 | 23 | - name: Create Environment 24 | run: | 25 | sudo apt update 26 | sudo apt install -y libfreetype-dev libx11-dev x11-common gcc-13 27 | ## wget https://apt.llvm.org/llvm.sh; chmod u+x llvm.sh; sudo ./llvm.sh 18 28 | cmake -E make_directory ${{runner.workspace}}/build 29 | 30 | - name: Configure 31 | working-directory: ${{runner.workspace}}/build 32 | env: 33 | CXX: ${{ matrix.compiler }} 34 | run: | 35 | cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_CXX_STANDARD=${{matrix.standard}} -DCMAKE_BUILD_TYPE=${{matrix.build_type}} $GITHUB_WORKSPACE 36 | 37 | - name: Build 38 | working-directory: ${{runner.workspace}}/build 39 | run: | 40 | cpus=`nproc` 41 | cmake --build . --config ${{matrix.build_type}} --parallel $cpus 42 | 43 | - name: Test 44 | working-directory: ${{runner.workspace}}/build 45 | env: 46 | CTEST_OUTPUT_ON_FAILURE: True 47 | run: | 48 | ctest -C ${{matrix.build_type}} 49 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_copy_if.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_COPY_IF_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_COPY_IF_HPP_INCLUDED 3 | 4 | // Copyright 2015-2019 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace boost 17 | { 18 | namespace mp11 19 | { 20 | 21 | // mp_copy_if 22 | namespace detail 23 | { 24 | 25 | template class P> struct mp_copy_if_impl 26 | { 27 | }; 28 | 29 | template class L, class... T, template class P> struct mp_copy_if_impl, P> 30 | { 31 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) 32 | template struct _f { using type = mp_if, mp_list, mp_list<>>; }; 33 | using type = mp_append, typename _f::type...>; 34 | #else 35 | template using _f = mp_if, mp_list, mp_list<>>; 36 | using type = mp_append, _f...>; 37 | #endif 38 | }; 39 | 40 | } // namespace detail 41 | 42 | template class P> using mp_copy_if = typename detail::mp_copy_if_impl::type; 43 | template using mp_copy_if_q = mp_copy_if; 44 | 45 | } // namespace mp11 46 | } // namespace boost 47 | 48 | #endif // #ifndef BOOST_MP11_DETAIL_MP_COPY_IF_HPP_INCLUDED 49 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_remove_if.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_REMOVE_IF_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_REMOVE_IF_HPP_INCLUDED 3 | 4 | // Copyright 2015-2019 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace boost 17 | { 18 | namespace mp11 19 | { 20 | 21 | // mp_remove_if 22 | namespace detail 23 | { 24 | 25 | template class P> struct mp_remove_if_impl 26 | { 27 | }; 28 | 29 | template class L, class... T, template class P> struct mp_remove_if_impl, P> 30 | { 31 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) 32 | template struct _f { using type = mp_if, mp_list<>, mp_list>; }; 33 | using type = mp_append, typename _f::type...>; 34 | #else 35 | template using _f = mp_if, mp_list<>, mp_list>; 36 | using type = mp_append, _f...>; 37 | #endif 38 | }; 39 | 40 | } // namespace detail 41 | 42 | template class P> using mp_remove_if = typename detail::mp_remove_if_impl::type; 43 | template using mp_remove_if_q = mp_remove_if; 44 | 45 | } // namespace mp11 46 | } // namespace boost 47 | 48 | #endif // #ifndef BOOST_MP11_DETAIL_MP_REMOVE_IF_HPP_INCLUDED 49 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_min_element.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_MIN_ELEMENT_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_MIN_ELEMENT_HPP_INCLUDED 3 | 4 | // Copyright 2015-2017 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace boost 16 | { 17 | namespace mp11 18 | { 19 | 20 | // mp_min_element 21 | namespace detail 22 | { 23 | 24 | template class P> struct select_min 25 | { 26 | template using fn = mp_if, T1, T2>; 27 | }; 28 | 29 | } // namespace detail 30 | 31 | template class P> using mp_min_element = mp_fold_q, mp_first, detail::select_min

>; 32 | template using mp_min_element_q = mp_min_element; 33 | 34 | // mp_max_element 35 | namespace detail 36 | { 37 | 38 | template class P> struct select_max 39 | { 40 | template using fn = mp_if, T1, T2>; 41 | }; 42 | 43 | } // namespace detail 44 | 45 | template class P> using mp_max_element = mp_fold_q, mp_first, detail::select_max

>; 46 | template using mp_max_element_q = mp_max_element; 47 | 48 | } // namespace mp11 49 | } // namespace boost 50 | 51 | #endif // #ifndef BOOST_MP11_DETAIL_MP_MIN_ELEMENT_HPP_INCLUDED 52 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_rename.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_RENAME_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_RENAME_HPP_INCLUDED 3 | 4 | // Copyright 2015-2023 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace boost 16 | { 17 | namespace mp11 18 | { 19 | 20 | // mp_rename 21 | namespace detail 22 | { 23 | 24 | template class B> struct mp_rename_impl 25 | { 26 | // An error "no type named 'type'" here means that the first argument to mp_rename is not a list 27 | }; 28 | 29 | template class L, class... T, template class B> struct mp_rename_impl, B>: mp_defer 30 | { 31 | }; 32 | 33 | #if defined(BOOST_MP11_HAS_TEMPLATE_AUTO) 34 | 35 | template class L, auto... A, template class B> struct mp_rename_impl, B>: mp_defer...> 36 | { 37 | }; 38 | 39 | #endif 40 | 41 | } // namespace detail 42 | 43 | template class B> using mp_rename = typename detail::mp_rename_impl::type; 44 | 45 | // mp_apply 46 | template class F, class L> using mp_apply = typename detail::mp_rename_impl::type; 47 | 48 | // mp_apply_q 49 | template using mp_apply_q = typename detail::mp_rename_impl::type; 50 | 51 | } // namespace mp11 52 | } // namespace boost 53 | 54 | #endif // #ifndef BOOST_MP11_DETAIL_MP_RENAME_HPP_INCLUDED 55 | -------------------------------------------------------------------------------- /doc/profiler_instructions.txt: -------------------------------------------------------------------------------- 1 | Setup: 2 | Step 1: 3 | Copy `gdbf_profiling.c` into your project. 4 | Either `#include` it like a single-header library, or add it a separate translation unit. 5 | This file is available under a permissive license, so don't worry if it ends up in version control. 6 | Step 2: 7 | If needed, change the settings at the top of `gdbf_profiling.c`. 8 | You can change the size of the buffer to use, and the type of time measurements to take. 9 | If you are not linking against the C standard library, you will also need to replace the 10 | calls to assert/malloc/clock_gettime. 11 | Step 3: 12 | Add `-finstrument-functions` to your compiler command line arguments. 13 | This works with Clang and GCC/G++. 14 | It does not need to be passed to the linker. 15 | Step 4: 16 | Add the `Prof` window to the interface layout in your gdbf configuration file. 17 | See gdbf's README.md for detailed instructions -- see the "User Interface" section. 18 | Step 5: 19 | Run your executable in gdbf as usual. 20 | To capture a profile, select the `Prof` tab, and click the "Step over profiled". 21 | This will run the typical step over debug command, and then create a report window in the data tab. 22 | 23 | Let me know if you have issues getting this to work. 24 | 25 | Usage: 26 | Left click and drag to pan horizontally. 27 | Middle click and drag to zoom in and out and move sideways. 28 | Right click and drag to zoom into a selection. 29 | Middle click an entry to fill the screen with it horizontally. 30 | Right click an entry to view more options. 31 | Click "Table view" to switch to a table report. 32 | In the table report, click a column header to sort by it. 33 | Click the close button in the top-right when you are done with the report. 34 | 35 | -------------------------------------------------------------------------------- /.github/workflows/macos.yml: -------------------------------------------------------------------------------- 1 | name: macOS 2 | 3 | on: 4 | push: 5 | pull_request: 6 | branches: [ main ] 7 | 8 | jobs: 9 | build: 10 | runs-on: ${{ matrix.os }} 11 | strategy: 12 | matrix: 13 | os: [macos-14, macos-15] # macos-14 = M1, macos-15 = M2/M3 14 | compiler: [clang++] 15 | build_type: [Release] 16 | standard: [23] 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | 21 | - name: Install Dependencies 22 | run: | 23 | # XQuartz provides X11 on macOS 24 | brew install xquartz 25 | # Note: XQuartz needs to be started, but headless build should work 26 | cmake -E make_directory ${{runner.workspace}}/build 27 | 28 | - name: Configure 29 | working-directory: ${{runner.workspace}}/build 30 | env: 31 | CXX: ${{ matrix.compiler }} 32 | run: | 33 | # Set X11 paths for macOS 34 | export PKG_CONFIG_PATH="/opt/X11/lib/pkgconfig:$PKG_CONFIG_PATH" 35 | cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ 36 | -DCMAKE_CXX_STANDARD=${{matrix.standard}} \ 37 | -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \ 38 | -DCMAKE_CXX_FLAGS="-I/opt/X11/include" \ 39 | -DCMAKE_EXE_LINKER_FLAGS="-L/opt/X11/lib" \ 40 | $GITHUB_WORKSPACE 41 | 42 | - name: Build 43 | working-directory: ${{runner.workspace}}/build 44 | run: | 45 | cpus=`sysctl -n hw.ncpu` 46 | cmake --build . --config ${{matrix.build_type}} --parallel $cpus 47 | 48 | - name: Test 49 | working-directory: ${{runner.workspace}}/build 50 | env: 51 | CTEST_OUTPUT_ON_FAILURE: True 52 | run: | 53 | # Tests that don't require GUI should work 54 | ctest -C ${{matrix.build_type}} || true 55 | echo "Note: Some tests may fail without X11 display" 56 | -------------------------------------------------------------------------------- /src/utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "luigi.hpp" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // --------------------------------------------------------------------------- 12 | static inline bool is_executable_in_path(const std::string& path) { 13 | if (path.find('/') != std::string::npos) { 14 | // It's a path, check directly 15 | return access(path.c_str(), X_OK) == 0; 16 | } 17 | 18 | // It's a command name, search PATH 19 | const char* path_env = getenv("PATH"); 20 | if (!path_env) 21 | return false; 22 | 23 | char buffer[PATH_MAX]; 24 | const char* start = path_env; 25 | const char* end; 26 | 27 | while ((end = strchr(start, ':')) != nullptr) { 28 | size_t dir_len = end - start; 29 | if (dir_len == 0) { 30 | start = end + 1; 31 | continue; 32 | } 33 | 34 | auto result = std::format_to_n(buffer, PATH_MAX - 1, "{}/{}", std::string_view(start, dir_len), path); 35 | buffer[result.size] = '\0'; 36 | 37 | if (access(buffer, X_OK) == 0) 38 | return true; 39 | 40 | start = end + 1; 41 | } 42 | 43 | // Check last directory 44 | if (*start != '\0') { 45 | auto result = std::format_to_n(buffer, PATH_MAX - 1, "{}/{}", start, path); 46 | *result.out = '\0'; 47 | return access(buffer, X_OK) == 0; 48 | } 49 | 50 | return false; 51 | } 52 | 53 | // --------------------------------------------------------------------------- 54 | static inline std::string my_getcwd() { 55 | char buff[PATH_MAX] = ""; 56 | return std::string{getcwd(buff, sizeof(buff))}; 57 | } 58 | 59 | // --------------------------------------------------------------------------- 60 | static inline std::string get_realpath(std::string_view sv_path) { 61 | ensure_null_terminated path(sv_path); 62 | 63 | char buff[PATH_MAX] = ""; 64 | (void)!realpath(path.data(), buff); // realpath can return 0 if path doesn'tr exist (ENOENT) 65 | return *buff ? std::string{buff} : std::string{sv_path}; 66 | } 67 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Build 2 | 3 | on: 4 | release: 5 | types: [published] 6 | workflow_dispatch: 7 | inputs: 8 | upload-to-release: 9 | description: 'Upload binary to latest release' 10 | type: boolean 11 | default: false 12 | 13 | permissions: 14 | contents: write 15 | 16 | jobs: 17 | build-reproducible: 18 | name: Build Reproducible gdbf Binary 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v4 23 | 24 | - name: Set up Docker Buildx 25 | uses: docker/setup-buildx-action@v3 26 | 27 | - name: Build reproducible gdbf binary 28 | uses: docker/build-push-action@v5 29 | with: 30 | context: . 31 | file: .github/tools/reproducible.Dockerfile 32 | target: exporter 33 | outputs: type=local,dest=./output 34 | build-args: | 35 | GDBF_BUILD_JOBS=${{ runner.hw.cpu-count }} 36 | 37 | - name: Verify binary 38 | run: | 39 | ls -lh output/ 40 | file output/gdbf 41 | ldd output/gdbf || true 42 | 43 | - name: Create tarball 44 | run: | 45 | cd output 46 | tar -czf gdbf-${{ github.ref_name }}-linux-x86_64.tar.gz gdbf 47 | sha256sum gdbf-${{ github.ref_name }}-linux-x86_64.tar.gz > gdbf-${{ github.ref_name }}-linux-x86_64.tar.gz.sha256 48 | 49 | - name: Upload artifact 50 | uses: actions/upload-artifact@v4 51 | with: 52 | name: gdbf-linux-x86_64 53 | path: | 54 | output/gdbf-${{ github.ref_name }}-linux-x86_64.tar.gz 55 | output/gdbf-${{ github.ref_name }}-linux-x86_64.tar.gz.sha256 56 | compression-level: 0 57 | 58 | - name: Upload to Release 59 | if: github.event_name == 'release' || inputs.upload-to-release 60 | uses: softprops/action-gh-release@v1 61 | with: 62 | files: | 63 | output/gdbf-${{ github.ref_name }}-linux-x86_64.tar.gz 64 | output/gdbf-${{ github.ref_name }}-linux-x86_64.tar.gz.sha256 65 | tag_name: ${{ github.ref_name }} 66 | env: 67 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 68 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_map_find.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_MAP_FIND_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_MAP_FIND_HPP_INCLUDED 3 | 4 | // Copyright 2015 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | 14 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1930 ) 15 | 16 | // not exactly good practice, but... 17 | namespace std 18 | { 19 | template class tuple; 20 | } 21 | 22 | #endif 23 | 24 | namespace boost 25 | { 26 | namespace mp11 27 | { 28 | 29 | // mp_map_find 30 | namespace detail 31 | { 32 | 33 | #if !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1930 ) 34 | 35 | template using mpmf_wrap = mp_identity; 36 | template using mpmf_unwrap = typename T::type; 37 | 38 | #else 39 | 40 | template struct mpmf_tuple {}; 41 | 42 | template struct mpmf_wrap_impl 43 | { 44 | using type = mp_identity; 45 | }; 46 | 47 | template struct mpmf_wrap_impl< std::tuple > 48 | { 49 | using type = mp_identity< mpmf_tuple >; 50 | }; 51 | 52 | template using mpmf_wrap = typename mpmf_wrap_impl::type; 53 | 54 | template struct mpmf_unwrap_impl 55 | { 56 | using type = typename T::type; 57 | }; 58 | 59 | template struct mpmf_unwrap_impl< mp_identity< mpmf_tuple > > 60 | { 61 | using type = std::tuple; 62 | }; 63 | 64 | template using mpmf_unwrap = typename mpmf_unwrap_impl::type; 65 | 66 | #endif // #if !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1930 ) 67 | 68 | template struct mp_map_find_impl; 69 | 70 | template class M, class... T, class K> struct mp_map_find_impl, K> 71 | { 72 | using U = mp_inherit...>; 73 | 74 | template class L, class... U> static mp_identity> f( mp_identity>* ); 75 | static mp_identity f( ... ); 76 | 77 | using type = mpmf_unwrap< decltype( f( static_cast(0) ) ) >; 78 | }; 79 | 80 | } // namespace detail 81 | 82 | template using mp_map_find = typename detail::mp_map_find_impl::type; 83 | 84 | } // namespace mp11 85 | } // namespace boost 86 | 87 | #endif // #ifndef BOOST_MP11_DETAIL_MP_MAP_FIND_HPP_INCLUDED 88 | -------------------------------------------------------------------------------- /examples/gf2_config.ini: -------------------------------------------------------------------------------- 1 | [executable] 2 | #path=./examples/luigi_example 3 | #arguments="--run_test=api_part2_tests" 4 | 5 | path=/home/greg/github/enf/spring/build_clang18_debug/bin/nodeos 6 | #arguments="--run_test=producer_schedule_tests" "--report_level=detailed" "--color_output" "--" "--eos-vm-jit" 7 | #arguments=--data-dir /media/greg/Samsung_T5/eos/cfg0/main --config-dir /home/greg/eos/cfg0 --plugin eosio::chain_api_plugin --snapshot /home/greg/eos/snapshots/snapshot-2024-08-11-16-eos-v8-0388338616.bin 8 | 9 | #path=/home/greg/github/greg/parallel-hashmap/build_gcc13_debug/ex_dump_load 10 | 11 | #path=./test/chainbase_test 12 | #arguments="--run_test=locality" 13 | #arguments="--run_test=open_and_create" 14 | 15 | #path=../build/OpenGL/OpenGL 16 | #path=./unittests/unit_test 17 | #arguments="--run_test=api_part2_tests" "--report_level=detailed" "--color_output" "--" "--eos-vm" --verbose 18 | #arguments="--run_test=snapshot_tests/test_compatible_versions" "-- --save-snapshot" 19 | #path=./libraries/libfc/test/test_fc 20 | #arguments=--run_test=raw_test_suite/struct_serialization 21 | 22 | ask_directory=0 23 | 24 | [commands] 25 | Set breakpoint=b mem_visualizer.cpp:118 26 | break in rbtree_best_fit=b rbtree_best_fit.hpp:1245 27 | 28 | [shortcuts] 29 | Ctrl+I=print i 30 | Ctrl+Shift+F10=reverse-next 31 | Ctrl+Shift+F11=reverse-step 32 | 33 | [gdb] 34 | log_all_output=1 35 | confirm_command_kill=0 36 | confirm_command_connect=0 37 | backtrace_count_limit=100 38 | 39 | [ui] 40 | scale=1 41 | font_path=/home/greg/fonts/FiraCode-Regular.ttf 42 | font_size=12 43 | window_width=3000 44 | window_height=1700 45 | selectable_source=1 46 | grab_focus_on_breakpoint=1 47 | layout=v(75,h(50,Source,v(50,t(Exe,Breakpoints,Commands,Struct),t(Stack,Files,Thread,CmdSearch))),h(40,Console,t(Watch,Locals,Registers,Data,Log))) 48 | 49 | [theme] 50 | # predefined themes are "classic", "dark", "ice", "lotus" and "hero" 51 | predefined=ice 52 | 53 | # any theme value can be overridden as follows: 54 | # panel1=F1F4FF 55 | # panel2=FFFFFF 56 | # text=000000 57 | # textDisabled=787D81 58 | # border=000000 59 | # buttonNormal=EAEDFF 60 | # buttonHovered=F0F8FF 61 | # buttonPressed=B6C5FB 62 | # buttonDisabled=1B1F23 63 | # textboxNormal=FFFFFF 64 | # textboxFocused=FFFFFF 65 | # codeFocused=9CD6FF 66 | # codeBackground=E8F2FF 67 | # codeDefault=000000 68 | # codeComment=7B6F81 69 | # codeString=0F7D32 70 | # codeNumber=0058F5 71 | # codeOperator=720EE7 72 | # codePreprocessor=900092 73 | # selected=B5D0FE 74 | # textSelected=000000 75 | # accent1=FF0000 76 | # accent2=00FF00 77 | 78 | [trusted_folders] 79 | /home/greg/github/enf/eos-system-contracts/build_clang18_debug 80 | /home/greg/github/enf/spring/build_clang18_debug 81 | /home/greg/github/enf/xyz-system-contract/build_clang18_debug 82 | /home/greg/github/greg/gf/build_clang18_debug 83 | -------------------------------------------------------------------------------- /doc/plugins.md: -------------------------------------------------------------------------------- 1 | ## Plugins 2 | 3 | There is a simple plugin system. Make a file called `plugins.cpp` in the source code folder. 4 | It will be found automatically, and #included in the compilation of the main translation unit. 5 | 6 | gdbf uses the [Luigi](https://github.com/greg7mdp/gdbf/blob/main/doc/luigi.md) UI library. 7 | 8 | You can register new windows, command and data viewers in a constructor function. For example, 9 | 10 | ```cpp 11 | __attribute__((constructor)) 12 | void MyPluginRegister() { 13 | _interface_windows["Hello"] = {._create = MyPluginHelloWindowCreate, // should create an instance of the window. 14 | ._update = MyPluginHelloWindowUpdate // called every time the target pauses/steps 15 | }; 16 | 17 | _interface_data_viewers.push_back({"Add waveform...", // The label of the button to show in the Data tab. 18 | WaveformAddDialog}); // The callback to create the data viewer. 19 | 20 | _interface_commands.push_back({ 21 | ._label = "My command", // The label to show in the application menu. 22 | ._shortcut{.code = UI_KEYCODE_LETTER('V'), .ctrl = true, .shift = true, .invoke = []() { 23 | // do something here 24 | return true; 25 | }} 26 | }); 27 | } 28 | ``` 29 | 30 | The interface window creation callback is passed the parent UIElement and should return the UIElement it creates. 31 | 32 | ```cpp 33 | UIElement *MyPluginHelloWindowCreate(UIElement *parent) { 34 | UIPanel &panel = parent->add_panel(UIPanel::GRAY || UIPanel::EXPAND); 35 | panel.add_label(0, "Hello, world!"); 36 | return &panel; 37 | } 38 | ``` 39 | 40 | The interface window update callback is passed the output of GDB from the most recent step, 41 | and the UIElement returned by the creation callback. 42 | 43 | ```cpp 44 | void MyPluginHelloWindowUpdate(const char *gdbOutput, UIElement *element) { 45 | // TODO Update the window. 46 | } 47 | ``` 48 | 49 | The interface data viewer creation callback should create a MDI child of the data tab as follows: 50 | 51 | ```cpp 52 | void MyPluginTestViewerCreate(void *unused) { 53 | UIMDIChild &window = dataWindow->add_mdichild(UIMDIChild::CLOSE_BUTTON, ui_rect_1(0), "Title"); 54 | // TODO Configure the viewer. 55 | dataWindow->refresh(); 56 | } 57 | ``` 58 | 59 | For communicating with GDB, there are the following member functions of the `Context` class (use `ctx` object). 60 | 61 | ```cpp 62 | // Evaluate an expression. The result is overwritten between calls! 63 | std::string eval_expression(string_view expression, string_view format = {}); 64 | 65 | // Send and run a command in GDB. Set `echo` to log the command in the console window. 66 | // If `synchronous` is set the function will wait for the command to complete before it returns. 67 | std::optional send_command_to_debugger(string_view command, bool echo, bool synchronous); 68 | ``` 69 | 70 | There are many examples of how to do these things in `gf.cpp`. -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_plus.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_PLUS_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_PLUS_HPP_INCLUDED 3 | 4 | // Copyright 2015 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | 14 | namespace boost 15 | { 16 | namespace mp11 17 | { 18 | 19 | // mp_plus 20 | namespace detail 21 | { 22 | 23 | #if defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) && !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, != 0 ) && !BOOST_MP11_WORKAROUND( BOOST_MP11_CLANG, != 0 ) 24 | 25 | // msvc fails with parser stack overflow for large sizeof...(T) 26 | // clang exceeds -fbracket-depth, which defaults to 256 27 | 28 | template struct mp_plus_impl 29 | { 30 | static const auto _v = (T::value + ... + 0); 31 | using type = std::integral_constant::type, _v>; 32 | }; 33 | 34 | #else 35 | 36 | template struct mp_plus_impl; 37 | 38 | template<> struct mp_plus_impl<> 39 | { 40 | using type = std::integral_constant; 41 | }; 42 | 43 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, < 40800 ) 44 | 45 | template struct mp_plus_impl 46 | { 47 | static const decltype(T1::value + mp_plus_impl::type::value) _v = T1::value + mp_plus_impl::type::value; 48 | using type = std::integral_constant::type, _v>; 49 | }; 50 | 51 | template struct mp_plus_impl 52 | { 53 | static const 54 | decltype(T1::value + T2::value + T3::value + T4::value + T5::value + T6::value + T7::value + T8::value + T9::value + T10::value + mp_plus_impl::type::value) 55 | _v = T1::value + T2::value + T3::value + T4::value + T5::value + T6::value + T7::value + T8::value + T9::value + T10::value + mp_plus_impl::type::value; 56 | using type = std::integral_constant::type, _v>; 57 | }; 58 | 59 | #else 60 | 61 | template struct mp_plus_impl 62 | { 63 | static const auto _v = T1::value + mp_plus_impl::type::value; 64 | using type = std::integral_constant::type, _v>; 65 | }; 66 | 67 | template struct mp_plus_impl 68 | { 69 | static const auto _v = T1::value + T2::value + T3::value + T4::value + T5::value + T6::value + T7::value + T8::value + T9::value + T10::value + mp_plus_impl::type::value; 70 | using type = std::integral_constant::type, _v>; 71 | }; 72 | 73 | #endif 74 | 75 | #endif 76 | 77 | } // namespace detail 78 | 79 | template using mp_plus = typename detail::mp_plus_impl::type; 80 | 81 | } // namespace mp11 82 | } // namespace boost 83 | 84 | #endif // #ifndef BOOST_MP11_DETAIL_MP_PLUS_HPP_INCLUDED 85 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_defer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_DEFER_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_DEFER_HPP_INCLUDED 3 | 4 | // Copyright 2015-2020, 2023 Peter Dimov 5 | // Distributed under the Boost Software License, Version 1.0. 6 | // https://www.boost.org/LICENSE_1_0.txt 7 | 8 | #include 9 | #include 10 | 11 | namespace boost 12 | { 13 | namespace mp11 14 | { 15 | 16 | // mp_if, mp_if_c 17 | namespace detail 18 | { 19 | 20 | template struct mp_if_c_impl 21 | { 22 | }; 23 | 24 | template struct mp_if_c_impl 25 | { 26 | using type = T; 27 | }; 28 | 29 | template struct mp_if_c_impl 30 | { 31 | using type = E; 32 | }; 33 | 34 | } // namespace detail 35 | 36 | template using mp_if_c = typename detail::mp_if_c_impl::type; 37 | template using mp_if = typename detail::mp_if_c_impl(C::value), T, E...>::type; 38 | 39 | // mp_valid 40 | 41 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_INTEL, != 0 ) // tested at 1800 42 | 43 | // contributed by Roland Schulz in https://github.com/boostorg/mp11/issues/17 44 | 45 | namespace detail 46 | { 47 | 48 | template using void_t = void; 49 | 50 | template class F, class... T> 51 | struct mp_valid_impl: mp_false {}; 52 | 53 | template class F, class... T> 54 | struct mp_valid_impl>, F, T...>: mp_true {}; 55 | 56 | } // namespace detail 57 | 58 | template class F, class... T> using mp_valid = typename detail::mp_valid_impl; 59 | 60 | #else 61 | 62 | // implementation by Bruno Dutra (by the name is_evaluable) 63 | namespace detail 64 | { 65 | 66 | template class F, class... T> struct mp_valid_impl 67 | { 68 | template class G, class = G> static mp_true check(int); 69 | template class> static mp_false check(...); 70 | 71 | using type = decltype(check(0)); 72 | }; 73 | 74 | } // namespace detail 75 | 76 | template class F, class... T> using mp_valid = typename detail::mp_valid_impl::type; 77 | 78 | #endif 79 | 80 | template using mp_valid_q = mp_valid; 81 | 82 | // mp_defer 83 | namespace detail 84 | { 85 | 86 | template class F, class... T> struct mp_defer_impl 87 | { 88 | using type = F; 89 | }; 90 | 91 | struct mp_no_type 92 | { 93 | }; 94 | 95 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 ) 96 | 97 | template class F, class... T> struct mp_defer_cuda_workaround 98 | { 99 | using type = mp_if, detail::mp_defer_impl, detail::mp_no_type>; 100 | }; 101 | 102 | #endif 103 | 104 | } // namespace detail 105 | 106 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 ) 107 | 108 | template class F, class... T> using mp_defer = typename detail::mp_defer_cuda_workaround< F, T...>::type; 109 | 110 | #else 111 | 112 | template class F, class... T> using mp_defer = mp_if, detail::mp_defer_impl, detail::mp_no_type>; 113 | 114 | #endif 115 | 116 | } // namespace mp11 117 | } // namespace boost 118 | 119 | #endif // #ifndef BOOST_MP11_DETAIL_MP_DEFER_HPP_INCLUDED 120 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/bind.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_BIND_HPP_INCLUDED 2 | #define BOOST_MP11_BIND_HPP_INCLUDED 3 | 4 | // Copyright 2017, 2018 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #if defined(_MSC_VER) || defined(__GNUC__) 16 | # pragma push_macro( "I" ) 17 | # undef I 18 | #endif 19 | 20 | namespace boost 21 | { 22 | namespace mp11 23 | { 24 | 25 | // mp_bind_front 26 | template class F, class... T> struct mp_bind_front 27 | { 28 | // the indirection through mp_defer works around the language inability 29 | // to expand U... into a fixed parameter list of an alias template 30 | 31 | template using fn = typename mp_defer::type; 32 | }; 33 | 34 | template using mp_bind_front_q = mp_bind_front; 35 | 36 | // mp_bind_back 37 | template class F, class... T> struct mp_bind_back 38 | { 39 | template using fn = typename mp_defer::type; 40 | }; 41 | 42 | template using mp_bind_back_q = mp_bind_back; 43 | 44 | // mp_arg 45 | template struct mp_arg 46 | { 47 | template using fn = mp_at_c, I>; 48 | }; 49 | 50 | using _1 = mp_arg<0>; 51 | using _2 = mp_arg<1>; 52 | using _3 = mp_arg<2>; 53 | using _4 = mp_arg<3>; 54 | using _5 = mp_arg<4>; 55 | using _6 = mp_arg<5>; 56 | using _7 = mp_arg<6>; 57 | using _8 = mp_arg<7>; 58 | using _9 = mp_arg<8>; 59 | 60 | // mp_bind 61 | template class F, class... T> struct mp_bind; 62 | 63 | namespace detail 64 | { 65 | 66 | template struct eval_bound_arg 67 | { 68 | using type = V; 69 | }; 70 | 71 | template struct eval_bound_arg, T...> 72 | { 73 | using type = typename mp_arg::template fn; 74 | }; 75 | 76 | template class F, class... U, class... T> struct eval_bound_arg, T...> 77 | { 78 | using type = typename mp_bind::template fn; 79 | }; 80 | 81 | template class F, class... U, class... T> struct eval_bound_arg, T...> 82 | { 83 | using type = typename mp_bind_front::template fn; 84 | }; 85 | 86 | template class F, class... U, class... T> struct eval_bound_arg, T...> 87 | { 88 | using type = typename mp_bind_back::template fn; 89 | }; 90 | 91 | } // namespace detail 92 | 93 | template class F, class... T> struct mp_bind 94 | { 95 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, == 1915 ) 96 | private: 97 | 98 | template struct _f { using type = F::type...>; }; 99 | 100 | public: 101 | 102 | template using fn = typename _f::type; 103 | 104 | #else 105 | 106 | template using fn = F::type...>; 107 | 108 | #endif 109 | }; 110 | 111 | template using mp_bind_q = mp_bind; 112 | 113 | } // namespace mp11 114 | } // namespace boost 115 | 116 | #if defined(_MSC_VER) || defined(__GNUC__) 117 | # pragma pop_macro( "I" ) 118 | #endif 119 | 120 | #endif // #ifndef BOOST_MP11_BIND_HPP_INCLUDED 121 | -------------------------------------------------------------------------------- /.github/tools/README.md: -------------------------------------------------------------------------------- 1 | # gdbf Build Tools 2 | 3 | This directory contains tools for building reproducible gdbf binaries. 4 | 5 | ## Reproducible Builds 6 | 7 | The reproducible build system uses Docker to create portable Linux binaries that will run on most modern Linux distributions (glibc 2.27+). 8 | 9 | ### Overview 10 | 11 | - **Base Image**: Debian Bullseye (oldoldstable) for maximum compatibility 12 | - **Compiler**: Clang 21.1.4 with libc++ (statically linked) 13 | - **CMake**: 3.27.6 14 | - **Build Features**: 15 | - Statically linked libc++ for portability 16 | - Security hardening flags enabled 17 | - Reproducible builds with pinned timestamps 18 | - Minimal dependencies (only X11 and FreeType required at runtime) 19 | 20 | ### Building Locally 21 | 22 | To build a reproducible binary locally: 23 | 24 | ```bash 25 | ./.github/tools/build-reproducible.sh [output-dir] 26 | ``` 27 | 28 | The binary will be created in the output directory (default: `build-reproducible/gdbf`). 29 | 30 | ### Requirements 31 | 32 | - Docker with BuildKit support 33 | - Docker Buildx (included in recent Docker versions) 34 | 35 | ### GitHub Actions Workflow 36 | 37 | The reproducible build runs automatically when a new release is published on GitHub. The workflow: 38 | 39 | 1. Builds the binary using the reproducible Dockerfile 40 | 2. Creates a tarball with version name (e.g., `gdbf-v1.0.0-linux-x86_64.tar.gz`) 41 | 3. Generates SHA256 checksum 42 | 4. Uploads the binary and checksum to the GitHub release 43 | 44 | You can also trigger a manual build via the GitHub Actions UI. 45 | 46 | ### Files 47 | 48 | - `reproducible.Dockerfile` - Multi-stage Docker build for reproducible binaries 49 | - `build-reproducible.sh` - Local build script for testing 50 | - `README.md` - This file 51 | 52 | ### Testing the Binary 53 | 54 | After building, verify the binary works: 55 | 56 | ```bash 57 | # Check binary information 58 | file build-reproducible/gdbf 59 | ldd build-reproducible/gdbf 60 | 61 | # Run the binary 62 | ./build-reproducible/gdbf --help 63 | ``` 64 | 65 | ### Portability 66 | 67 | The resulting binary should run on: 68 | - Ubuntu 18.04+ (Bionic and newer) 69 | - Debian 10+ (Buster and newer) 70 | - RHEL/CentOS 8+ 71 | - Fedora 28+ 72 | - Most modern Linux distributions 73 | 74 | Runtime requirements: 75 | - X11 libraries (libX11) 76 | - FreeType library (libfreetype) 77 | - Linux kernel 3.2+ 78 | - glibc 2.27+ 79 | 80 | ### Troubleshooting 81 | 82 | **Docker build fails:** 83 | - Ensure you have enough disk space (build requires ~5GB) 84 | - Make sure Docker BuildKit is enabled: `export DOCKER_BUILDKIT=1` 85 | 86 | **Binary won't run on target system:** 87 | - Check glibc version: `ldd --version` 88 | - Ensure X11 and FreeType are installed: `apt install libx11-6 libfreetype6` 89 | 90 | **GPG key verification fails:** 91 | - The build verifies signatures for CMake and LLVM downloads 92 | - If keys expire, update the key IDs in the Dockerfile 93 | 94 | ### Security 95 | 96 | The reproducible build includes security hardening: 97 | - Stack protection (`-fstack-protector-strong`) 98 | - Position-independent executable (PIE) 99 | - FORTIFY_SOURCE=2 100 | - RELRO and immediate binding for shared libraries 101 | - Static linking of C++ standard library to avoid ABI issues 102 | 103 | ### Reproducibility 104 | 105 | To verify reproducibility, build twice and compare: 106 | 107 | ```bash 108 | ./.github/tools/build-reproducible.sh output1 109 | ./.github/tools/build-reproducible.sh output2 110 | sha256sum output1/gdbf output2/gdbf 111 | ``` 112 | 113 | The hashes should be identical. 114 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mpl_common.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MPL_COMMON_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MPL_COMMON_HPP_INCLUDED 3 | 4 | // Copyright 2017, 2019 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | 14 | namespace boost 15 | { 16 | namespace mpl 17 | { 18 | 19 | struct forward_iterator_tag; 20 | 21 | namespace aux 22 | { 23 | 24 | struct mp11_tag {}; 25 | 26 | template struct mp11_iterator 27 | { 28 | using category = forward_iterator_tag; 29 | 30 | using type = mp11::mp_first; 31 | using next = mp11_iterator>; 32 | }; 33 | 34 | } // namespace aux 35 | 36 | // at 37 | 38 | template< typename Tag > struct at_impl; 39 | 40 | template<> struct at_impl 41 | { 42 | template struct apply 43 | { 44 | using type = mp11::mp_at; 45 | }; 46 | }; 47 | 48 | // back 49 | 50 | template< typename Tag > struct back_impl; 51 | 52 | template<> struct back_impl 53 | { 54 | template struct apply 55 | { 56 | using N = mp11::mp_size; 57 | using type = mp11::mp_at_c; 58 | }; 59 | }; 60 | 61 | // begin 62 | 63 | template< typename Tag > struct begin_impl; 64 | 65 | template<> struct begin_impl 66 | { 67 | template struct apply 68 | { 69 | using type = aux::mp11_iterator; 70 | }; 71 | }; 72 | 73 | // clear 74 | 75 | template< typename Tag > struct clear_impl; 76 | 77 | template<> struct clear_impl 78 | { 79 | template struct apply 80 | { 81 | using type = mp11::mp_clear; 82 | }; 83 | }; 84 | 85 | // end 86 | 87 | template< typename Tag > struct end_impl; 88 | 89 | template<> struct end_impl 90 | { 91 | template struct apply 92 | { 93 | using type = aux::mp11_iterator>; 94 | }; 95 | }; 96 | 97 | // front 98 | 99 | template< typename Tag > struct front_impl; 100 | 101 | template<> struct front_impl 102 | { 103 | template struct apply 104 | { 105 | using type = mp11::mp_front; 106 | }; 107 | }; 108 | 109 | // pop_front 110 | 111 | template< typename Tag > struct pop_front_impl; 112 | 113 | template<> struct pop_front_impl 114 | { 115 | template struct apply 116 | { 117 | using type = mp11::mp_pop_front; 118 | }; 119 | }; 120 | 121 | // push_back 122 | 123 | template< typename Tag > struct push_back_impl; 124 | 125 | template<> struct push_back_impl 126 | { 127 | template struct apply 128 | { 129 | using type = mp11::mp_push_back; 130 | }; 131 | }; 132 | 133 | // push_front 134 | 135 | template< typename Tag > struct push_front_impl; 136 | 137 | template<> struct push_front_impl 138 | { 139 | template struct apply 140 | { 141 | using type = mp11::mp_push_front; 142 | }; 143 | }; 144 | 145 | // size 146 | 147 | template< typename Tag > struct size_impl; 148 | 149 | template<> struct size_impl 150 | { 151 | template struct apply 152 | { 153 | using type = mp11::mp_size; 154 | }; 155 | }; 156 | 157 | } // namespace mpl 158 | } // namespace boost 159 | 160 | #endif // #ifndef BOOST_MP11_DETAIL_MPL_COMMON_HPP_INCLUDED 161 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/integer_sequence.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_INTEGER_SEQUENCE_HPP_INCLUDED 2 | #define BOOST_MP11_INTEGER_SEQUENCE_HPP_INCLUDED 3 | 4 | // Copyright 2015, 2017, 2019 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | 14 | #if defined(_MSC_VER) || defined(__GNUC__) 15 | # pragma push_macro( "I" ) 16 | # undef I 17 | #endif 18 | 19 | #if defined(__has_builtin) 20 | # if __has_builtin(__make_integer_seq) 21 | # define BOOST_MP11_HAS_MAKE_INTEGER_SEQ 22 | # endif 23 | #endif 24 | 25 | namespace boost 26 | { 27 | namespace mp11 28 | { 29 | 30 | // integer_sequence 31 | template struct integer_sequence 32 | { 33 | }; 34 | 35 | #if defined(BOOST_MP11_HAS_MAKE_INTEGER_SEQ) 36 | 37 | template using make_integer_sequence = __make_integer_seq; 38 | 39 | #else 40 | 41 | // detail::make_integer_sequence_impl 42 | namespace detail 43 | { 44 | 45 | // iseq_if_c 46 | template struct iseq_if_c_impl; 47 | 48 | template struct iseq_if_c_impl 49 | { 50 | using type = T; 51 | }; 52 | 53 | template struct iseq_if_c_impl 54 | { 55 | using type = E; 56 | }; 57 | 58 | template using iseq_if_c = typename iseq_if_c_impl::type; 59 | 60 | // iseq_identity 61 | template struct iseq_identity 62 | { 63 | using type = T; 64 | }; 65 | 66 | template struct append_integer_sequence; 67 | 68 | template struct append_integer_sequence, integer_sequence> 69 | { 70 | using type = integer_sequence< T, I..., ( J + sizeof...(I) )... >; 71 | }; 72 | 73 | template struct make_integer_sequence_impl; 74 | 75 | template struct make_integer_sequence_impl_ 76 | { 77 | private: 78 | 79 | static_assert( N >= 0, "make_integer_sequence: N must not be negative" ); 80 | 81 | static T const M = N / 2; 82 | static T const R = N % 2; 83 | 84 | using S1 = typename make_integer_sequence_impl::type; 85 | using S2 = typename append_integer_sequence::type; 86 | using S3 = typename make_integer_sequence_impl::type; 87 | using S4 = typename append_integer_sequence::type; 88 | 89 | public: 90 | 91 | using type = S4; 92 | }; 93 | 94 | template struct make_integer_sequence_impl: iseq_if_c>, iseq_if_c>, make_integer_sequence_impl_ > > 95 | { 96 | }; 97 | 98 | } // namespace detail 99 | 100 | // make_integer_sequence 101 | template using make_integer_sequence = typename detail::make_integer_sequence_impl::type; 102 | 103 | #endif // defined(BOOST_MP11_HAS_MAKE_INTEGER_SEQ) 104 | 105 | // index_sequence 106 | template using index_sequence = integer_sequence; 107 | 108 | // make_index_sequence 109 | template using make_index_sequence = make_integer_sequence; 110 | 111 | // index_sequence_for 112 | template using index_sequence_for = make_integer_sequence; 113 | 114 | } // namespace mp11 115 | } // namespace boost 116 | 117 | #if defined(_MSC_VER) || defined(__GNUC__) 118 | # pragma pop_macro( "I" ) 119 | #endif 120 | 121 | #endif // #ifndef BOOST_MP11_INTEGER_SEQUENCE_HPP_INCLUDED 122 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/map.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_MAP_HPP_INCLUDED 2 | #define BOOST_MP11_MAP_HPP_INCLUDED 3 | 4 | // Copyright 2015-2017 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace boost 21 | { 22 | namespace mp11 23 | { 24 | 25 | // mp_map_contains 26 | template using mp_map_contains = mp_not, void>>; 27 | 28 | // mp_map_insert 29 | template using mp_map_insert = mp_if< mp_map_contains>, M, mp_push_back >; 30 | 31 | // mp_map_replace 32 | namespace detail 33 | { 34 | 35 | template struct mp_map_replace_impl; 36 | 37 | template class M, class... U, class T> struct mp_map_replace_impl, T> 38 | { 39 | using K = mp_first; 40 | 41 | // mp_replace_if is inlined here using a struct _f because of msvc-14.0 42 | 43 | template struct _f { using type = mp_if< std::is_same, K>, T, V >; }; 44 | 45 | using type = mp_if< mp_map_contains, K>, M::type...>, M >; 46 | }; 47 | 48 | } // namespace detail 49 | 50 | template using mp_map_replace = typename detail::mp_map_replace_impl::type; 51 | 52 | // mp_map_update 53 | namespace detail 54 | { 55 | 56 | template class F> struct mp_map_update_impl 57 | { 58 | template using _f = std::is_same, mp_first>; 59 | 60 | // _f3> -> L> 61 | template using _f3 = mp_assign, mp_rename > >; 62 | 63 | using type = mp_if< mp_map_contains>, mp_transform_if<_f, _f3, M>, mp_push_back >; 64 | }; 65 | 66 | } // namespace detail 67 | 68 | template class F> using mp_map_update = typename detail::mp_map_update_impl::type; 69 | template using mp_map_update_q = mp_map_update; 70 | 71 | // mp_map_erase 72 | namespace detail 73 | { 74 | 75 | template struct mp_map_erase_impl 76 | { 77 | template using _f = std::is_same, K>; 78 | using type = mp_remove_if; 79 | }; 80 | 81 | } // namespace detail 82 | 83 | template using mp_map_erase = typename detail::mp_map_erase_impl::type; 84 | 85 | // mp_map_keys 86 | template using mp_map_keys = mp_transform; 87 | 88 | // mp_is_map 89 | namespace detail 90 | { 91 | 92 | template struct mp_is_map_element: mp_false 93 | { 94 | }; 95 | 96 | template class L, class T1, class... T> struct mp_is_map_element>: mp_true 97 | { 98 | }; 99 | 100 | template using mp_keys_are_set = mp_is_set>; 101 | 102 | template struct mp_is_map_impl 103 | { 104 | using type = mp_false; 105 | }; 106 | 107 | template class M, class... T> struct mp_is_map_impl> 108 | { 109 | using type = mp_eval_if...>>, mp_false, mp_keys_are_set, M>; 110 | }; 111 | 112 | } // namespace detail 113 | 114 | template using mp_is_map = typename detail::mp_is_map_impl::type; 115 | 116 | } // namespace mp11 117 | } // namespace boost 118 | 119 | #endif // #ifndef BOOST_MP11_MAP_HPP_INCLUDED 120 | -------------------------------------------------------------------------------- /examples/donut.cpp: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------------------ 2 | // From: https://github.com/sherwinvishesh/ASCII-Donut-Animation 3 | // 4 | // MIT License 5 | // 6 | // Copyright (c) 2024 Sherwin Vishesh Jathanna 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // ------------------------------------------------------------------------------------------ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | using namespace std; 34 | 35 | // Function to set the color based on user input 36 | string setColor(string color) { 37 | if (color == "red") { 38 | return "\033[31m"; 39 | } else if (color == "green") { 40 | return "\033[32m"; 41 | } else if (color == "yellow") { 42 | return "\033[33m"; 43 | } else if (color == "blue") { 44 | return "\033[34m"; 45 | } else if (color == "magenta") { 46 | return "\033[35m"; 47 | } else if (color == "cyan") { 48 | return "\033[36m"; 49 | } else if (color == "white") { 50 | return "\033[37m"; 51 | } 52 | // Default to white if no valid color is chosen 53 | return "\033[37m"; 54 | } 55 | 56 | int main() { 57 | float A = 0, B = 0, i, j; 58 | int size = 5; 59 | string colorInput {"blue"}; 60 | 61 | string color = setColor(colorInput); // Set color 62 | 63 | float R1 = 1, R2 = 2, K2 = 5; 64 | // Adjust R2 based on the size input 65 | R2 = R2 + (size - 5) * 0.2; // Scale R2 based on input size 66 | float K1 = 10 / (R1 + R2); 67 | vector b(1760, ' '); 68 | vector z(1760, 0); 69 | cout << "\x1b[2J"; 70 | for (;;) { 71 | fill(b.begin(), b.end(), ' '); 72 | fill(z.begin(), z.end(), 0); 73 | for (j = 0; 6.28 > j; j += 0.07) 74 | for (i = 0; 6.28 > i; i += 0.02) { 75 | float c = sin(i), d = cos(j), e = sin(A), f = sin(j), 76 | g = cos(A), h = d + 2, D = 1 / (c * h * e + f * g + 5), 77 | l = cos(i), m = cos(B), n = sin(B), 78 | t = c * h * g - f * e; 79 | int x = 40 + 30 * D * (l * h * m - t * n), 80 | y = 12 + 15 * D * (l * h * n + t * m), 81 | o = x + 80 * y, 82 | N = 8 * ((f * e - c * d * g) * m - c * d * e - f * g - l * d * n); 83 | if (22 > y && y > 0 && x > 0 && 80 > x && D > z[o]) { 84 | z[o] = D; 85 | b[o] = ".,-~:;=!*#$@"[N > 0 ? N : 0]; 86 | } 87 | } 88 | cout << "\x1b[H"; 89 | for (int k = 0; 1761 > k; k++) 90 | if (k % 80) { 91 | cout << color << b[k]; 92 | } else { 93 | cout << endl; 94 | } 95 | A += 0.04; 96 | B += 0.02; 97 | usleep(30000); 98 | } 99 | return 0; 100 | } -------------------------------------------------------------------------------- /src/re/gdb.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | using namespace ctre::literals; 9 | using namespace regexp; 10 | 11 | // -------------------------------------------------------------------------------- 12 | bool gdb_impl::matches(std::string_view s, debug_look_for lf, size_t pos /* = 0 */) const { 13 | switch(lf) { 14 | case debug_look_for::stack_or_breakpoint_output: 15 | return static_cast(ctre::starts_with<"(Num|#[0-9]+)[ ]+">(s.substr(pos))); 16 | 17 | case debug_look_for::evaluation_error: 18 | return static_cast(ctre::starts_with<"(A syntax error|No symbol|Attempt to|cannot resolve)">(s.substr(pos))); 19 | 20 | default: 21 | assert(0); 22 | } 23 | return false; 24 | } 25 | 26 | // -------------------------------------------------------------------------------- 27 | opt_res_t<1> gdb_impl::find_1(std::string_view s, debug_look_for lf, size_t pos /* = 0 */) const { 28 | switch(lf) { 29 | 30 | default: 31 | assert(0); 32 | } 33 | return {}; 34 | } 35 | 36 | // -------------------------------------------------------------------------------- 37 | opt_res_t<2> gdb_impl::find_2(std::string_view s, debug_look_for lf, size_t pos /* = 0 */) const { 38 | switch(lf) { 39 | 40 | default: 41 | assert(0); 42 | } 43 | return {}; 44 | } 45 | 46 | // -------------------------------------------------------------------------------- 47 | opt_res_t<3> gdb_impl::find_3(std::string_view s, debug_look_for lf, size_t pos /* = 0 */) const { 48 | switch(lf) { 49 | 50 | default: 51 | assert(0); 52 | } 53 | return {}; 54 | } 55 | 56 | // -------------------------------------------------------------------------------- 57 | opt_res_t<4> gdb_impl::find_4(std::string_view s, debug_look_for lf, size_t pos /* = 0 */) const { 58 | switch(lf) { 59 | 60 | default: 61 | assert(0); 62 | } 63 | return {}; 64 | } 65 | 66 | // -------------------------------------------------------------------------------- 67 | vec_res_t<1> gdb_impl::find_1s(std::string_view s, debug_look_for lf, size_t pos /* = 0 */) const { 68 | switch(lf) { 69 | 70 | default: 71 | assert(0); 72 | } 73 | return {}; 74 | } 75 | 76 | // -------------------------------------------------------------------------------- 77 | vec_res_t<2> gdb_impl::find_2s(std::string_view s, debug_look_for lf, size_t pos /* = 0 */) const { 78 | switch(lf) { 79 | 80 | default: 81 | assert(0); 82 | } 83 | return {}; 84 | } 85 | 86 | // -------------------------------------------------------------------------------- 87 | vec_res_t<3> gdb_impl::find_3s(std::string_view s, debug_look_for lf, size_t pos /* = 0 */) const { 88 | switch(lf) { 89 | 90 | default: 91 | assert(0); 92 | } 93 | return {}; 94 | } 95 | 96 | // -------------------------------------------------------------------------------- 97 | vec_res_t<4> gdb_impl::find_4s(std::string_view s, debug_look_for lf, size_t pos /* = 0 */) const { 98 | vec_res_t<4> res; 99 | 100 | switch(lf) { 101 | case debug_look_for::thread_info: 102 | // ---------------------------------- gdb output -------------------------------------------- 103 | // Id Target Id Frame 104 | // * 1 Thread 0x7ffff78eb780 (LWP 1103966) "gf" 0x00007ffff7718bcf in poll () from /lib/x86_64-linux-gnu/libc.so.6 105 | // 3 Thread 0x7ffff3200640 (LWP 1103968) "gdb_thread" 0x00007ffff771b63d in select () from /lib/x86_64-linux-gnu/libc.so.6 106 | // (gdb) 107 | // ------------------------------------------------------------------------------------------ 108 | res.reserve(8); 109 | for (auto match : ctre::multiline_search_all(s)) { 110 | auto [m, sel, id, name, frame] = match; 111 | res.push_back(tuples_t<4>{sel, id, name, frame}); 112 | } 113 | return res; 114 | 115 | default: 116 | assert(0); 117 | } 118 | return res; 119 | } 120 | -------------------------------------------------------------------------------- /.github/tools/reproducible.Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | # Use Debian Bullseye (oldoldstable) for good compatibility while still being accessible 3 | # debian:bullseye-20240722-slim 4 | FROM debian:bullseye-20240722-slim AS builder 5 | 6 | ENV SOURCE_DATE_EPOCH=1721606400 7 | 8 | RUN apt-get update && apt-get -y upgrade && DEBIAN_FRONTEND=noninteractive apt-get -y install \ 9 | build-essential \ 10 | file \ 11 | git \ 12 | libfreetype6-dev \ 13 | libx11-dev \ 14 | x11-common \ 15 | ninja-build \ 16 | python3 \ 17 | zlib1g-dev \ 18 | ca-certificates \ 19 | curl \ 20 | xz-utils \ 21 | lsb-release \ 22 | wget \ 23 | software-properties-common \ 24 | gnupg \ 25 | ; 26 | 27 | # Install LLVM 18 from apt to bootstrap the build of LLVM 21 28 | RUN wget https://apt.llvm.org/llvm.sh && \ 29 | chmod +x llvm.sh && \ 30 | ./llvm.sh 18 && \ 31 | rm llvm.sh 32 | 33 | ARG _GDBF_CLANG_VERSION=21.1.4 34 | ARG _GDBF_CMAKE_VERSION=3.27.6 35 | 36 | # Download CMake and LLVM sources 37 | RUN curl -fsSL -o /cmake.tar.gz \ 38 | https://github.com/Kitware/CMake/releases/download/v${_GDBF_CMAKE_VERSION}/cmake-${_GDBF_CMAKE_VERSION}.tar.gz && \ 39 | curl -fsSL -o /llvm-project.tar.xz \ 40 | https://github.com/llvm/llvm-project/releases/download/llvmorg-${_GDBF_CLANG_VERSION}/llvm-project-${_GDBF_CLANG_VERSION}.src.tar.xz 41 | 42 | # Build and install CMake 43 | RUN tar xf /cmake.tar.gz && \ 44 | cd cmake-${_GDBF_CMAKE_VERSION} && \ 45 | echo 'set(CMAKE_USE_OPENSSL OFF CACHE BOOL "" FORCE)' > gdbf-init.cmake && \ 46 | ./bootstrap --parallel=$(nproc) --init=gdbf-init.cmake --generator=Ninja && \ 47 | ninja install && \ 48 | cd / && rm -rf /cmake* cmake-* 49 | 50 | # Build and install Clang/LLVM toolchain using LLVM 18 as bootstrap compiler 51 | RUN tar xf /llvm-project.tar.xz && \ 52 | cmake -S llvm-project-${_GDBF_CLANG_VERSION}.src/llvm -B build-toolchain -GNinja \ 53 | -DCMAKE_C_COMPILER=clang-18 \ 54 | -DCMAKE_CXX_COMPILER=clang++-18 \ 55 | -DCMAKE_C_FLAGS="-march=x86-64" \ 56 | -DCMAKE_CXX_FLAGS="-march=x86-64" \ 57 | -DLLVM_INCLUDE_DOCS=Off \ 58 | -DLLVM_TARGETS_TO_BUILD=X86 \ 59 | -DCMAKE_BUILD_TYPE=Release \ 60 | -DCMAKE_INSTALL_PREFIX=/pinnedtoolchain \ 61 | -DCOMPILER_RT_BUILD_SANITIZERS=Off \ 62 | -DLIBCXX_HARDENING_MODE=fast \ 63 | -DLLVM_ENABLE_PROJECTS='lld;clang;clang-tools-extra' \ 64 | -DLLVM_ENABLE_RUNTIMES='compiler-rt;libcxx;libcxxabi;libunwind' && \ 65 | cmake --build build-toolchain -t install && \ 66 | cd / && rm -rf /build* /llvm* 67 | 68 | # Create CMake toolchain file for reproducible builds 69 | COPY <<-"EOF" /pinnedtoolchain/pinnedtoolchain.cmake 70 | set(CMAKE_C_COMPILER ${CMAKE_CURRENT_LIST_DIR}/bin/clang) 71 | set(CMAKE_CXX_COMPILER ${CMAKE_CURRENT_LIST_DIR}/bin/clang++) 72 | 73 | set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/include/c++/v1 ${CMAKE_CURRENT_LIST_DIR}/include/x86_64-unknown-linux-gnu/c++/v1 /usr/local/include /usr/include) 74 | 75 | set(CMAKE_C_FLAGS_INIT "-march=x86-64 -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -pthread") 76 | set(CMAKE_CXX_FLAGS_INIT "-march=x86-64 -nostdinc++ -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -pthread") 77 | 78 | set(CMAKE_EXE_LINKER_FLAGS_INIT "-stdlib=libc++ -nostdlib++ -pie -pthread -Wl,-z,relro,-z,now") 79 | set(CMAKE_SHARED_LINKER_FLAGS_INIT "-stdlib=libc++ -nostdlib++") 80 | set(CMAKE_MODULE_LINKER_FLAGS_INIT "-stdlib=libc++ -nostdlib++") 81 | 82 | set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CURRENT_LIST_DIR}/lib/x86_64-unknown-linux-gnu/libc++.a ${CMAKE_CURRENT_LIST_DIR}/lib/x86_64-unknown-linux-gnu/libc++abi.a") 83 | EOF 84 | 85 | ENV CMAKE_TOOLCHAIN_FILE=/pinnedtoolchain/pinnedtoolchain.cmake 86 | 87 | FROM builder AS build 88 | 89 | ARG GDBF_BUILD_JOBS 90 | 91 | COPY / /gdbf 92 | 93 | RUN cmake -S /gdbf -B build \ 94 | -DCMAKE_BUILD_TYPE=Release \ 95 | -GNinja && \ 96 | cmake --build build ${GDBF_BUILD_JOBS:+-j$GDBF_BUILD_JOBS} 97 | 98 | FROM scratch AS exporter 99 | COPY --from=build /build/gdbf /gdbf 100 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/config.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_CONFIG_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_CONFIG_HPP_INCLUDED 3 | 4 | // Copyright 2016, 2018, 2019 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | // BOOST_MP11_WORKAROUND 12 | 13 | #if defined( BOOST_STRICT_CONFIG ) || defined( BOOST_MP11_NO_WORKAROUNDS ) 14 | 15 | # define BOOST_MP11_WORKAROUND( symbol, test ) 0 16 | 17 | #else 18 | 19 | # define BOOST_MP11_WORKAROUND( symbol, test ) ((symbol) != 0 && ((symbol) test)) 20 | 21 | #endif 22 | 23 | // 24 | 25 | #define BOOST_MP11_CUDA 0 26 | #define BOOST_MP11_CLANG 0 27 | #define BOOST_MP11_INTEL 0 28 | #define BOOST_MP11_GCC 0 29 | #define BOOST_MP11_MSVC 0 30 | 31 | #define BOOST_MP11_CONSTEXPR constexpr 32 | 33 | #if defined( __CUDACC__ ) 34 | 35 | // nvcc 36 | 37 | # undef BOOST_MP11_CUDA 38 | # define BOOST_MP11_CUDA (__CUDACC_VER_MAJOR__ * 1000000 + __CUDACC_VER_MINOR__ * 10000 + __CUDACC_VER_BUILD__) 39 | 40 | // CUDA (8.0) has no constexpr support in msvc mode: 41 | # if defined(_MSC_VER) && (BOOST_MP11_CUDA < 9000000) 42 | 43 | # define BOOST_MP11_NO_CONSTEXPR 44 | 45 | # undef BOOST_MP11_CONSTEXPR 46 | # define BOOST_MP11_CONSTEXPR 47 | 48 | # endif 49 | 50 | #endif 51 | 52 | #if defined(__clang__) 53 | 54 | // Clang 55 | 56 | # undef BOOST_MP11_CLANG 57 | # define BOOST_MP11_CLANG (__clang_major__ * 100 + __clang_minor__) 58 | 59 | # if defined(__has_cpp_attribute) 60 | # if __has_cpp_attribute(fallthrough) && __cplusplus >= 201406L // Clang 3.9+ in c++1z mode 61 | # define BOOST_MP11_HAS_FOLD_EXPRESSIONS 62 | # endif 63 | # endif 64 | 65 | #if BOOST_MP11_CLANG < 400 && __cplusplus >= 201402L \ 66 | && defined( __GLIBCXX__ ) && !__has_include() 67 | 68 | // Clang pre-4 in C++14 mode, libstdc++ pre-4.9, ::gets is not defined, 69 | // but Clang tries to import it into std 70 | 71 | extern "C" char *gets (char *__s); 72 | #endif 73 | 74 | #elif defined(__INTEL_COMPILER) 75 | 76 | // Intel C++ 77 | 78 | # undef BOOST_MP11_INTEL 79 | # define BOOST_MP11_INTEL __INTEL_COMPILER 80 | 81 | #elif defined(__GNUC__) 82 | 83 | // g++ 84 | 85 | # undef BOOST_MP11_GCC 86 | # define BOOST_MP11_GCC (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 87 | 88 | #elif defined(_MSC_VER) 89 | 90 | // MS Visual C++ 91 | 92 | # undef BOOST_MP11_MSVC 93 | # define BOOST_MP11_MSVC _MSC_VER 94 | 95 | # if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) 96 | # define BOOST_MP11_NO_CONSTEXPR 97 | # endif 98 | 99 | #if _MSC_FULL_VER < 190024210 // 2015u3 100 | # undef BOOST_MP11_CONSTEXPR 101 | # define BOOST_MP11_CONSTEXPR 102 | #endif 103 | 104 | #endif 105 | 106 | // BOOST_MP11_HAS_CXX14_CONSTEXPR 107 | 108 | #if !defined(BOOST_MP11_NO_CONSTEXPR) && defined(__cpp_constexpr) && __cpp_constexpr >= 201304 109 | # define BOOST_MP11_HAS_CXX14_CONSTEXPR 110 | #endif 111 | 112 | // BOOST_MP11_HAS_FOLD_EXPRESSIONS 113 | 114 | #if !defined(BOOST_MP11_HAS_FOLD_EXPRESSIONS) && defined(__cpp_fold_expressions) && __cpp_fold_expressions >= 201603 115 | # define BOOST_MP11_HAS_FOLD_EXPRESSIONS 116 | #endif 117 | 118 | // BOOST_MP11_HAS_TYPE_PACK_ELEMENT 119 | 120 | #if defined(__has_builtin) 121 | # if __has_builtin(__type_pack_element) 122 | # define BOOST_MP11_HAS_TYPE_PACK_ELEMENT 123 | # endif 124 | #endif 125 | 126 | // BOOST_MP11_HAS_TEMPLATE_AUTO 127 | 128 | #if defined(__cpp_nontype_template_parameter_auto) && __cpp_nontype_template_parameter_auto >= 201606L 129 | # define BOOST_MP11_HAS_TEMPLATE_AUTO 130 | #endif 131 | 132 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) 133 | // mp_value<0> is bool, mp_value<-1L> is int, etc 134 | # undef BOOST_MP11_HAS_TEMPLATE_AUTO 135 | #endif 136 | 137 | // BOOST_MP11_DEPRECATED(msg) 138 | 139 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_CLANG, < 304 ) 140 | # define BOOST_MP11_DEPRECATED(msg) 141 | #elif defined(__GNUC__) || defined(__clang__) 142 | # define BOOST_MP11_DEPRECATED(msg) __attribute__((deprecated(msg))) 143 | #elif defined(_MSC_VER) && _MSC_VER >= 1900 144 | # define BOOST_MP11_DEPRECATED(msg) [[deprecated(msg)]] 145 | #else 146 | # define BOOST_MP11_DEPRECATED(msg) 147 | #endif 148 | 149 | #endif // #ifndef BOOST_MP11_DETAIL_CONFIG_HPP_INCLUDED 150 | -------------------------------------------------------------------------------- /src/re/re.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | namespace regexp { 11 | 12 | struct bounds { size_t start, end; }; 13 | 14 | enum expr_flags { 15 | allow_function_calls = 1 << 0, 16 | avoid_constant_litterals = 1 << 1 17 | }; 18 | 19 | enum class code_look_for { 20 | selectable_expression // an expression to select when double clicking (compat. with `add_watch`) 21 | }; 22 | 23 | enum class debug_look_for { 24 | stack_or_breakpoint_output, // debugger output when hitting a breakpoint or stack frame change 25 | evaluation_error, // debugger output when evaluating an expression fails 26 | thread_info // `info threads` debugger output -> (id, thread_name, stack_frame) 27 | }; 28 | 29 | using sv_t = std::string_view; 30 | 31 | template 32 | using tuples_t = boost::mp11::mp_repeat_c, N>; // tuple 33 | 34 | template 35 | using opt_res_t = std::optional>; // optional> 36 | 37 | template 38 | using vec_res_t = std::vector>; // vector> 39 | 40 | // -------- 41 | // debugger 42 | // -------- 43 | struct debugger_base { 44 | virtual ~debugger_base() {} 45 | 46 | virtual bool matches(sv_t s, debug_look_for lf, size_t pos = 0) const = 0; 47 | 48 | virtual opt_res_t<1> find_1(sv_t s, debug_look_for lf, size_t pos = 0) const = 0; 49 | virtual opt_res_t<2> find_2(sv_t s, debug_look_for lf, size_t pos = 0) const = 0; 50 | virtual opt_res_t<3> find_3(sv_t s, debug_look_for lf, size_t pos = 0) const = 0; 51 | virtual opt_res_t<4> find_4(sv_t s, debug_look_for lf, size_t pos = 0) const = 0; 52 | 53 | virtual vec_res_t<1> find_1s(sv_t s, debug_look_for lf, size_t pos = 0) const = 0; 54 | virtual vec_res_t<2> find_2s(sv_t s, debug_look_for lf, size_t pos = 0) const = 0; 55 | virtual vec_res_t<3> find_3s(sv_t s, debug_look_for lf, size_t pos = 0) const = 0; 56 | virtual vec_res_t<4> find_4s(sv_t s, debug_look_for lf, size_t pos = 0) const = 0; 57 | }; 58 | 59 | struct gdb_impl : public debugger_base { 60 | bool matches(sv_t s, debug_look_for lf, size_t pos = 0) const final; 61 | 62 | opt_res_t<1> find_1(sv_t s, debug_look_for lf, size_t pos = 0) const final; 63 | opt_res_t<2> find_2(sv_t s, debug_look_for lf, size_t pos = 0) const final; 64 | opt_res_t<3> find_3(sv_t s, debug_look_for lf, size_t pos = 0) const final; 65 | opt_res_t<4> find_4(sv_t s, debug_look_for lf, size_t pos = 0) const final; 66 | 67 | vec_res_t<1> find_1s(sv_t s, debug_look_for lf, size_t pos = 0) const final; 68 | vec_res_t<2> find_2s(sv_t s, debug_look_for lf, size_t pos = 0) const final; 69 | vec_res_t<3> find_3s(sv_t s, debug_look_for lf, size_t pos = 0) const final; 70 | vec_res_t<4> find_4s(sv_t s, debug_look_for lf, size_t pos = 0) const final; 71 | }; 72 | 73 | // -------- 74 | // language 75 | // -------- 76 | struct language_base { 77 | virtual ~language_base() {} 78 | 79 | virtual std::vector debuggable_expressions(sv_t code, uint32_t e = 0) const = 0; 80 | virtual std::optional find_at_pos(sv_t code, code_look_for lf, size_t pos) const = 0; 81 | 82 | virtual bool matches(sv_t s, code_look_for lf, size_t pos = 0) const = 0; 83 | virtual opt_res_t<1> find_1(sv_t s, code_look_for lf, size_t pos = 0) const = 0; 84 | virtual opt_res_t<2> find_2(sv_t s, code_look_for lf, size_t pos = 0) const = 0; 85 | virtual opt_res_t<3> find_3(sv_t s, code_look_for lf, size_t pos = 0) const = 0; 86 | }; 87 | 88 | struct cpp_impl : public language_base { 89 | std::vector debuggable_expressions(sv_t code, uint32_t e = 0) const final; 90 | std::optional find_at_pos(sv_t code, code_look_for lf, size_t pos) const final; 91 | 92 | bool matches(sv_t s, code_look_for lf, size_t pos = 0) const final; 93 | opt_res_t<1> find_1(sv_t s, code_look_for lf, size_t pos = 0) const final; 94 | opt_res_t<2> find_2(sv_t s, code_look_for lf, size_t pos = 0) const final; 95 | opt_res_t<3> find_3(sv_t s, code_look_for lf, size_t pos = 0) const final; 96 | }; 97 | 98 | // ---- 99 | // misc 100 | // ---- 101 | struct misc { 102 | 103 | }; 104 | 105 | 106 | } -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_count.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_COUNT_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_COUNT_HPP_INCLUDED 3 | 4 | // Copyright 2015, 2016 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace boost 16 | { 17 | namespace mp11 18 | { 19 | 20 | // mp_count 21 | namespace detail 22 | { 23 | 24 | #if !defined( BOOST_MP11_NO_CONSTEXPR ) 25 | 26 | constexpr std::size_t cx_plus() 27 | { 28 | return 0; 29 | } 30 | 31 | template constexpr std::size_t cx_plus(T1 t1, T... t) 32 | { 33 | return static_cast(t1) + cx_plus(t...); 34 | } 35 | 36 | template 37 | constexpr std::size_t cx_plus(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T... t) 38 | { 39 | return static_cast(t1 + t2 + t3 + t4 + t5 + t6 + t7 + t8 + t9 + t10) + cx_plus(t...); 40 | } 41 | 42 | #endif 43 | 44 | template struct mp_count_impl; 45 | 46 | #if defined( BOOST_MP11_HAS_CXX14_CONSTEXPR ) 47 | 48 | template constexpr std::size_t cx_count() 49 | { 50 | constexpr bool a[] = { false, std::is_same::value... }; 51 | 52 | std::size_t r = 0; 53 | 54 | for( std::size_t i = 0; i < sizeof...(T); ++i ) 55 | { 56 | r += a[ i+1 ]; 57 | } 58 | 59 | return r; 60 | } 61 | 62 | template class L, class... T, class V> struct mp_count_impl, V> 63 | { 64 | using type = mp_size_t()>; 65 | }; 66 | 67 | #elif !defined( BOOST_MP11_NO_CONSTEXPR ) 68 | 69 | template class L, class... T, class V> struct mp_count_impl, V> 70 | { 71 | using type = mp_size_t::value...)>; 72 | }; 73 | 74 | #else 75 | 76 | template class L, class... T, class V> struct mp_count_impl, V> 77 | { 78 | using type = mp_size_t...>::value>; 79 | }; 80 | 81 | #endif 82 | 83 | } // namespace detail 84 | 85 | template using mp_count = typename detail::mp_count_impl::type; 86 | 87 | // mp_count_if 88 | namespace detail 89 | { 90 | 91 | template class P> struct mp_count_if_impl; 92 | 93 | #if defined( BOOST_MP11_HAS_CXX14_CONSTEXPR ) && !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1930 ) 94 | 95 | template class P, class... T> constexpr std::size_t cx_count_if() 96 | { 97 | constexpr bool a[] = { false, static_cast( P::value )... }; 98 | 99 | std::size_t r = 0; 100 | 101 | for( std::size_t i = 0; i < sizeof...(T); ++i ) 102 | { 103 | r += a[ i+1 ]; 104 | } 105 | 106 | return r; 107 | } 108 | 109 | template class L, class... T, template class P> struct mp_count_if_impl, P> 110 | { 111 | using type = mp_size_t()>; 112 | }; 113 | 114 | #elif !defined( BOOST_MP11_NO_CONSTEXPR ) 115 | 116 | template class L, class... T, template class P> struct mp_count_if_impl, P> 117 | { 118 | using type = mp_size_t>::value...)>; 119 | }; 120 | 121 | #else 122 | 123 | template class L, class... T, template class P> struct mp_count_if_impl, P> 124 | { 125 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) 126 | 127 | template struct _f { using type = mp_to_bool>; }; 128 | using type = mp_size_t::type...>::value>; 129 | 130 | #else 131 | 132 | using type = mp_size_t>...>::value>; 133 | 134 | #endif 135 | }; 136 | 137 | #endif 138 | 139 | } // namespace detail 140 | 141 | template class P> using mp_count_if = typename detail::mp_count_if_impl::type; 142 | template using mp_count_if_q = mp_count_if; 143 | 144 | } // namespace mp11 145 | } // namespace boost 146 | 147 | #endif // #ifndef BOOST_MP11_DETAIL_MP_COUNT_HPP_INCLUDED 148 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/utility.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_UTILITY_HPP_INCLUDED 2 | #define BOOST_MP11_UTILITY_HPP_INCLUDED 3 | 4 | // Copyright 2015-2020 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace boost 20 | { 21 | namespace mp11 22 | { 23 | 24 | // mp_identity 25 | template struct mp_identity 26 | { 27 | using type = T; 28 | }; 29 | 30 | // mp_identity_t 31 | template using mp_identity_t = typename mp_identity::type; 32 | 33 | // mp_inherit 34 | template struct mp_inherit: T... {}; 35 | 36 | // mp_if, mp_if_c 37 | // mp_valid 38 | // mp_defer 39 | // moved to detail/mp_defer.hpp 40 | 41 | // mp_eval_if, mp_eval_if_c 42 | namespace detail 43 | { 44 | 45 | template class F, class... U> struct mp_eval_if_c_impl; 46 | 47 | template class F, class... U> struct mp_eval_if_c_impl 48 | { 49 | using type = T; 50 | }; 51 | 52 | template class F, class... U> struct mp_eval_if_c_impl: mp_defer 53 | { 54 | }; 55 | 56 | } // namespace detail 57 | 58 | template class F, class... U> using mp_eval_if_c = typename detail::mp_eval_if_c_impl::type; 59 | template class F, class... U> using mp_eval_if = typename detail::mp_eval_if_c_impl(C::value), T, F, U...>::type; 60 | template using mp_eval_if_q = typename detail::mp_eval_if_c_impl(C::value), T, Q::template fn, U...>::type; 61 | 62 | // mp_eval_if_not 63 | template class F, class... U> using mp_eval_if_not = mp_eval_if, T, F, U...>; 64 | template using mp_eval_if_not_q = mp_eval_if, T, Q::template fn, U...>; 65 | 66 | // mp_eval_or 67 | template class F, class... U> using mp_eval_or = mp_eval_if_not, T, F, U...>; 68 | template using mp_eval_or_q = mp_eval_or; 69 | 70 | // mp_valid_and_true 71 | template class F, class... T> using mp_valid_and_true = mp_eval_or; 72 | template using mp_valid_and_true_q = mp_valid_and_true; 73 | 74 | // mp_cond 75 | 76 | // so elegant; so doesn't work 77 | // template using mp_cond = mp_eval_if; 78 | 79 | namespace detail 80 | { 81 | 82 | template struct mp_cond_impl; 83 | 84 | } // namespace detail 85 | 86 | template using mp_cond = typename detail::mp_cond_impl::type; 87 | 88 | namespace detail 89 | { 90 | 91 | template using mp_cond_ = mp_eval_if; 92 | 93 | template struct mp_cond_impl: mp_defer 94 | { 95 | }; 96 | 97 | } // namespace detail 98 | 99 | // mp_quote 100 | template class F> struct mp_quote 101 | { 102 | // the indirection through mp_defer works around the language inability 103 | // to expand T... into a fixed parameter list of an alias template 104 | 105 | template using fn = typename mp_defer::type; 106 | }; 107 | 108 | // mp_quote_trait 109 | template class F> struct mp_quote_trait 110 | { 111 | template using fn = typename F::type; 112 | }; 113 | 114 | // mp_invoke_q 115 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1900 ) 116 | 117 | namespace detail 118 | { 119 | 120 | template struct mp_invoke_q_impl: mp_defer {}; 121 | 122 | } // namespace detail 123 | 124 | template using mp_invoke_q = typename detail::mp_invoke_q_impl::type; 125 | 126 | #elif BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, < 50000 ) 127 | 128 | template using mp_invoke_q = typename mp_defer::type; 129 | 130 | #else 131 | 132 | template using mp_invoke_q = typename Q::template fn; 133 | 134 | #endif 135 | 136 | // mp_not_fn

137 | template class P> struct mp_not_fn 138 | { 139 | template using fn = mp_not< mp_invoke_q, T...> >; 140 | }; 141 | 142 | template using mp_not_fn_q = mp_not_fn; 143 | 144 | // mp_compose 145 | namespace detail 146 | { 147 | 148 | template using mp_compose_helper = mp_list< mp_apply_q >; 149 | 150 | } // namespace detail 151 | 152 | #if !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1900 ) 153 | 154 | template class... F> struct mp_compose 155 | { 156 | template using fn = mp_front< mp_fold...>, mp_list, detail::mp_compose_helper> >; 157 | }; 158 | 159 | #endif 160 | 161 | template struct mp_compose_q 162 | { 163 | template using fn = mp_front< mp_fold, mp_list, detail::mp_compose_helper> >; 164 | }; 165 | 166 | } // namespace mp11 167 | } // namespace boost 168 | 169 | #endif // #ifndef BOOST_MP11_UTILITY_HPP_INCLUDED 170 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/function.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_FUNCTION_HPP_INCLUDED 2 | #define BOOST_MP11_FUNCTION_HPP_INCLUDED 3 | 4 | // Copyright 2015-2019 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace boost 22 | { 23 | namespace mp11 24 | { 25 | 26 | // mp_void 27 | // in detail/mp_void.hpp 28 | 29 | // mp_and 30 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1910 ) 31 | 32 | namespace detail 33 | { 34 | 35 | template struct mp_and_impl; 36 | 37 | } // namespace detail 38 | 39 | template using mp_and = mp_to_bool< typename detail::mp_and_impl::type >; 40 | 41 | namespace detail 42 | { 43 | 44 | template<> struct mp_and_impl<> 45 | { 46 | using type = mp_true; 47 | }; 48 | 49 | template struct mp_and_impl 50 | { 51 | using type = T; 52 | }; 53 | 54 | template struct mp_and_impl 55 | { 56 | using type = mp_eval_if< mp_not, T1, mp_and, T... >; 57 | }; 58 | 59 | } // namespace detail 60 | 61 | #else 62 | 63 | namespace detail 64 | { 65 | 66 | template struct mp_and_impl 67 | { 68 | using type = mp_false; 69 | }; 70 | 71 | template struct mp_and_impl< mp_list, mp_void...> > 72 | { 73 | using type = mp_true; 74 | }; 75 | 76 | } // namespace detail 77 | 78 | template using mp_and = typename detail::mp_and_impl>::type; 79 | 80 | #endif 81 | 82 | // mp_all 83 | // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86355 84 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) || BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, != 0 ) 85 | 86 | template using mp_all = mp_bool< mp_count_if< mp_list, mp_not >::value == 0 >; 87 | 88 | #else 89 | 90 | template using mp_all = mp_bool< mp_count< mp_list...>, mp_false >::value == 0 >; 91 | 92 | #endif 93 | 94 | // mp_or 95 | namespace detail 96 | { 97 | 98 | template struct mp_or_impl; 99 | 100 | } // namespace detail 101 | 102 | template using mp_or = mp_to_bool< typename detail::mp_or_impl::type >; 103 | 104 | namespace detail 105 | { 106 | 107 | template<> struct mp_or_impl<> 108 | { 109 | using type = mp_false; 110 | }; 111 | 112 | template struct mp_or_impl 113 | { 114 | using type = T; 115 | }; 116 | 117 | template struct mp_or_impl 118 | { 119 | using type = mp_eval_if< T1, T1, mp_or, T... >; 120 | }; 121 | 122 | } // namespace detail 123 | 124 | // mp_any 125 | // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86356 126 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) || BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, != 0 ) 127 | 128 | template using mp_any = mp_bool< mp_count_if< mp_list, mp_to_bool >::value != 0 >; 129 | 130 | #else 131 | 132 | template using mp_any = mp_bool< mp_count< mp_list...>, mp_true >::value != 0 >; 133 | 134 | #endif 135 | 136 | // mp_same 137 | namespace detail 138 | { 139 | 140 | template struct mp_same_impl; 141 | 142 | template<> struct mp_same_impl<> 143 | { 144 | using type = mp_true; 145 | }; 146 | 147 | template struct mp_same_impl 148 | { 149 | using type = mp_bool< mp_count, T1>::value == sizeof...(T) >; 150 | }; 151 | 152 | } // namespace detail 153 | 154 | template using mp_same = typename detail::mp_same_impl::type; 155 | 156 | // mp_similar 157 | namespace detail 158 | { 159 | 160 | template struct mp_similar_impl; 161 | 162 | template<> struct mp_similar_impl<> 163 | { 164 | using type = mp_true; 165 | }; 166 | 167 | template struct mp_similar_impl 168 | { 169 | using type = mp_true; 170 | }; 171 | 172 | template struct mp_similar_impl 173 | { 174 | using type = mp_true; 175 | }; 176 | 177 | template struct mp_similar_impl 178 | { 179 | using type = mp_false; 180 | }; 181 | 182 | template class L, class... T1, class... T2> struct mp_similar_impl, L> 183 | { 184 | using type = mp_true; 185 | }; 186 | 187 | template class L, class... T> struct mp_similar_impl, L> 188 | { 189 | using type = mp_true; 190 | }; 191 | 192 | template struct mp_similar_impl 193 | { 194 | using type = mp_all< typename mp_similar_impl::type, typename mp_similar_impl::type, typename mp_similar_impl::type... >; 195 | }; 196 | 197 | } // namespace detail 198 | 199 | template using mp_similar = typename detail::mp_similar_impl::type; 200 | 201 | #if BOOST_MP11_GCC 202 | # pragma GCC diagnostic push 203 | # pragma GCC diagnostic ignored "-Wsign-compare" 204 | #endif 205 | 206 | // mp_less 207 | template using mp_less = mp_bool<(T1::value < 0 && T2::value >= 0) || ((T1::value < T2::value) && !(T1::value >= 0 && T2::value < 0))>; 208 | 209 | #if BOOST_MP11_GCC 210 | # pragma GCC diagnostic pop 211 | #endif 212 | 213 | // mp_min 214 | template using mp_min = mp_min_element, mp_less>; 215 | 216 | // mp_max 217 | template using mp_max = mp_max_element, mp_less>; 218 | 219 | } // namespace mp11 220 | } // namespace boost 221 | 222 | #endif // #ifndef BOOST_MP11_FUNCTION_HPP_INCLUDED 223 | -------------------------------------------------------------------------------- /doc/gdbf_profiling.c: -------------------------------------------------------------------------------- 1 | // ------------- Configuration ------------- 2 | #define GDBF_PROFILING_BUFFER_BYTES (64 * 1024 * 1024) 3 | #define GDBF_PROFILING_CLOCK CLOCK_MONOTONIC 4 | // #define GDBF_PROFILING_CLOCK CLOCK_THREAD_CPUTIME_ID 5 | // ----------------------------------------- 6 | 7 | /* 8 | ------------------------------------------------------------------------------ 9 | This file is available under 2 licenses -- choose whichever you prefer. 10 | ------------------------------------------------------------------------------ 11 | ALTERNATIVE A - MIT License 12 | Copyright (c) 2021 nakst 13 | Permission is hereby granted, free of charge, to any person obtaining a copy of 14 | this software and associated documentation files (the "Software"), to deal in 15 | the Software without restriction, including without limitation the rights to 16 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 17 | of the Software, and to permit persons to whom the Software is furnished to do 18 | so, subject to the following conditions: 19 | The above copyright notice and this permission notice shall be included in all 20 | copies or substantial portions of the Software. 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | SOFTWARE. 28 | ------------------------------------------------------------------------------ 29 | ALTERNATIVE B - Public Domain (www.unlicense.org) 30 | This is free and unencumbered software released into the public domain. 31 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 32 | software, either in source code form or as a compiled binary, for any purpose, 33 | commercial or non-commercial, and by any means. 34 | In jurisdictions that recognize copyright laws, the author or authors of this 35 | software dedicate any and all copyright interest in the software to the public 36 | domain. We make this dedication for the benefit of the public at large and to 37 | the detriment of our heirs and successors. We intend this dedication to be an 38 | overt act of relinquishment in perpetuity of all present and future rights to 39 | this software under copyright law. 40 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 41 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 42 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 43 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 44 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 45 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 46 | ------------------------------------------------------------------------------ 47 | */ 48 | 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | #ifdef __cplusplus 57 | #define GDBF_PROFILING_EXTERN extern "C" 58 | #else 59 | #define GDBF_PROFILING_EXTERN 60 | #endif 61 | 62 | typedef struct GdbfProfilingEntry { 63 | void* thisFunction; 64 | uint64_t timeStamp; 65 | } GdbfProfilingEntry; 66 | 67 | static __thread bool gdbfProfilingEnabledOnThisThread; 68 | static bool gdbfProfilingEnabled; 69 | static size_t gdbfProfilingBufferSize; 70 | GdbfProfilingEntry* gdbfProfilingBuffer; 71 | uintptr_t gdbfProfilingBufferPosition; 72 | uint64_t gdbfProfilingTicksPerMs; 73 | 74 | #define GDBF_PROFILING_FUNCTION(_exiting) \ 75 | (void)callSite; \ 76 | \ 77 | if (gdbfProfilingBufferPosition < gdbfProfilingBufferSize && gdbfProfilingEnabledOnThisThread) { \ 78 | GdbfProfilingEntry* entry = (GdbfProfilingEntry*)&gdbfProfilingBuffer[gdbfProfilingBufferPosition++]; \ 79 | entry->thisFunction = thisFunction; \ 80 | struct timespec time; \ 81 | clock_gettime(GDBF_PROFILING_CLOCK, &time); \ 82 | entry->timeStamp = ((uint64_t)time.tv_sec * 1000000000 + time.tv_nsec) | ((uint64_t)_exiting << 63); \ 83 | } 84 | 85 | GDBF_PROFILING_EXTERN __attribute__((no_instrument_function)) void __cyg_profile_func_enter(void* thisFunction, 86 | void* callSite) { 87 | GDBF_PROFILING_FUNCTION(0); 88 | } 89 | 90 | GDBF_PROFILING_EXTERN __attribute__((no_instrument_function)) void __cyg_profile_func_exit(void* thisFunction, 91 | void* callSite) { 92 | GDBF_PROFILING_FUNCTION(1); 93 | } 94 | 95 | GDBF_PROFILING_EXTERN __attribute__((no_instrument_function)) void GdbfProfilingStart() { 96 | assert(!gdbfProfilingEnabled); 97 | assert(!gdbfProfilingEnabledOnThisThread); 98 | assert(gdbfProfilingBufferSize); 99 | gdbfProfilingEnabled = true; 100 | gdbfProfilingEnabledOnThisThread = true; 101 | gdbfProfilingBufferPosition = 0; 102 | } 103 | 104 | GDBF_PROFILING_EXTERN __attribute__((no_instrument_function)) void GdbfProfilingStop() { 105 | assert(gdbfProfilingEnabled); 106 | assert(gdbfProfilingEnabledOnThisThread); 107 | gdbfProfilingEnabled = false; 108 | gdbfProfilingEnabledOnThisThread = false; 109 | } 110 | 111 | __attribute__((constructor)) __attribute__((no_instrument_function)) void GdbfProfilingInitialise() { 112 | gdbfProfilingBufferSize = GDBF_PROFILING_BUFFER_BYTES / sizeof(GdbfProfilingEntry); 113 | gdbfProfilingBuffer = (GdbfProfilingEntry*)malloc(GDBF_PROFILING_BUFFER_BYTES); 114 | gdbfProfilingTicksPerMs = 1000000; 115 | assert(gdbfProfilingBufferSize && gdbfProfilingBuffer); 116 | } 117 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/detail/mp_fold.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_DETAIL_MP_FOLD_HPP_INCLUDED 2 | #define BOOST_MP11_DETAIL_MP_FOLD_HPP_INCLUDED 3 | 4 | // Copyright 2015-2017 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace boost 17 | { 18 | namespace mp11 19 | { 20 | 21 | // mp_fold 22 | namespace detail 23 | { 24 | 25 | template class F> struct mp_fold_impl 26 | { 27 | // An error "no type named 'type'" here means that the first argument to mp_fold is not a list 28 | }; 29 | 30 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, <= 1800 ) 31 | 32 | template class L, class... T, class V, template class F> struct mp_fold_impl, V, F> 33 | { 34 | static_assert( sizeof...(T) == 0, "T... must be empty" ); 35 | using type = V; 36 | }; 37 | 38 | #else 39 | 40 | template class L, class V, template class F> struct mp_fold_impl, V, F> 41 | { 42 | using type = V; 43 | }; 44 | 45 | #endif 46 | 47 | // 48 | 49 | template class F> struct mp_fold_Q1 50 | { 51 | template 52 | using fn = F; 53 | }; 54 | 55 | template class F> struct mp_fold_Q2 56 | { 57 | template 58 | using fn = F, T2>; 59 | }; 60 | 61 | template class F> struct mp_fold_Q3 62 | { 63 | template 64 | using fn = F, T2>, T3>; 65 | }; 66 | 67 | template class F> struct mp_fold_Q4 68 | { 69 | template 70 | using fn = F, T2>, T3>, T4>; 71 | }; 72 | 73 | template class F> struct mp_fold_Q5 74 | { 75 | template 76 | using fn = F, T2>, T3>, T4>, T5>; 77 | }; 78 | 79 | template class F> struct mp_fold_Q6 80 | { 81 | template 82 | using fn = F, T2>, T3>, T4>, T5>, T6>; 83 | }; 84 | 85 | template class F> struct mp_fold_Q7 86 | { 87 | template 88 | using fn = F, T2>, T3>, T4>, T5>, T6>, T7>; 89 | }; 90 | 91 | template class F> struct mp_fold_Q8 92 | { 93 | template 94 | using fn = F, T2>, T3>, T4>, T5>, T6>, T7>, T8>; 95 | }; 96 | 97 | template class F> struct mp_fold_Q9 98 | { 99 | template 100 | using fn = F, T2>, T3>, T4>, T5>, T6>, T7>, T8>, T9>; 101 | }; 102 | 103 | // 104 | 105 | template class L, class T1, class V, template class F> 106 | struct mp_fold_impl, V, F>: mp_defer::template fn, T1> 107 | { 108 | }; 109 | 110 | template class L, class T1, class T2, class V, template class F> 111 | struct mp_fold_impl, V, F>: mp_defer::template fn, T1, T2> 112 | { 113 | }; 114 | 115 | template class L, class T1, class T2, class T3, class V, template class F> 116 | struct mp_fold_impl, V, F>: mp_defer::template fn, T1, T2, T3> 117 | { 118 | }; 119 | 120 | template class L, class T1, class T2, class T3, class T4, class V, template class F> 121 | struct mp_fold_impl, V, F>: mp_defer::template fn, T1, T2, T3, T4> 122 | { 123 | }; 124 | 125 | template class L, class T1, class T2, class T3, class T4, class T5, class V, template class F> 126 | struct mp_fold_impl, V, F>: mp_defer::template fn, T1, T2, T3, T4, T5> 127 | { 128 | }; 129 | 130 | template class L, class T1, class T2, class T3, class T4, class T5, class T6, class V, template class F> 131 | struct mp_fold_impl, V, F>: mp_defer::template fn, T1, T2, T3, T4, T5, T6> 132 | { 133 | }; 134 | 135 | template class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class V, template class F> 136 | struct mp_fold_impl, V, F>: mp_defer::template fn, T1, T2, T3, T4, T5, T6, T7> 137 | { 138 | }; 139 | 140 | template class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class V, template class F> 141 | struct mp_fold_impl, V, F>: mp_defer::template fn, T1, T2, T3, T4, T5, T6, T7, T8> 142 | { 143 | }; 144 | 145 | template class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class V, template class F> 146 | struct mp_fold_impl, V, F>: mp_defer::template fn, T1, T2, T3, T4, T5, T6, T7, T8, T9> 147 | { 148 | }; 149 | 150 | // 151 | 152 | template class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class... T, class V, template class F> 153 | struct mp_fold_impl, V, F> 154 | { 155 | using type = typename mp_fold_impl, F, T2>, T3>, T4>, T5>, T6>, T7>, T8>, T9>, T10>, F>::type; 156 | }; 157 | 158 | } // namespace detail 159 | 160 | template class F> using mp_fold = typename detail::mp_fold_impl, V, F>::type; 161 | template using mp_fold_q = mp_fold; 162 | 163 | } // namespace mp11 164 | } // namespace boost 165 | 166 | #endif // #ifndef BOOST_MP11_DETAIL_MP_FOLD_HPP_INCLUDED 167 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ## 2 | ## Example of use: 3 | ## cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++-18 -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -GNinja .. 4 | ## 5 | ## Build with `libc++` 6 | ## cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++-20 -DCMAKE_C_COMPILER=clang-20 -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++ -lc++abi" -GNinja .. 7 | ## 8 | ## ---------------------------------------------------------------------------------- 9 | 10 | cmake_minimum_required(VERSION 3.24...4.0) 11 | 12 | # Extract version from gf.hpp 13 | file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/src/gf.hpp" GDBF_VERSION_MAJOR_LINE REGEX "^#define GDBF_VERSION_MAJOR ") 14 | file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/src/gf.hpp" GDBF_VERSION_MINOR_LINE REGEX "^#define GDBF_VERSION_MINOR ") 15 | file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/src/gf.hpp" GDBF_VERSION_PATCH_LINE REGEX "^#define GDBF_VERSION_PATCH ") 16 | 17 | string(REGEX REPLACE "^#define GDBF_VERSION_MAJOR[ \t]+([0-9]+).*$" "\\1" GDBF_VERSION_MAJOR "${GDBF_VERSION_MAJOR_LINE}") 18 | string(REGEX REPLACE "^#define GDBF_VERSION_MINOR[ \t]+([0-9]+).*$" "\\1" GDBF_VERSION_MINOR "${GDBF_VERSION_MINOR_LINE}") 19 | string(REGEX REPLACE "^#define GDBF_VERSION_PATCH[ \t]+([0-9]+).*$" "\\1" GDBF_VERSION_PATCH "${GDBF_VERSION_PATCH_LINE}") 20 | set(DETECTED_GDBF_VERSION "${GDBF_VERSION_MAJOR}.${GDBF_VERSION_MINOR}.${GDBF_VERSION_PATCH}") 21 | 22 | project(gdbf VERSION ${DETECTED_GDBF_VERSION} LANGUAGES CXX) 23 | 24 | set(CMAKE_CXX_STANDARD 23) 25 | set(CMAKE_CXX_EXTENSIONS OFF) 26 | set(CXX_STANDARD_REQUIRED ON) 27 | 28 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 29 | 30 | ## ------------------------------------------------------------------------------------ 31 | ## Required packages 32 | ## ------------------------------------------------------------------------------------ 33 | if(APPLE) 34 | set(X11_ROOT "/opt/X11") # Hint to CMake where XQuartz is installed 35 | set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${X11_ROOT}) 36 | endif() 37 | 38 | if (NOT MSVC) 39 | find_package(Freetype REQUIRED) 40 | find_package(X11 REQUIRED) 41 | find_package(Threads REQUIRED) 42 | endif() 43 | 44 | ## ------------------------------------------------------------------------------------ 45 | ## Compiler options 46 | ## ------------------------------------------------------------------------------------ 47 | if(NOT MSVC) 48 | add_compile_options(-Wall -Wextra -Wdisabled-optimization -Winit-self -Wmissing-include-dirs -Wswitch-default 49 | -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers 50 | -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion 51 | -Wno-gnu-conditional-omitted-operand) 52 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 53 | add_compile_options(-Wlogical-op -Wstrict-null-sentinel) 54 | else() 55 | add_compile_options(-pedantic) 56 | endif() 57 | else() 58 | add_compile_options(/W4 /Zc:__cplusplus) 59 | endif() 60 | 61 | ## ------------------------------------------------------------------------------------ 62 | ## luigi 63 | ## ------------------------------------------------------------------------------------ 64 | add_library(luigi STATIC src/luigi.cpp) 65 | set_property(TARGET luigi PROPERTY PUBLIC_HEADER src/luigi.hpp) 66 | 67 | if (NOT MSVC) 68 | target_link_libraries(luigi ${FREETYPE_LIBRARIES} ${X11_LIBRARIES}) 69 | target_include_directories(luigi PUBLIC ${FREETYPE_INCLUDE_DIRS} ${X11_INCLUDE_DIR}) 70 | target_compile_options(luigi PUBLIC -DUI_FREETYPE -DUI_FREETYPE_SUBPIXEL) 71 | endif() 72 | 73 | ## ------------------------------------------------------------------------------------ 74 | ## gdbf 75 | ## ------------------------------------------------------------------------------------ 76 | if (NOT MSVC) 77 | add_executable(${PROJECT_NAME} WIN32 src/gf.cpp src/main.cpp src/re/cpp.cpp src/re/gdb.cpp) 78 | 79 | ## dmalloc: link with `-ldmalloc` and run command: `dmalloc -l logfile -i 100 high` 80 | 81 | target_include_directories(${PROJECT_NAME} PRIVATE src deps/include ) 82 | target_link_libraries(${PROJECT_NAME} luigi Threads::Threads) 83 | target_compile_definitions(${PROJECT_NAME} PRIVATE GDBF_VERSION_STRING="${PROJECT_VERSION}") 84 | endif () 85 | 86 | 87 | ## ------------------------------------------------------------------------------------ 88 | ## Sanitizers 89 | ## ---------- 90 | ## set break at: __sanitizer::Die() 91 | ## ------------------------------------------------------------------------------------ 92 | option(ENABLE_SANITIZERS "Build with sanitizers enabled" OFF) 93 | option(ENABLE_ADDRESS_SANITIZER "Build with address sanitizers enabled" OFF) 94 | 95 | if (ENABLE_SANITIZERS OR ENABLE_ADDRESS_SANITIZER) 96 | if (ENABLE_ADDRESS_SANITIZER) 97 | message( STATUS "Configuring address sanitizer" ) 98 | set(clang_san_options -g -fsanitize=address -fno-omit-frame-pointer) 99 | # use: address, leak, memory, thread, undefined 100 | else() 101 | message( STATUS "Configuring other sanitizers" ) 102 | set(clang_san_options -g -fsanitize=undefined -fno-sanitize-recover=all -fsanitize=float-divide-by-zero 103 | -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -fPIE 104 | -fno-omit-frame-pointer -fsanitize-ignorelist=${CMAKE_SOURCE_DIR}/san_ignore_list.txt) 105 | endif() 106 | 107 | target_compile_options(luigi PUBLIC ${clang_san_options} ) 108 | target_link_options( luigi PUBLIC ${clang_san_options} ) 109 | 110 | target_compile_options(${PROJECT_NAME} PUBLIC ${clang_san_options} ) 111 | target_link_options( ${PROJECT_NAME} PUBLIC ${clang_san_options} ) 112 | 113 | endif() 114 | 115 | 116 | ## ------------------------------------------------------------------------------------ 117 | ## Subdirectories 118 | ## ------------------------------------------------------------------------------------ 119 | if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples/CMakeLists.txt") 120 | add_subdirectory(examples) 121 | endif() 122 | 123 | if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt") 124 | add_subdirectory(tests) 125 | endif() -------------------------------------------------------------------------------- /deps/include/boost/mp11/set.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_SET_HPP_INCLUDED 2 | #define BOOST_MP11_SET_HPP_INCLUDED 3 | 4 | // Copyright 2015, 2019, 2024 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | namespace boost 23 | { 24 | namespace mp11 25 | { 26 | 27 | // mp_set_contains 28 | namespace detail 29 | { 30 | 31 | template struct mp_set_contains_impl 32 | { 33 | }; 34 | 35 | template class L, class... T, class V> struct mp_set_contains_impl, V> 36 | { 37 | using type = mp_to_bool, mp_inherit...> > >; 38 | }; 39 | 40 | } // namespace detail 41 | 42 | template using mp_set_contains = typename detail::mp_set_contains_impl::type; 43 | 44 | // mp_set_push_back 45 | namespace detail 46 | { 47 | 48 | template struct mp_set_push_back_impl 49 | { 50 | }; 51 | 52 | template class L, class... U> struct mp_set_push_back_impl> 53 | { 54 | using type = L; 55 | }; 56 | 57 | template class L, class... U, class T1, class... T> struct mp_set_push_back_impl, T1, T...> 58 | { 59 | using S = mp_if, T1>, L, L>; 60 | using type = typename mp_set_push_back_impl::type; 61 | }; 62 | 63 | } // namespace detail 64 | 65 | template using mp_set_push_back = typename detail::mp_set_push_back_impl::type; 66 | 67 | // mp_set_push_front 68 | namespace detail 69 | { 70 | 71 | template struct mp_set_push_front_impl 72 | { 73 | }; 74 | 75 | template class L, class... U> struct mp_set_push_front_impl> 76 | { 77 | using type = L; 78 | }; 79 | 80 | template class L, class... U, class T1> struct mp_set_push_front_impl, T1> 81 | { 82 | using type = mp_if, T1>, L, L>; 83 | }; 84 | 85 | template class L, class... U, class T1, class... T> struct mp_set_push_front_impl, T1, T...> 86 | { 87 | using S = typename mp_set_push_front_impl, T...>::type; 88 | using type = typename mp_set_push_front_impl::type; 89 | }; 90 | 91 | } // namespace detail 92 | 93 | template using mp_set_push_front = typename detail::mp_set_push_front_impl::type; 94 | 95 | // mp_is_set 96 | namespace detail 97 | { 98 | 99 | #if !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1900 ) 100 | 101 | struct mp_is_set_helper_start 102 | { 103 | static constexpr bool value = true; 104 | template static mp_false contains( T ); 105 | }; 106 | 107 | template 108 | struct mp_is_set_helper: Base 109 | { 110 | static constexpr bool value = Base::value && !decltype( Base::contains( mp_identity{} ) )::value; 111 | using Base::contains; 112 | static mp_true contains( mp_identity ); 113 | }; 114 | 115 | template struct mp_is_set_impl 116 | { 117 | using type = mp_false; 118 | }; 119 | 120 | template class L, class... T> struct mp_is_set_impl> 121 | { 122 | using type = mp_bool, detail::mp_is_set_helper_start, detail::mp_is_set_helper>::value>; 123 | }; 124 | 125 | #else 126 | 127 | template struct mp_is_set_impl 128 | { 129 | using type = mp_false; 130 | }; 131 | 132 | template class L, class... T> struct mp_is_set_impl> 133 | { 134 | using type = mp_to_bool, mp_set_push_back, T...> > >; 135 | }; 136 | 137 | #endif // !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1900 ) 138 | 139 | } // namespace detail 140 | 141 | template using mp_is_set = typename detail::mp_is_set_impl::type; 142 | 143 | // mp_set_union 144 | namespace detail 145 | { 146 | 147 | template struct mp_set_union_impl 148 | { 149 | }; 150 | 151 | template<> struct mp_set_union_impl<> 152 | { 153 | using type = mp_list<>; 154 | }; 155 | 156 | template class L, class... T> struct mp_set_union_impl> 157 | { 158 | using type = L; 159 | }; 160 | 161 | template class L1, class... T1, template class L2, class... T2> struct mp_set_union_impl, L2> 162 | { 163 | using type = mp_set_push_back, T2...>; 164 | }; 165 | 166 | template using mp_set_union_ = typename mp_set_union_impl, L...>>::type; 167 | 168 | template struct mp_set_union_impl: mp_defer 169 | { 170 | }; 171 | 172 | } // namespace detail 173 | 174 | template using mp_set_union = typename detail::mp_set_union_impl::type; 175 | 176 | // mp_set_intersection 177 | namespace detail 178 | { 179 | 180 | template struct in_all_sets 181 | { 182 | template using fn = mp_all< mp_set_contains... >; 183 | }; 184 | 185 | template using mp_set_intersection_ = mp_if< mp_all...>, mp_copy_if_q> >; 186 | 187 | template struct mp_set_intersection_impl 188 | { 189 | }; 190 | 191 | template<> struct mp_set_intersection_impl<> 192 | { 193 | using type = mp_list<>; 194 | }; 195 | 196 | template struct mp_set_intersection_impl: mp_defer 197 | { 198 | }; 199 | 200 | } // namespace detail 201 | 202 | template using mp_set_intersection = typename detail::mp_set_intersection_impl::type; 203 | 204 | // mp_set_difference 205 | namespace detail 206 | { 207 | 208 | template struct in_any_set 209 | { 210 | template using fn = mp_any< mp_set_contains... >; 211 | }; 212 | 213 | } // namespace detail 214 | 215 | template using mp_set_difference = mp_if< mp_all...>, mp_remove_if_q> >; 216 | 217 | } // namespace mp11 218 | } // namespace boost 219 | 220 | #endif // #ifndef BOOST_MP11_SET_HPP_INCLUDED 221 | -------------------------------------------------------------------------------- /deps/include/boost/mp11/tuple.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_TUPLE_HPP_INCLUDED 2 | #define BOOST_MP11_TUPLE_HPP_INCLUDED 3 | 4 | // Copyright 2015-2020 Peter Dimov. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #if BOOST_MP11_MSVC 21 | # pragma warning( push ) 22 | # pragma warning( disable: 4100 ) // unreferenced formal parameter 'tp' 23 | #endif 24 | 25 | namespace boost 26 | { 27 | namespace mp11 28 | { 29 | 30 | // tuple_apply 31 | namespace detail 32 | { 33 | 34 | using std::get; 35 | 36 | template BOOST_MP11_CONSTEXPR auto tuple_apply_impl( F && f, Tp && tp, integer_sequence ) 37 | -> decltype( std::forward(f)( get(std::forward(tp))... ) ) 38 | { 39 | return std::forward(f)( get(std::forward(tp))... ); 40 | } 41 | 42 | } // namespace detail 43 | 44 | template::type>::value>> 46 | BOOST_MP11_CONSTEXPR auto tuple_apply( F && f, Tp && tp ) 47 | -> decltype( detail::tuple_apply_impl( std::forward(f), std::forward(tp), Seq() ) ) 48 | { 49 | return detail::tuple_apply_impl( std::forward(f), std::forward(tp), Seq() ); 50 | } 51 | 52 | // construct_from_tuple 53 | namespace detail 54 | { 55 | 56 | template BOOST_MP11_CONSTEXPR T construct_from_tuple_impl( Tp && tp, integer_sequence ) 57 | { 58 | return T( get(std::forward(tp))... ); 59 | } 60 | 61 | } // namespace detail 62 | 63 | template::type>::value>> 65 | BOOST_MP11_CONSTEXPR T construct_from_tuple( Tp && tp ) 66 | { 67 | return detail::construct_from_tuple_impl( std::forward(tp), Seq() ); 68 | } 69 | 70 | // tuple_for_each 71 | namespace detail 72 | { 73 | 74 | template BOOST_MP11_CONSTEXPR F tuple_for_each_impl( Tp && tp, integer_sequence, F && f ) 75 | { 76 | using A = int[sizeof...(J)]; 77 | return (void)A{ ((void)f(get(std::forward(tp))), 0)... }, std::forward(f); 78 | } 79 | 80 | template BOOST_MP11_CONSTEXPR F tuple_for_each_impl( Tp && /*tp*/, integer_sequence, F && f ) 81 | { 82 | return std::forward(f); 83 | } 84 | 85 | } // namespace detail 86 | 87 | template BOOST_MP11_CONSTEXPR F tuple_for_each( Tp && tp, F && f ) 88 | { 89 | using seq = make_index_sequence::type>::value>; 90 | return detail::tuple_for_each_impl( std::forward(tp), seq(), std::forward(f) ); 91 | } 92 | 93 | // tuple_transform 94 | 95 | namespace detail 96 | { 97 | 98 | // std::forward_as_tuple is not constexpr in C++11 or libstdc++ 5.x 99 | template BOOST_MP11_CONSTEXPR auto tp_forward_r( T&&... t ) -> std::tuple 100 | { 101 | return std::tuple( std::forward( t )... ); 102 | } 103 | 104 | template BOOST_MP11_CONSTEXPR auto tp_forward_v( T&&... t ) -> std::tuple 105 | { 106 | return std::tuple( std::forward( t )... ); 107 | } 108 | 109 | template 110 | BOOST_MP11_CONSTEXPR auto tp_extract( Tp&&... tp ) 111 | -> decltype( tp_forward_r( get( std::forward( tp ) )... ) ) 112 | { 113 | return tp_forward_r( get( std::forward( tp ) )... ); 114 | } 115 | 116 | #if !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1900 ) 117 | 118 | template 119 | BOOST_MP11_CONSTEXPR auto tuple_transform_impl( integer_sequence, F const& f, Tp&&... tp ) 120 | -> decltype( tp_forward_v( tuple_apply( f, tp_extract( std::forward(tp)... ) )... ) ) 121 | { 122 | return tp_forward_v( tuple_apply( f, tp_extract( std::forward(tp)... ) )... ); 123 | } 124 | 125 | #else 126 | 127 | template 128 | BOOST_MP11_CONSTEXPR auto tuple_transform_impl( integer_sequence, F const& f, Tp1&& tp1 ) 129 | -> decltype( tp_forward_v( f( get( std::forward(tp1) ) )... ) ) 130 | { 131 | return tp_forward_v( f( get( std::forward(tp1) ) )... ); 132 | } 133 | 134 | template 135 | BOOST_MP11_CONSTEXPR auto tuple_transform_impl( integer_sequence, F const& f, Tp1&& tp1, Tp2&& tp2 ) 136 | -> decltype( tp_forward_v( f( get( std::forward(tp1) ), get( std::forward(tp2) ) )... ) ) 137 | { 138 | return tp_forward_v( f( get( std::forward(tp1) ), get( std::forward(tp2) ) )... ); 139 | } 140 | 141 | template 142 | BOOST_MP11_CONSTEXPR auto tuple_transform_impl( integer_sequence, F const& f, Tp1&& tp1, Tp2&& tp2, Tp3&& tp3 ) 143 | -> decltype( tp_forward_v( f( get( std::forward(tp1) ), get( std::forward(tp2) ), get( std::forward(tp3) ) )... ) ) 144 | { 145 | return tp_forward_v( f( get( std::forward(tp1) ), get( std::forward(tp2) ), get( std::forward(tp3) ) )... ); 146 | } 147 | 148 | #endif // !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1900 ) 149 | 150 | } // namespace detail 151 | 152 | #if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1910 ) 153 | 154 | template::type>::value>> 156 | BOOST_MP11_CONSTEXPR auto tuple_transform( F const& f, Tp1&& tp1, Tp&&... tp ) 157 | -> decltype( detail::tuple_transform_impl( Seq(), f, std::forward(tp1), std::forward(tp)... ) ) 158 | { 159 | return detail::tuple_transform_impl( Seq(), f, std::forward(tp1), std::forward(tp)... ); 160 | } 161 | 162 | #else 163 | 164 | template::type>::value>...>, 166 | class E = mp_if, mp_front>, 167 | class Seq = make_index_sequence> 168 | BOOST_MP11_CONSTEXPR auto tuple_transform( F const& f, Tp&&... tp ) 169 | -> decltype( detail::tuple_transform_impl( Seq(), f, std::forward(tp)... ) ) 170 | { 171 | return detail::tuple_transform_impl( Seq(), f, std::forward(tp)... ); 172 | } 173 | 174 | #endif // BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1910 ) 175 | 176 | } // namespace mp11 177 | } // namespace boost 178 | 179 | #if BOOST_MP11_MSVC 180 | # pragma warning( pop ) 181 | #endif 182 | 183 | #endif // #ifndef BOOST_TUPLE_HPP_INCLUDED 184 | -------------------------------------------------------------------------------- /deps/include/nlohmann/json_fwd.hpp: -------------------------------------------------------------------------------- 1 | // __ _____ _____ _____ 2 | // __| | __| | | | JSON for Modern C++ 3 | // | | |__ | | | | | | version 3.12.0 4 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 | // 6 | // SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann 7 | // SPDX-License-Identifier: MIT 8 | 9 | #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ 10 | #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ 11 | 12 | #include // int64_t, uint64_t 13 | #include // map 14 | #include // allocator 15 | #include // string 16 | #include // vector 17 | 18 | // #include 19 | // __ _____ _____ _____ 20 | // __| | __| | | | JSON for Modern C++ 21 | // | | |__ | | | | | | version 3.12.0 22 | // |_____|_____|_____|_|___| https://github.com/nlohmann/json 23 | // 24 | // SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann 25 | // SPDX-License-Identifier: MIT 26 | 27 | 28 | 29 | // This file contains all macro definitions affecting or depending on the ABI 30 | 31 | #ifndef JSON_SKIP_LIBRARY_VERSION_CHECK 32 | #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) 33 | #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 12 || NLOHMANN_JSON_VERSION_PATCH != 0 34 | #warning "Already included a different version of the library!" 35 | #endif 36 | #endif 37 | #endif 38 | 39 | #define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) 40 | #define NLOHMANN_JSON_VERSION_MINOR 12 // NOLINT(modernize-macro-to-enum) 41 | #define NLOHMANN_JSON_VERSION_PATCH 0 // NOLINT(modernize-macro-to-enum) 42 | 43 | #ifndef JSON_DIAGNOSTICS 44 | #define JSON_DIAGNOSTICS 0 45 | #endif 46 | 47 | #ifndef JSON_DIAGNOSTIC_POSITIONS 48 | #define JSON_DIAGNOSTIC_POSITIONS 0 49 | #endif 50 | 51 | #ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 52 | #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 53 | #endif 54 | 55 | #if JSON_DIAGNOSTICS 56 | #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag 57 | #else 58 | #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS 59 | #endif 60 | 61 | #if JSON_DIAGNOSTIC_POSITIONS 62 | #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp 63 | #else 64 | #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS 65 | #endif 66 | 67 | #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 68 | #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp 69 | #else 70 | #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON 71 | #endif 72 | 73 | #ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION 74 | #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 75 | #endif 76 | 77 | // Construct the namespace ABI tags component 78 | #define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c 79 | #define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \ 80 | NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) 81 | 82 | #define NLOHMANN_JSON_ABI_TAGS \ 83 | NLOHMANN_JSON_ABI_TAGS_CONCAT( \ 84 | NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ 85 | NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \ 86 | NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS) 87 | 88 | // Construct the namespace version component 89 | #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ 90 | _v ## major ## _ ## minor ## _ ## patch 91 | #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ 92 | NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) 93 | 94 | #if NLOHMANN_JSON_NAMESPACE_NO_VERSION 95 | #define NLOHMANN_JSON_NAMESPACE_VERSION 96 | #else 97 | #define NLOHMANN_JSON_NAMESPACE_VERSION \ 98 | NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ 99 | NLOHMANN_JSON_VERSION_MINOR, \ 100 | NLOHMANN_JSON_VERSION_PATCH) 101 | #endif 102 | 103 | // Combine namespace components 104 | #define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b 105 | #define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ 106 | NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) 107 | 108 | #ifndef NLOHMANN_JSON_NAMESPACE 109 | #define NLOHMANN_JSON_NAMESPACE \ 110 | nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ 111 | NLOHMANN_JSON_ABI_TAGS, \ 112 | NLOHMANN_JSON_NAMESPACE_VERSION) 113 | #endif 114 | 115 | #ifndef NLOHMANN_JSON_NAMESPACE_BEGIN 116 | #define NLOHMANN_JSON_NAMESPACE_BEGIN \ 117 | namespace nlohmann \ 118 | { \ 119 | inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ 120 | NLOHMANN_JSON_ABI_TAGS, \ 121 | NLOHMANN_JSON_NAMESPACE_VERSION) \ 122 | { 123 | #endif 124 | 125 | #ifndef NLOHMANN_JSON_NAMESPACE_END 126 | #define NLOHMANN_JSON_NAMESPACE_END \ 127 | } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ 128 | } // namespace nlohmann 129 | #endif 130 | 131 | 132 | /*! 133 | @brief namespace for Niels Lohmann 134 | @see https://github.com/nlohmann 135 | @since version 1.0.0 136 | */ 137 | NLOHMANN_JSON_NAMESPACE_BEGIN 138 | 139 | /*! 140 | @brief default JSONSerializer template argument 141 | 142 | This serializer ignores the template arguments and uses ADL 143 | ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) 144 | for serialization. 145 | */ 146 | template 147 | struct adl_serializer; 148 | 149 | /// a class to store JSON values 150 | /// @sa https://json.nlohmann.me/api/basic_json/ 151 | template class ObjectType = 152 | std::map, 153 | template class ArrayType = std::vector, 154 | class StringType = std::string, class BooleanType = bool, 155 | class NumberIntegerType = std::int64_t, 156 | class NumberUnsignedType = std::uint64_t, 157 | class NumberFloatType = double, 158 | template class AllocatorType = std::allocator, 159 | template class JSONSerializer = 160 | adl_serializer, 161 | class BinaryType = std::vector, // cppcheck-suppress syntaxError 162 | class CustomBaseClass = void> 163 | class basic_json; 164 | 165 | /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document 166 | /// @sa https://json.nlohmann.me/api/json_pointer/ 167 | template 168 | class json_pointer; 169 | 170 | /*! 171 | @brief default specialization 172 | @sa https://json.nlohmann.me/api/json/ 173 | */ 174 | using json = basic_json<>; 175 | 176 | /// @brief a minimal map-like container that preserves insertion order 177 | /// @sa https://json.nlohmann.me/api/ordered_map/ 178 | template 179 | struct ordered_map; 180 | 181 | /// @brief specialization that maintains the insertion order of object keys 182 | /// @sa https://json.nlohmann.me/api/ordered_json/ 183 | using ordered_json = basic_json; 184 | 185 | NLOHMANN_JSON_NAMESPACE_END 186 | 187 | #endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ 188 | -------------------------------------------------------------------------------- /examples/tinyraytracer.cpp: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------- 2 | // by @ssloy - see https://github.com/ssloy/tinyraytracer 3 | // released under [WTFPL](https://en.wikipedia.org/wiki/WTFPL) license 4 | // -------------------------------------------------------------------------------------- 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | struct vec3 { 12 | float x = 0, y = 0, z = 0; 13 | float& operator[](const int i) { return i == 0 ? x : (1 == i ? y : z); } 14 | const float& operator[](const int i) const { return i == 0 ? x : (1 == i ? y : z); } 15 | vec3 operator*(const float v) const { return {x * v, y * v, z * v}; } 16 | float operator*(const vec3& v) const { return x * v.x + y * v.y + z * v.z; } 17 | vec3 operator+(const vec3& v) const { return {x + v.x, y + v.y, z + v.z}; } 18 | vec3 operator-(const vec3& v) const { return {x - v.x, y - v.y, z - v.z}; } 19 | vec3 operator-() const { return {-x, -y, -z}; } 20 | float norm() const { return std::sqrt(x * x + y * y + z * z); } 21 | vec3 normalized() const { return (*this) * (1.f / norm()); } 22 | }; 23 | 24 | vec3 cross(const vec3 v1, const vec3 v2) { 25 | return {v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x}; 26 | } 27 | 28 | struct Material { 29 | float refractive_index = 1; 30 | float albedo[4] = {2, 0, 0, 0}; 31 | vec3 diffuse_color = {0, 0, 0}; 32 | float specular_exponent = 0; 33 | }; 34 | 35 | struct Sphere { 36 | vec3 center; 37 | float radius; 38 | Material material; 39 | }; 40 | 41 | constexpr Material ivory = { 42 | 1.0, 43 | {0.9, 0.5, 0.1, 0.0}, 44 | {0.4, 0.4, 0.3}, 45 | 50. 46 | }; 47 | constexpr Material glass = { 48 | 1.5, 49 | {0.0, 0.9, 0.1, 0.8}, 50 | {0.6, 0.7, 0.8}, 51 | 125. 52 | }; 53 | constexpr Material red_rubber = { 54 | 1.0, 55 | {1.4, 0.3, 0.0, 0.0}, 56 | {0.3, 0.1, 0.1}, 57 | 10. 58 | }; 59 | constexpr Material mirror = { 60 | 1.0, 61 | {0.0, 16.0, 0.8, 0.0}, 62 | {1.0, 1.0, 1.0}, 63 | 1425. 64 | }; 65 | 66 | constexpr Sphere spheres[] = { 67 | {{-3, 0, -16}, 2, ivory }, 68 | {{-1.0, -1.5, -12}, 2, glass }, 69 | {{1.5, -0.5, -18}, 3, red_rubber}, 70 | {{7, 5, -18}, 4, mirror } 71 | }; 72 | 73 | constexpr vec3 lights[] = { 74 | {-20, 20, 20 }, 75 | {30, 50, -25}, 76 | {30, 20, 30 } 77 | }; 78 | 79 | vec3 reflect(const vec3& I, const vec3& N) { return I - N * 2.f * (I * N); } 80 | 81 | vec3 refract(const vec3& I, const vec3& N, const float eta_t, const float eta_i = 1.f) { // Snell's law 82 | float cosi = -std::max(-1.f, std::min(1.f, I * N)); 83 | if (cosi < 0) 84 | return refract(I, -N, eta_i, eta_t); // if the ray comes from the inside the object, swap the air and the media 85 | float eta = eta_i / eta_t; 86 | float k = 1 - eta * eta * (1 - cosi * cosi); 87 | return k < 0 ? vec3{1, 0, 0} 88 | : I * eta + N * (eta * cosi - std::sqrt(k)); // k<0 = total reflection, no ray to refract. I refract it 89 | // anyways, this has no physical meaning 90 | } 91 | 92 | std::tuple ray_sphere_intersect(const vec3& orig, const vec3& dir, 93 | const Sphere& s) { // ret value is a pair [intersection found, distance] 94 | vec3 L = s.center - orig; 95 | float tca = L * dir; 96 | float d2 = L * L - tca * tca; 97 | if (d2 > s.radius * s.radius) 98 | return {false, 0}; 99 | float thc = std::sqrt(s.radius * s.radius - d2); 100 | float t0 = tca - thc, t1 = tca + thc; 101 | if (t0 > .001) 102 | return {true, t0}; // offset the original point by .001 to avoid occlusion by the object itself 103 | if (t1 > .001) 104 | return {true, t1}; 105 | return {false, 0}; 106 | } 107 | 108 | std::tuple scene_intersect(const vec3& orig, const vec3& dir) { 109 | vec3 pt, N; 110 | Material material; 111 | 112 | float nearest_dist = 1e10; 113 | if (std::abs(dir.y) > .001) { // intersect the ray with the checkerboard, avoid division by zero 114 | float d = -(orig.y + 4) / dir.y; // the checkerboard plane has equation y = -4 115 | vec3 p = orig + dir * d; 116 | if (d > .001 && d < nearest_dist && std::abs(p.x) < 10 && p.z < -10 && p.z > -30) { 117 | nearest_dist = d; 118 | pt = p; 119 | N = {0, 1, 0}; 120 | material.diffuse_color = (int(.5 * pt.x + 1000) + int(.5 * pt.z)) & 1 ? vec3{.3, .3, .3} : vec3{.3, .2, .1}; 121 | } 122 | } 123 | 124 | for (const Sphere& s : spheres) { // intersect the ray with all spheres 125 | auto [intersection, d] = ray_sphere_intersect(orig, dir, s); 126 | if (!intersection || d > nearest_dist) 127 | continue; 128 | nearest_dist = d; 129 | pt = orig + dir * nearest_dist; 130 | N = (pt - s.center).normalized(); 131 | material = s.material; 132 | } 133 | return {nearest_dist < 1000, pt, N, material}; 134 | } 135 | 136 | vec3 cast_ray(const vec3& orig, const vec3& dir, const int depth = 0) { 137 | auto [hit, point, N, material] = scene_intersect(orig, dir); 138 | if (depth > 4 || !hit) 139 | return {0.2, 0.7, 0.8}; // background color 140 | 141 | vec3 reflect_dir = reflect(dir, N).normalized(); 142 | vec3 refract_dir = refract(dir, N, material.refractive_index).normalized(); 143 | vec3 reflect_color = cast_ray(point, reflect_dir, depth + 1); 144 | vec3 refract_color = cast_ray(point, refract_dir, depth + 1); 145 | 146 | float diffuse_light_intensity = 0, specular_light_intensity = 0; 147 | for (const vec3& light : lights) { // checking if the point lies in the shadow of the light 148 | vec3 light_dir = (light - point).normalized(); 149 | auto [hit, shadow_pt, trashnrm, trashmat] = scene_intersect(point, light_dir); 150 | if (hit && (shadow_pt - point).norm() < (light - point).norm()) 151 | continue; 152 | diffuse_light_intensity += std::max(0.f, light_dir * N); 153 | specular_light_intensity += std::pow(std::max(0.f, -reflect(-light_dir, N) * dir), material.specular_exponent); 154 | } 155 | return material.diffuse_color * diffuse_light_intensity * material.albedo[0] + 156 | vec3{1., 1., 1.} * specular_light_intensity * material.albedo[1] + reflect_color * material.albedo[2] + 157 | refract_color * material.albedo[3]; 158 | } 159 | 160 | int main() { 161 | constexpr int width = 1024; 162 | constexpr int height = 768; 163 | constexpr float fov = 1.05; // 60 degrees field of view in radians 164 | std::vector framebuffer(width * height); 165 | //#pragma omp parallel for 166 | for (int pix = 0; pix < width * height; pix++) { // actual rendering loop 167 | float dir_x = (pix % width + 0.5) - width / 2.; 168 | float dir_y = -(pix / width + 0.5) + height / 2.; // this flips the image at the same time 169 | float dir_z = -height / (2. * tan(fov / 2.)); 170 | framebuffer[pix] = cast_ray(vec3{0, 0, 0}, vec3{dir_x, dir_y, dir_z}.normalized()); 171 | } 172 | 173 | std::ofstream ofs("./out.ppm", std::ios::binary); 174 | ofs << "P6\n" << width << " " << height << "\n255\n"; 175 | for (vec3& color : framebuffer) { 176 | float max = std::max(1.f, std::max(color[0], std::max(color[1], color[2]))); 177 | for (int chan : {0, 1, 2}) 178 | ofs << (char)(255 * color[chan] / max); 179 | } 180 | return 0; 181 | } 182 | -------------------------------------------------------------------------------- /doc/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to gdbf 2 | 3 | **[Getting Started](#getting-started)** • **[Project Structure](#project-structure)** • **[Testing](#testing)** • **[Code Style](#code-style)** • **[Architecture](#architecture-guidelines)** • **[Making Changes](#making-changes)** • **[Areas for Contribution](#areas-for-contribution)** • **[Getting Help](#getting-help)** 4 | 5 | --- 6 | 7 | Thank you for your interest in contributing to gdbf! This document provides guidelines and information for contributors. 8 | 9 | ## Getting Started 10 | 11 | gdbf is built with: 12 | - **Language**: C++23 (requires clang++-18 or g++-13 or higher) 13 | - **GUI Framework**: Custom [Luigi framework](luigi.md) 14 | - **Build System**: CMake + Ninja 15 | - **Platforms**: Linux (X11), Windows (Win32) 16 | 17 | ## Development Setup 18 | 19 | ### Building with Debug Symbols 20 | 21 | ```bash 22 | cmake -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++-18 -GNinja . 23 | cmake --build build 24 | ``` 25 | 26 | ### Building for Development 27 | 28 | ```bash 29 | # Enable compile_commands.json for clangd/IDE integration 30 | cmake -Bbuild \ 31 | -DCMAKE_BUILD_TYPE=Debug \ 32 | -DCMAKE_CXX_COMPILER=clang++-18 \ 33 | -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ 34 | -GNinja . 35 | 36 | cmake --build build 37 | ``` 38 | 39 | ## Project Structure 40 | 41 | ``` 42 | gdbf/ 43 | ├── src/ 44 | │ ├── gf.cpp, gf.hpp # Main debugger frontend 45 | │ ├── luigi.cpp, luigi.hpp # GUI framework 46 | │ └── re/ # Regular expression engine 47 | │ ├── re.hpp # Core regex using CTRE 48 | │ ├── cpp.cpp # C++ code parsing 49 | │ ├── gdb.cpp # GDB output parsing 50 | │ └── misc.cpp # Utility functions 51 | ├── examples/ 52 | │ └── luigi_example.cpp # Luigi GUI example 53 | ├── tests/ # Unit tests (doctest framework) 54 | │ ├── luigi_tests.cpp 55 | │ ├── re_cpp_tests.cpp 56 | │ └── re_gdb_tests.cpp 57 | ├── doc/ # Documentation 58 | │ ├── luigi.md # Luigi GUI documentation 59 | │ ├── plugins.md # Plugin system guide 60 | │ └── profiler_instructions.txt 61 | └── deps/ # Bundled dependencies 62 | ├── boost/ # Boost.Mp11 63 | ├── ctre/ # Compile-time regex 64 | ├── doctest/ # Testing framework 65 | └── nlohmann/ # JSON library 66 | ``` 67 | 68 | ## Testing 69 | 70 | ### Running Tests 71 | 72 | ```bash 73 | # Run all tests 74 | ./build/tests/luigi_tests 75 | ./build/tests/re_cpp_tests 76 | ./build/tests/re_gdb_tests 77 | ``` 78 | 79 | ### Writing Tests 80 | 81 | Tests use the [doctest](https://github.com/doctest/doctest) framework. Add tests to the appropriate file in `tests/`: 82 | 83 | ```cpp 84 | #include 85 | 86 | TEST_CASE("My feature works correctly") { 87 | // Arrange 88 | auto value = calculate_something(); 89 | 90 | // Assert 91 | CHECK(value == expected_value); 92 | } 93 | ``` 94 | 95 | ## Code Style 96 | 97 | ### General Guidelines 98 | 99 | - Use **spaces for indentation** (existing codebase style) 100 | - Braces on the same line: `if (condition) {` 101 | - Modern C++23 features are encouraged 102 | - Use `std::string_view` for string parameters when appropriate 103 | - Prefer `auto` for type deduction where it improves readability 104 | 105 | ### Example 106 | 107 | ```cpp 108 | void my_function(std::string_view name, int value) { 109 | if (value > 0) { 110 | auto result = process(name, value); 111 | // ... 112 | } 113 | } 114 | ``` 115 | 116 | ### Platform-Specific Code 117 | 118 | Isolate platform-specific code with preprocessor guards: 119 | 120 | ```cpp 121 | #ifdef UI_LINUX 122 | // Linux/X11 specific code 123 | #elif defined(UI_WINDOWS) 124 | // Windows specific code 125 | #endif 126 | ``` 127 | 128 | ## Architecture Guidelines 129 | 130 | ### GDB Communication 131 | 132 | All GDB communication must go through these functions: 133 | - `DebuggerSend()` - Send commands to GDB (src/gf.cpp) 134 | - `EvaluateExpression()` - Evaluate expressions in GDB context (src/gf.cpp) 135 | 136 | ### Window System 137 | 138 | Windows are registered in the `interfaceWindows` array with: 139 | - Create callback - Initialize window state 140 | - Update callback - Handle messages and render 141 | 142 | Example: 143 | 144 | ```cpp 145 | InterfaceWindow my_window = { 146 | .label = "My Window", 147 | .create = MyWindowCreate, 148 | .update = MyWindowUpdate, 149 | }; 150 | ``` 151 | 152 | ### Luigi UI Framework 153 | 154 | See [luigi.md](luigi.md) for complete documentation on: 155 | - Element hierarchy 156 | - Message system 157 | - Layout system 158 | - Event handling 159 | 160 | Key patterns: 161 | - Use method chaining for element creation 162 | - Call `refresh()` after state changes 163 | - Handle messages by returning `1` if processed 164 | 165 | ## Making Changes 166 | 167 | ### Before Submitting 168 | 169 | 1. **Build and test** - Ensure the code compiles and all tests pass 170 | 2. **Test manually** - Run gdbf and verify your changes work as expected 171 | 3. **Check for regressions** - Test existing functionality still works 172 | 4. **Follow code style** - Match the existing codebase style 173 | 174 | ### Commit Messages 175 | 176 | Write clear, concise commit messages: 177 | 178 | ``` 179 | Add support for custom breakpoint colors 180 | 181 | - Add color configuration to breakpoint struct 182 | - Update rendering code to use configured colors 183 | - Add INI configuration options for breakpoint colors 184 | ``` 185 | 186 | ### Pull Requests 187 | 188 | 1. Fork the repository 189 | 2. Create a feature branch (`git checkout -b feature/my-feature`) 190 | 3. Make your changes 191 | 4. Commit with clear messages 192 | 5. Push to your fork 193 | 6. Open a pull request with: 194 | - Clear description of changes 195 | - Motivation/use case 196 | - Testing performed 197 | - Screenshots (for UI changes) 198 | 199 | ## Areas for Contribution 200 | 201 | ### High Priority 202 | 203 | - **Documentation** - Improve user and developer documentation 204 | - **Bug fixes** - Check the issue tracker for reported bugs 205 | - **Testing** - Add tests for untested functionality 206 | - **Platform support** - Improve Windows support 207 | 208 | ### Feature Ideas 209 | 210 | - **New window types** - Add specialized debugging windows 211 | - **GDB integration** - Enhance GDB command support 212 | - **UI improvements** - Better themes, layout options 213 | - **Python hooks** - More watch window customization examples 214 | - **Editor integration** - Support for more editors beyond vim 215 | 216 | ### Luigi Framework 217 | 218 | The Luigi GUI framework is a core component and welcomes: 219 | - New UI elements 220 | - Performance improvements 221 | - Platform-specific enhancements 222 | - Documentation and examples 223 | 224 | See [luigi.md](luigi.md) and `examples/luigi_example.cpp` for details. 225 | 226 | ## Dependencies 227 | 228 | ### External (Must be installed) 229 | 230 | **Linux:** 231 | - X11 development libraries 232 | - FreeType development libraries 233 | - pthread 234 | 235 | **Windows:** 236 | - Native Win32 APIs (no external dependencies) 237 | 238 | ### Bundled (In deps/) 239 | 240 | - **Boost.Mp11** - Template metaprogramming 241 | - **CTRE** - Compile-time regular expressions 242 | - **doctest** - Testing framework 243 | - **nlohmann/json** - JSON parsing 244 | 245 | These are header-only or single-file libraries included directly. 246 | 247 | ## Debugging gdbf Itself 248 | 249 | ### Using GDB on gdbf 250 | 251 | ```bash 252 | # Build with debug symbols 253 | cmake -Bbuild -DCMAKE_BUILD_TYPE=Debug -GNinja . 254 | cmake --build build 255 | 256 | # Run under GDB 257 | gdb ./build/gdbf 258 | ``` 259 | 260 | ### Logging 261 | 262 | Add debug output to stderr: 263 | 264 | ```cpp 265 | std::print(stderr, "Debug: value = {}\n", value); 266 | ``` 267 | 268 | ### UI Debugging 269 | 270 | Set `UI_DEBUG` to `1` in `src/luigi.hpp`: 271 | 272 | ```cpp 273 | #define UI_DEBUG 1 274 | ``` 275 | 276 | This enables additional debug output for the UI system. 277 | 278 | ## Getting Help 279 | 280 | - **Documentation**: See files in `doc/` directory 281 | - **Examples**: Check `examples/luigi_example.cpp` 282 | - **Issue Tracker**: Report bugs or ask questions on GitHub 283 | -------------------------------------------------------------------------------- /tests/luigi_tests.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace rng = std::ranges; 11 | namespace views = rng::views; 12 | 13 | TEST_CASE(".ini file reading") { 14 | const char* ini_str = R"( 15 | [commands] 16 | Set breakpoint=b mem_visualizer.cpp:118 17 | break in rbtree_best_fit=b rbtree_best_fit.hpp:1245 18 | 19 | [shortcuts] 20 | Ctrl+I=print i 21 | Ctrl+Shift+F10=reverse-next 22 | Ctrl+Shift+F11=reverse-step 23 | 24 | [ui] 25 | scale=1 26 | )"; 27 | 28 | INI_Parser ini_file(ini_str); 29 | 30 | auto ui = ini_file | views::filter([](auto& t) { return t._section == "ui" && !t._key.empty(); }); 31 | CHECK(rng::count_if(ui, [](auto&) { return true; }) == 1); 32 | 33 | auto shortcuts = ini_file | views::filter([](auto& t) { return t._section == "shortcuts" && !t._key.empty(); }); 34 | CHECK(rng::count_if(shortcuts, [](auto&) { return true; }) == 3); 35 | 36 | auto first_command = rng::find_if(ini_file, [](auto& t) { return t._section == "commands" && !t._key.empty(); }); 37 | CHECK(first_command != rng::end(ini_file)); 38 | auto [section, key, value] = *first_command; 39 | CHECK(section == "commands"); 40 | CHECK(key == "Set breakpoint"); 41 | CHECK(value == "b mem_visualizer.cpp:118"); 42 | } 43 | 44 | TEST_CASE("INI_File::insert_in_section - duplicate removal bug") { 45 | // This test verifies the fix for the bug where removing duplicates 46 | // would cause the rest of the file to be appended, duplicating all 47 | // subsequent sections. The bug was in line 2406 of luigi.hpp where 48 | // std::string_view was constructed without a size parameter. 49 | 50 | // Create a temporary test file 51 | fs::path test_file = fs::temp_directory_path() / "test_ini_bug.ini"; 52 | 53 | SUBCASE("Removing duplicate should not duplicate subsequent sections") { 54 | // Create initial file with two sections 55 | { 56 | std::ofstream ofs(test_file); 57 | ofs << "[program]\n" 58 | << "./examples/calc\n" 59 | << "./gdbf\n" 60 | << "./examples/gdbf_testprog\n" 61 | << "\n" 62 | << "[ui_layout]\n" 63 | << "layout1\n" 64 | << "layout2\n"; 65 | } 66 | 67 | // Insert "./gdbf\n" at the beginning (it already exists, so should just move it) 68 | INI_File{test_file}.insert_in_section("[program]\n", "./gdbf\n", 0); 69 | 70 | // Read the result 71 | std::ifstream ifs(test_file); 72 | std::string result((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); 73 | 74 | // Verify the structure 75 | CHECK(result.find("[program]\n") != std::string::npos); 76 | CHECK(result.find("[ui_layout]\n") != std::string::npos); 77 | 78 | // Count how many times [ui_layout] appears - should be exactly once 79 | size_t count = 0; 80 | size_t pos = 0; 81 | while ((pos = result.find("[ui_layout]", pos)) != std::string::npos) { 82 | count++; 83 | pos += 11; // length of "[ui_layout]" 84 | } 85 | CHECK(count == 1); 86 | 87 | // Verify layout1 and layout2 appear exactly once each 88 | CHECK(std::count(result.begin(), result.end(), '1') == 1); 89 | CHECK(std::count(result.begin(), result.end(), '2') == 1); 90 | 91 | // Verify ./gdbf is at the beginning of [program] section 92 | size_t program_pos = result.find("[program]\n"); 93 | size_t gdbf_pos = result.find("./gdbf\n", program_pos); 94 | size_t calc_pos = result.find("./examples/calc\n", program_pos); 95 | CHECK(gdbf_pos < calc_pos); // ./gdbf should come before ./examples/calc 96 | } 97 | 98 | SUBCASE("Removing duplicate from middle of section") { 99 | // Create initial file 100 | { 101 | std::ofstream ofs(test_file); 102 | ofs << "[program]\n" 103 | << "./first\n" 104 | << "./middle\n" 105 | << "./last\n" 106 | << "\n" 107 | << "[other]\n" 108 | << "content1\n" 109 | << "content2\n"; 110 | } 111 | 112 | // Move "./middle\n" to the beginning 113 | INI_File{test_file}.insert_in_section("[program]\n", "./middle\n", 0); 114 | 115 | // Read the result 116 | std::ifstream ifs(test_file); 117 | std::string result((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); 118 | 119 | // Verify [other] section appears exactly once 120 | size_t count = 0; 121 | size_t pos = 0; 122 | while ((pos = result.find("[other]", pos)) != std::string::npos) { 123 | count++; 124 | pos += 7; 125 | } 126 | CHECK(count == 1); 127 | 128 | // Verify content1 and content2 appear exactly once 129 | CHECK(result.find("content1") != std::string::npos); 130 | CHECK(result.find("content2") != std::string::npos); 131 | size_t first_content1 = result.find("content1"); 132 | size_t second_content1 = result.find("content1", first_content1 + 8); 133 | CHECK(second_content1 == std::string::npos); // Should not find it again 134 | 135 | // Verify order in [program] section: middle, first, last 136 | size_t program_pos = result.find("[program]\n"); 137 | size_t middle_pos = result.find("./middle\n", program_pos); 138 | size_t first_pos = result.find("./first\n", program_pos); 139 | size_t last_pos = result.find("./last\n", program_pos); 140 | CHECK(middle_pos < first_pos); 141 | CHECK(first_pos < last_pos); 142 | } 143 | 144 | SUBCASE("Inserting new entry should not duplicate subsequent sections") { 145 | // Create initial file 146 | { 147 | std::ofstream ofs(test_file); 148 | ofs << "[program]\n" 149 | << "./existing\n" 150 | << "\n" 151 | << "[settings]\n" 152 | << "key=value\n"; 153 | } 154 | 155 | // Insert a new entry that doesn't exist 156 | INI_File{test_file}.insert_in_section("[program]\n", "./new\n", 0); 157 | 158 | // Read the result 159 | std::ifstream ifs(test_file); 160 | std::string result((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); 161 | 162 | // Verify [settings] section appears exactly once 163 | size_t count = 0; 164 | size_t pos = 0; 165 | while ((pos = result.find("[settings]", pos)) != std::string::npos) { 166 | count++; 167 | pos += 10; 168 | } 169 | CHECK(count == 1); 170 | 171 | // Verify the new entry is there 172 | CHECK(result.find("./new\n") != std::string::npos); 173 | CHECK(result.find("./existing\n") != std::string::npos); 174 | } 175 | 176 | SUBCASE("Multiple operations should not cause cumulative duplication") { 177 | // Create initial file 178 | { 179 | std::ofstream ofs(test_file); 180 | ofs << "[program]\n" 181 | << "./a\n" 182 | << "./b\n" 183 | << "./c\n" 184 | << "\n" 185 | << "[ui_layout]\n" 186 | << "layout_line\n"; 187 | } 188 | 189 | // Perform multiple insert operations (simulating multiple program runs) 190 | INI_File{test_file}.insert_in_section("[program]\n", "./b\n", 0); 191 | INI_File{test_file}.insert_in_section("[program]\n", "./c\n", 0); 192 | INI_File{test_file}.insert_in_section("[program]\n", "./a\n", 0); 193 | 194 | // Read the result 195 | std::ifstream ifs(test_file); 196 | std::string result((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); 197 | 198 | // Count [ui_layout] sections - should still be exactly one 199 | size_t count = 0; 200 | size_t pos = 0; 201 | while ((pos = result.find("[ui_layout]", pos)) != std::string::npos) { 202 | count++; 203 | pos += 11; 204 | } 205 | CHECK(count == 1); 206 | 207 | // Verify layout_line appears exactly once 208 | count = 0; 209 | pos = 0; 210 | while ((pos = result.find("layout_line", pos)) != std::string::npos) { 211 | count++; 212 | pos += 11; 213 | } 214 | CHECK(count == 1); 215 | } 216 | 217 | // Clean up 218 | fs::remove(test_file); 219 | } -------------------------------------------------------------------------------- /examples/luigi_example.cpp: -------------------------------------------------------------------------------- 1 | #ifdef _MSC_VER 2 | #pragma warning(disable : 4100) // unreferenced formal parameter 3 | #pragma warning(disable : 4996) // This function or variable may be unsafe. Consider using ... instead. 4 | #endif 5 | 6 | #include 7 | 8 | UILabel* label = nullptr; 9 | 10 | UISlider* slider_horiz = nullptr; 11 | UIGauge* gauge_horiz1 = nullptr; 12 | UIGauge* gauge_horiz2 = nullptr; 13 | 14 | UISlider* slider_vert = nullptr; 15 | UIGauge* gauge_vert1 = nullptr; 16 | UIGauge* gauge_vert2 = nullptr; 17 | 18 | UICheckbox* check_delete; 19 | 20 | const char* themeItems[] = { 21 | "panel1", "panel2", "selected", "border", "text", "textDisabled", 22 | "textSelected", "buttonNormal", "buttonHovered", "buttonPressed", "buttonDisabled", "textboxNormal", 23 | "textboxFocused", "codeFocused", "codeBackground", "codeDefault", "codeComment", "codeString", 24 | "codeNumber", "codeOperator", "codePreprocessor", 25 | }; 26 | 27 | int selected; 28 | 29 | int main(int argc, char** argv) { 30 | UIConfig cfg; 31 | 32 | // optional: set local font if present 33 | std::string home = getenv("HOME"); 34 | std::string font_path = home + "/.fonts/FiraCode-Regular.ttf"; 35 | if (fs::exists(font_path)) 36 | cfg.font_path = font_path; 37 | 38 | auto ui_ptr = UI::initialise(cfg); 39 | 40 | if (!ui_ptr) 41 | return 1; 42 | 43 | UIWindow& window = ui_ptr->create_window(0, 0, "luigi - Example Application", 0, 0); 44 | 45 | // Split window (vertically) into top/bottom panes. 46 | UISplitPane& uisplit_topbottom = window.add_splitpane(UIElement::vertical_flag, 0.75f); 47 | 48 | // Split top pane (horizontally) into left/right panes. 49 | UISplitPane& uisplit_top_leftright = uisplit_topbottom.add_splitpane(0, 0.3f); 50 | 51 | auto button_cb = [](UIButton& button) { 52 | std::print("clicked button '{}'...", button.label()); 53 | 54 | if (check_delete->checked()) { 55 | button.parent().refresh(); 56 | button.destroy(); 57 | std::print("{}", " and deleted it!\n"); 58 | } else { 59 | std::print("{}", " but not deleted!\n"); 60 | } 61 | }; 62 | 63 | { 64 | // In the top-left pane - create a single panel taking up the whole pane. 65 | UIPanel& panel = uisplit_top_leftright.add_panel(UIPanel::COLOR_1 | UIPanel::MEDIUM_SPACING); 66 | 67 | // Panels are by default vertical in layout, so items start at top and go down. 68 | panel.add_button(0, "Hello World").on_click(button_cb); 69 | 70 | // Create a new horizontal-layout "sub-panel" and put left and right panels inside it. 71 | UIPanel& subpanel = panel.add_panel(UIPanel::COLOR_1 | UIPanel::HORIZONTAL); 72 | 73 | // The left side will layout elements horizontally, with custom borders and gap. 74 | UIPanel& sub_left = 75 | subpanel.add_panel(UIPanel::COLOR_1 | UIPanel::HORIZONTAL).set_border(ui_rect_1(10)).set_gap(2); 76 | gauge_vert1 = &sub_left.add_gauge(UIElement::vertical_flag); 77 | gauge_vert2 = &sub_left.add_gauge(UIElement::vertical_flag); 78 | 79 | slider_vert = &sub_left.add_slider(UIElement::vertical_flag).on_value_changed([](UISlider&) { 80 | gauge_vert2->set_position(slider_vert->position()); 81 | gauge_horiz1->set_position(slider_vert->position()); 82 | }); 83 | 84 | // The right side will lay out elements vertically (the default), with default medium spacing. 85 | UIPanel& sub_right = subpanel.add_panel(UIPanel::COLOR_1 | UIPanel::MEDIUM_SPACING); 86 | sub_right.add_button(0, "1").on_click(button_cb); 87 | sub_right.add_button(0, "2").on_click(button_cb); 88 | sub_right.add_button(0, "3").on_click(button_cb); 89 | sub_right.add_button(0, "4").on_click(button_cb); 90 | sub_right.add_button(0, "5").on_click(button_cb); 91 | 92 | // Back outside of the "sub-panel", we continue layout downwards. 93 | panel.add_button(0, "Goodbye World").on_click(button_cb); 94 | 95 | gauge_horiz1 = &panel.add_gauge(0); 96 | gauge_horiz2 = &panel.add_gauge(0); 97 | 98 | slider_horiz = &panel.add_slider(0).on_value_changed([](UISlider&) { 99 | gauge_horiz2->set_position(slider_horiz->position()); 100 | gauge_vert1->set_position(slider_horiz->position()); 101 | }); 102 | 103 | panel.add_textbox(0); 104 | panel.add_textbox(0); // UITextbox::HIDE_CHARACTERS); 105 | 106 | // Set default slider positions. 107 | slider_vert->set_position(0.1); 108 | slider_horiz->set_position(0.3); 109 | } 110 | 111 | // Top-Right pane. 112 | uisplit_top_leftright.add_code(0).load_file("../src/luigi.hpp").set_focus_line(0); 113 | 114 | // Split bottom pane (horizontally) into left/right panes. 115 | UISplitPane& uisplit_bottom_leftright = uisplit_topbottom.add_splitpane(0, 0.3f); 116 | 117 | { 118 | // Bottom-Left pane. 119 | UIPanel& panel = uisplit_bottom_leftright.add_panel(UIPanel::COLOR_2).set_border(UIRectangle(5)).set_gap(5); 120 | panel.add_button(0, "It's a button??").on_click([&ui_ptr](UIButton& el) { 121 | ui_ptr->create_menu(&el, 0) 122 | .add_item(0, "Item 1\tCtrl+F5", 123 | [](UIButton&) { 124 | label->set_label("Item 1 clicked!"); 125 | label->refresh(); 126 | }) 127 | .add_item(0, "Item 2\tF6", 128 | [](UIButton&) { 129 | label->set_label("Item 2 clicked!"); 130 | label->refresh(); 131 | }) 132 | .show(); 133 | }); 134 | label = &panel.add_label(UIElement::h_fill, "Hello, I am a label!"); 135 | } 136 | 137 | { 138 | // Bottom-Right pane. 139 | UITabPane& tab_pane = uisplit_bottom_leftright.add_tabpane(0, "Tab 1\tMiddle Tab\tTab 3"); 140 | 141 | // First tab in tabPane 142 | tab_pane.add_table(0, "Column 1\tColumn 2") 143 | .set_num_items(100000) 144 | .on_getitem([](UITable&, UITableGetItem& m) -> int { 145 | m._is_selected = (selected == (int)m._row); 146 | if (m._column == 0) { 147 | return m.format_to("Item {}", m._row); 148 | } else { 149 | return m.format_to("other column {}", m._row); 150 | } 151 | }) 152 | .on_click([](UITable& table) { 153 | int hit = table.hittest(table.cursor_pos()); 154 | 155 | if (selected != hit) { 156 | selected = hit; 157 | if (!table.ensure_visible(selected)) { 158 | table.repaint(NULL); 159 | } 160 | } 161 | }) 162 | .resize_columns(); 163 | 164 | // Second tab 165 | tab_pane.add_panel(UIPanel::COLOR_1).add_label(0, "you're in tab 2, bucko"); 166 | 167 | // Third tab 168 | UIPanel& settings_panel = tab_pane.add_panel(UIPanel::COLOR_1 | UIPanel::MEDIUM_SPACING | UIPanel::HORIZONTAL); 169 | settings_panel.add_label(0, "Delete top-left panel buttons on click:"); 170 | check_delete = &settings_panel.add_checkbox(0, "Off").on_click([](UICheckbox& cb) { 171 | cb.set_label(cb.checked() ? "On" : "Off"); 172 | }); 173 | } 174 | 175 | window.register_shortcut(UIShortcut{.code = UI_KEYCODE_LETTER('T'), .ctrl = true, .invoke = []() { 176 | if (!label) 177 | return false; 178 | label->set_label("Keyboard shortcut!"); 179 | label->refresh(); 180 | return true; 181 | }}); 182 | 183 | { 184 | // Create a separate window demonstrating the MDI element 185 | UIMDIClient& client = ui_ptr->create_window(0, 0, "luigi - MDI Example", 0, 0).add_mdiclient(0); 186 | 187 | client.add_mdichild(UIMDIChild::CLOSE_BUTTON, UIRectangle(10, 600, 10, 400), "My Window") 188 | .add_panel(UIPanel::COLOR_1 | UIPanel::MEDIUM_SPACING) 189 | .add_label(0, "It's a christmas miracle"); 190 | 191 | client.add_mdichild(UIMDIChild::CLOSE_BUTTON, UIRectangle(40, 630, 40, 430), "Second Window") 192 | .add_panel(UIPanel::COLOR_1 | UIPanel::MEDIUM_SPACING) 193 | .add_label(0, "the system is down"); 194 | 195 | client.add_mdichild(UIMDIChild::CLOSE_BUTTON, UIRectangle(70, 670, 70, 470), "Third Window") 196 | .add_button(0, "giant button!!"); 197 | } 198 | 199 | return ui_ptr->message_loop(); 200 | } 201 | -------------------------------------------------------------------------------- /src/re/cpp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | using namespace ctre::literals; 9 | using namespace regexp; 10 | 11 | template 12 | using fs_t = ctll::fixed_string; // we can use `fs_t` instead of `ctll::fixed_string` only with clang++-19 or g++-11 13 | 14 | // -------------------------------------------------------------------------------- 15 | template 16 | constexpr auto fs_concat() noexcept { 17 | constexpr std::size_t len = (Strings.size() + ...); 18 | std::array arr{}; 19 | std::size_t i = 0; 20 | auto append = [&](auto const& s) mutable { 21 | for (auto c : s) 22 | arr[i++] = c; 23 | }; 24 | (append(Strings), ...); 25 | 26 | return ctll::fixed_string(arr); 27 | } 28 | 29 | // -------------------------------------------------------------------------------- 30 | template 31 | constexpr auto fs_repeat() noexcept { 32 | return fs_concat<"(", fs, ")*">(); 33 | } 34 | 35 | // Basic patterns 36 | // -------------- 37 | static constexpr auto identifier = ctll::fixed_string{"[a-zA-Z_][a-zA-Z0-9_]*"}; 38 | static constexpr auto ns_delim = ctll::fixed_string{"::"}; 39 | static constexpr auto call_params = ctll::fixed_string{R"(\s*\([^()]*\))"}; 40 | static constexpr auto bracket_op = ctll::fixed_string{R"(\s*\[[^\[\]]+\])"}; 41 | static constexpr auto dereference = ctll::fixed_string{R"((?:(?:\.|\->)[a-zA-Z0-9_]*)*)"}; 42 | 43 | // Namespaced identifier pattern (includes non-namespaced as well) 44 | // --------------------------------------------------------------- 45 | static constexpr auto namespaced_id = fs_concat()>()>(); 46 | 47 | // Function calls with parameters: foo(arg1, arg2) or ns::foo(arg1, arg2) 48 | // ---------------------------------------------------------------------- 49 | [[maybe_unused]] static constexpr auto function_call = fs_concat(); 50 | 51 | // Parenthesized expressions: (x + y) 52 | // ---------------------------------- 53 | static constexpr auto parenthesized = ctll::fixed_string{R"(\(([^(),]+)\))"}; 54 | 55 | // Variable names and member access: foo, foo.bar, foo->bar, ns::foo, ns::foo->bar 56 | // ------------------------------------------------------------------------------- 57 | static constexpr auto variables = fs_concat(); 58 | 59 | // Array access: arr[idx] or ns::arr[idx] 60 | // -------------------------------------- 61 | static constexpr auto array_access = fs_concat(); 62 | 63 | // Basic binary expressions: a + b, x * y, ns::x + y etc. 64 | // ------------------------------------------------------ 65 | static constexpr auto oper = ctll::fixed_string{R"(\s*[+\-*/%&|^]\s*)"}; 66 | static constexpr auto binary_expr = fs_concat(); 67 | 68 | // Spaces and open parenthesis 69 | // --------------------------- 70 | static constexpr auto spaces_par = ctll::fixed_string{R"(\s*\()"}; 71 | 72 | // -------------------------------------------------------------------------------- 73 | template 74 | void collect_matches(std::vector& expressions, const std::string_view& code, uint32_t e = 0) { 75 | for (auto match : ctre::search_all(code)) { 76 | std::string_view sv = match.template get(); 77 | if ((e & avoid_constant_litterals) && ctre::match(sv)) 78 | continue; 79 | expressions.push_back(sv); 80 | } 81 | } 82 | 83 | // -------------------------------------------------------------------------------- 84 | std::vector regexp::cpp_impl::debuggable_expressions(std::string_view code, 85 | uint32_t e /* = 0 */) const { 86 | std::vector expressions; 87 | expressions.reserve(32); 88 | 89 | // Find all matches for each pattern 90 | // --------------------------------- 91 | if (e & allow_function_calls) 92 | collect_matches(expressions, code, e); // don't execute function calls which may have side effects 93 | collect_matches(expressions, code, e); 94 | collect_matches(expressions, code, e); 95 | collect_matches(expressions, code, e); 96 | collect_matches(expressions, code, e); 97 | 98 | // remove duplicates 99 | // ----------------- 100 | std::sort(expressions.begin(), expressions.end()); 101 | auto newEnd = std::unique(expressions.begin(), expressions.end()); 102 | expressions.erase(newEnd, expressions.end()); 103 | 104 | // sort by size 105 | // ------------ 106 | std::stable_sort(expressions.begin(), expressions.end(), 107 | [](std::string_view a, std::string_view b) { return a.size() < b.size(); }); 108 | 109 | return expressions; 110 | } 111 | 112 | // -------------------------------------------------------------------------------- 113 | std::optional regexp::cpp_impl::find_at_pos(std::string_view code, code_look_for lf, size_t pos) const { 114 | std::vector matches; 115 | matches.reserve(4); 116 | auto c = code[pos]; 117 | 118 | if (lf == code_look_for::selectable_expression) { 119 | bool match_ident = false; 120 | if (c == '(' || c == ')') { 121 | collect_matches(matches, code); 122 | collect_matches(matches, code); 123 | } else if (c == '[' || c == ']') { 124 | collect_matches(matches, code); 125 | } else { 126 | match_ident = true; 127 | collect_matches(matches, code); 128 | } 129 | for (const auto& v : matches) { 130 | size_t start = v.data() - code.data(); 131 | if (start <= pos && start + v.length() >= pos) { 132 | auto rest = code.substr(start + v.length()); 133 | if (match_ident && static_cast(ctre::starts_with(rest))) { 134 | // if we parsed an variable reference followed by an open parenthesis, it is likely a function call 135 | auto par = ctre::match(rest); 136 | return find_at_pos(code, lf, start + v.length() + par.get<0>().size()); // will parse function calls 137 | } 138 | return regexp::bounds{start, start + v.length()}; 139 | } 140 | } 141 | } 142 | return {}; 143 | } 144 | 145 | 146 | // -------------------------------------------------------------------------------- 147 | bool cpp_impl::matches(std::string_view s, code_look_for lf, size_t pos /* = 0 */) const { 148 | switch(lf) { 149 | 150 | default: 151 | assert(0); 152 | } 153 | return false; 154 | } 155 | 156 | // -------------------------------------------------------------------------------- 157 | opt_res_t<1> cpp_impl::find_1(std::string_view sv, code_look_for lf, size_t pos /* = 0 */) const { 158 | switch(lf) { 159 | 160 | default: 161 | assert(0); 162 | } 163 | return {}; 164 | } 165 | 166 | // -------------------------------------------------------------------------------- 167 | opt_res_t<2> cpp_impl::find_2(std::string_view sv, code_look_for lf, size_t pos /* = 0 */) const { 168 | switch(lf) { 169 | 170 | default: 171 | assert(0); 172 | } 173 | return {}; 174 | } 175 | 176 | // -------------------------------------------------------------------------------- 177 | opt_res_t<3> cpp_impl::find_3(std::string_view sv, code_look_for lf, size_t pos /* = 0 */) const { 178 | switch(lf) { 179 | 180 | default: 181 | assert(0); 182 | } 183 | return {}; 184 | } 185 | 186 | #if 0 187 | // compile with: `cd ../src; g++-12 -std=c++20 -I../deps/include regex.cpp` 188 | // ------------------------------------------------------------------------ 189 | int main() { 190 | std::string code = "aa::bb::result = aa::foo::bar(x + y) + a::b::c->x + arr[idx]->member.value * 2;"; 191 | auto expressions = regex::extract_debuggable_expressions(code); 192 | 193 | for (const auto& expr : expressions) { 194 | std::cout << "Debuggable expression: " << expr << '\n'; 195 | } 196 | 197 | std::string input; 198 | while (true) { 199 | std::cout << "Enter text (or 'quit' to exit): "; 200 | getline(std::cin, input); 201 | if (input == "quit") 202 | break; 203 | 204 | std::cout << "match: " << regex::match_stack_or_breakpoint_output(input) << '\n'; 205 | } 206 | 207 | return 0; 208 | } 209 | #endif -------------------------------------------------------------------------------- /deps/include/boost/mp11/lambda.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MP11_LAMBDA_HPP_INCLUDED 2 | #define BOOST_MP11_LAMBDA_HPP_INCLUDED 3 | 4 | // Copyright 2024 Joaquin M Lopez Munoz. 5 | // 6 | // Distributed under the Boost Software License, Version 1.0. 7 | // 8 | // See accompanying file LICENSE_1_0.txt or copy at 9 | // http://www.boost.org/LICENSE_1_0.txt 10 | 11 | #include 12 | 13 | #if BOOST_MP11_WORKAROUND(BOOST_MP11_MSVC, <= 1800) 14 | 15 | // mp_lambda not supported due to compiler limitations 16 | 17 | #else 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #if defined(_MSC_VER) || defined(__GNUC__) 24 | # pragma push_macro( "I" ) 25 | # undef I 26 | #endif 27 | 28 | namespace boost 29 | { 30 | namespace mp11 31 | { 32 | namespace detail 33 | { 34 | 35 | template struct lambda_impl; 36 | 37 | } // namespace detail 38 | 39 | // mp_lambda 40 | template using mp_lambda = typename detail::lambda_impl::type; 41 | 42 | namespace detail 43 | { 44 | 45 | // base case (no placeholder replacement) 46 | template struct lambda_impl 47 | { 48 | template using make = T; 49 | using type = mp_bind; 50 | }; 51 | 52 | // placeholders (behave directly as mp_bind expressions) 53 | template struct lambda_impl> 54 | { 55 | using type = mp_arg; 56 | }; 57 | 58 | #define BOOST_MP11_SPECIALIZE_LAMBDA_IMPL(name, compound_type) \ 59 | template using lambda_make_##name = compound_type; \ 60 | \ 61 | template struct lambda_impl \ 62 | { \ 63 | using type = mp_bind>; \ 64 | }; 65 | 66 | // [basic.type.qualifier] 67 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL(const, const T) 68 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL(volatile, volatile T) 69 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL(const_volatile, const volatile T) 70 | 71 | // [dcl.ptr] 72 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL(pointer, T*) 73 | 74 | // [dcl.ref] 75 | // GCC < 7 fails with template using make = U&; 76 | template struct lambda_impl 77 | { 78 | template using make = typename std::add_lvalue_reference::type; 79 | using type = mp_bind>; 80 | }; 81 | 82 | template struct lambda_impl 83 | { 84 | template using make = typename std::add_rvalue_reference::type; 85 | using type = mp_bind>; 86 | }; 87 | 88 | // [dcl.array] 89 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL(array, T[]) 90 | 91 | #undef BOOST_MP11_SPECIALIZE_LAMBDA_IMPL 92 | 93 | template struct lambda_impl 94 | { 95 | template using make = Q[N]; 96 | using type = mp_bind>; 97 | }; 98 | 99 | // [dcl.fct], [dcl.mptr] (member functions) 100 | #define BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(name, qualifier) \ 101 | template using lambda_make_fct_##name = R(T...) qualifier; \ 102 | \ 103 | template struct lambda_impl \ 104 | { \ 105 | using type = mp_bind< \ 106 | lambda_make_fct_##name, \ 107 | mp_lambda, mp_lambda...>; \ 108 | }; \ 109 | \ 110 | template using lambda_make_fct_##name##_ellipsis = \ 111 | R(T..., ...) qualifier; \ 112 | \ 113 | template struct lambda_impl \ 114 | { \ 115 | using type = mp_bind< \ 116 | lambda_make_fct_##name##_ellipsis, \ 117 | mp_lambda, mp_lambda...>; \ 118 | }; \ 119 | \ 120 | template using lambda_make_mfptr_##name = \ 121 | R (C::*)(T...) qualifier; \ 122 | \ 123 | template struct lambda_impl \ 124 | { \ 125 | using type = mp_bind< \ 126 | lambda_make_mfptr_##name, \ 127 | mp_lambda, mp_lambda, mp_lambda...>; \ 128 | }; \ 129 | \ 130 | template using lambda_make_mfptr_##name##_ellipsis = \ 131 | R (C::*)(T..., ...) qualifier; \ 132 | \ 133 | template struct lambda_impl \ 134 | { \ 135 | using type = mp_bind< \ 136 | lambda_make_mfptr_##name##_ellipsis, \ 137 | mp_lambda, mp_lambda, mp_lambda...>; \ 138 | }; 139 | 140 | #define BOOST_MP11_LAMBDA_EMPTY() 141 | 142 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(no_qualifier, BOOST_MP11_LAMBDA_EMPTY()) 143 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const, const) 144 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(volatile, volatile) 145 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_volatile, const volatile) 146 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(ref, &) 147 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_ref, const&) 148 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(volatile_ref, volatile&) 149 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_volatile_ref, const volatile&) 150 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(rvalue_ref, &&) 151 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_rvalue_ref, const&&) 152 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(volatile_rvalue_ref, volatile&&) 153 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_volatile_rvalue_ref, const volatile&&) 154 | 155 | #if (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L 156 | 157 | // P0012R1: exception specification as part of the type system 158 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(noexcept, noexcept) 159 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_noexcept, const noexcept) 160 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(volatile_noexcept, volatile noexcept) 161 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_volatile_noexcept, const volatile noexcept) 162 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(ref_noexcept, & noexcept) 163 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_ref_noexcept, const& noexcept) 164 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(volatile_ref_noexcept, volatile& noexcept) 165 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_volatile_ref_noexcept, const volatile& noexcept) 166 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(rvalue_ref_noexcept, && noexcept) 167 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_rvalue_ref_noexcept, const&& noexcept) 168 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(volatile_rvalue_ref_noexcept, volatile&& noexcept) 169 | BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR(const_volatile_rvalue_ref_noexcept, const volatile&& noexcept) 170 | 171 | #endif // P0012R1 172 | 173 | #undef BOOST_MP11_LAMBDA_EMPTY 174 | #undef BOOST_MP11_SPECIALIZE_LAMBDA_IMPL_FCT_AND_MFPTR 175 | 176 | // [dcl.mptr] (data members) 177 | template struct lambda_impl 178 | { 179 | template using make = U D::*; 180 | using type = mp_bind, mp_lambda>; 181 | }; 182 | 183 | // template class instantiation 184 | template