diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 1118d2286..000000000 --- a/.clang-format +++ /dev/null @@ -1,83 +0,0 @@ ---- -BasedOnStyle: Google -AccessModifierOffset: -2 -ConstructorInitializerIndentWidth: 2 -AlignEscapedNewlinesLeft: false -AlignTrailingComments: true -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortIfStatementsOnASingleLine: false -AllowShortLoopsOnASingleLine: false -AllowShortFunctionsOnASingleLine: None -AlwaysBreakTemplateDeclarations: true -AlwaysBreakBeforeMultilineStrings: false -BreakBeforeBinaryOperators: false -BreakBeforeTernaryOperators: false -BreakConstructorInitializers: BeforeComma -BinPackParameters: true -ColumnLimit: 90 -ConstructorInitializerAllOnOneLineOrOnePerLine: true -DerivePointerBinding: false -PointerBindsToType: true -ExperimentalAutoDetectBinPacking: false -IndentCaseLabels: true -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCSpaceBeforeProtocolList: true -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 60 -PenaltyBreakString: 1 -PenaltyBreakFirstLessLess: 1000 -PenaltyExcessCharacter: 1000 -PenaltyReturnTypeOnItsOwnLine: 90 -SpacesBeforeTrailingComments: 2 -Cpp11BracedListStyle: false -Standard: Auto -IndentWidth: 2 -TabWidth: 2 -UseTab: Never -IndentFunctionDeclarationAfterType: false -SpacesInParentheses: false -SpacesInAngles: false -SpaceInEmptyParentheses: false -SpacesInCStyleCastParentheses: false -SpaceAfterControlStatementKeyword: true -SpaceBeforeAssignmentOperators: true -SpaceBeforeParens: Never -ContinuationIndentWidth: 4 -SortIncludes: CaseSensitive -IncludeBlocks: Regroup -IncludeCategories: - # Main header (same name as source file) - - Regex: '^"[^/]*\.h(pp)?"$' - Priority: 1 - # BehaviorTree.CPP project headers - - Regex: '^"behaviortree_cpp/.*' - Priority: 2 - # C++ standard library headers - - Regex: '^<[a-z_]+>$' - Priority: 3 - # System headers with .h extension - - Regex: '^<.*\.h>' - Priority: 4 -IncludeIsMainRegex: '(_test)?$' -SpaceAfterCStyleCast: false -ReflowComments: false - -# Configure each individual brace in BraceWrapping -BreakBeforeBraces: Custom - -# Control of individual brace wrapping cases -BraceWrapping: { - AfterClass: 'true', - AfterControlStatement: 'true', - AfterEnum : 'true', - AfterFunction : 'true', - AfterNamespace : 'true', - AfterStruct : 'true', - AfterUnion : 'true', - BeforeCatch : 'true', - BeforeElse : 'true', - IndentBraces : 'false', - SplitEmptyFunction: 'false' -} -... diff --git a/.clang-tidy b/.clang-tidy deleted file mode 100644 index e34185555..000000000 --- a/.clang-tidy +++ /dev/null @@ -1,48 +0,0 @@ -Checks: [ - "-*", - "bugprone-*", - "cert-*", - "clang-analyzer-*", - "concurrency-*", - "cppcoreguidelines-*", - "misc-*", - "modernize-*", - "performance-*", - "portability-*", - "readability-*", - "-bugprone-easily-swappable-parameters", - "-bugprone-narrowing-conversions", - "-cert-err58-cpp", - "-cppcoreguidelines-avoid-c-arrays", - "-cppcoreguidelines-avoid-magic-numbers", - "-cppcoreguidelines-avoid-non-const-global-variables", - "-cppcoreguidelines-non-private-member-variables-in-classes", - "-cppcoreguidelines-pro-bounds-array-to-pointer-decay", - "-cppcoreguidelines-pro-bounds-constant-array-index", - "-cppcoreguidelines-pro-bounds-pointer-arithmetic", - "-cppcoreguidelines-pro-type-const-cast", - "-cppcoreguidelines-pro-type-union-access", - "-cppcoreguidelines-pro-type-vararg", - "-misc-no-recursion", - "-misc-non-private-member-variables-in-classes" -] - - -WarningsAsErrors: '-*,bugprone-*,cert-*,clang-analyzer-*,concurrency-*,cppcoreguidelines-*,misc-*,portability-*,readability-implicit-bool-conversion,-concurrency-mt-unsafe,-readability-function-cognitive-complexity' - -CheckOptions: - # ignore macros when computing the cyclomatic complexity. problem caused by RCLCPP LOG macros - - key: readability-function-cognitive-complexity.IgnoreMacros - value: 'true' - - # This change makes it compatible with MISRA:2023 rule 4.14.1 - - key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic - value: 'true' - - # Making a copy of a shared_ptr has a non-zero cost, but this cost is small. - # Unfortunately the ROS API (subscriber callbacks) oblige the user to use callbacks functions that will trigger this warning - # This is the reason wht the warning is silenced here - - key: performance-unnecessary-value-param.AllowedTypes - value: 'std::shared_ptr' - - # Reference: https://clang.llvm.org/extra/clang-tidy/checks/readability/identifier-naming.html diff --git a/.codespell_ignore_words b/.codespell_ignore_words deleted file mode 100644 index ab09b3c2f..000000000 --- a/.codespell_ignore_words +++ /dev/null @@ -1,7 +0,0 @@ -INOUT -InOut -delimeter -Succesful -worl -valu -Exeption diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index accb08cd7..000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,4 +0,0 @@ -# These are supported funding model platforms - -github: facontidavide -custom: https://www.paypal.me/facontidavide diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 9eb010608..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: Bug report -about: Help me help you... -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -If you are experiencing a crash, provide a backtrace (GDB or similar). - -*How to Reproduce** - -Please provide a specific description of how to reproduce the issue or source code that can be compiled and executed. Please attach a file/project that is easy to compile, don't copy and paste code snippets! - -Even better, create a Pull Request with a failing unit test. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 021458556..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 5ace4600a..000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,6 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 052ed3a65..000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,11 +0,0 @@ - diff --git a/.github/workflows/cmake_ubuntu.yml b/.github/workflows/cmake_ubuntu.yml deleted file mode 100644 index 17c9efa8c..000000000 --- a/.github/workflows/cmake_ubuntu.yml +++ /dev/null @@ -1,134 +0,0 @@ -name: cmake Ubuntu - -on: - push: - branches: - - master - pull_request: - types: [opened, synchronize, reopened] - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -env: - BUILD_TYPE: Release - -jobs: - build: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-22.04] - - steps: - - uses: actions/checkout@v6 - - - name: Install Conan - id: conan - uses: turtlebrowser/get-conan@main - - - name: Create default profile - run: conan profile detect - - - name: Install conan dependencies - run: conan install conanfile.py -s build_type=${{env.BUILD_TYPE}} --build=missing - - - name: Normalize build type - shell: bash - run: echo "BUILD_TYPE_LOWERCASE=$(echo "${BUILD_TYPE}" | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV - - - name: Configure CMake - shell: bash - run: cmake --preset conan-${{ env.BUILD_TYPE_LOWERCASE }} - - - name: Build - shell: bash - run: cmake --build --preset conan-${{ env.BUILD_TYPE_LOWERCASE }} - - - name: run test (Linux) - run: ctest --test-dir build/${{env.BUILD_TYPE}} - - coverage: - runs-on: ubuntu-24.04 - - steps: - - uses: actions/checkout@v6 - with: - fetch-depth: 0 # Full history needed by SonarCloud - - - name: Install lcov - run: sudo apt-get update && sudo apt-get install -y lcov - - - name: Install Conan - id: conan - uses: turtlebrowser/get-conan@main - - - name: Create default profile - run: conan profile detect - - - name: Install conan dependencies - run: conan install conanfile.py -s build_type=Debug --build=missing - - - name: Configure CMake with coverage - shell: bash - run: | - cmake --preset conan-debug \ - -DCMAKE_C_FLAGS="--coverage -fprofile-update=atomic" \ - -DCMAKE_CXX_FLAGS="--coverage -fprofile-update=atomic" - - - name: Build - shell: bash - run: cmake --build --preset conan-debug - - - name: Run tests - run: ctest --test-dir build/Debug --output-on-failure - - - name: Collect coverage - run: | - lcov --capture --directory build/Debug \ - --output-file coverage.info \ - --ignore-errors mismatch,mismatch \ - --ignore-errors negative,negative \ - --ignore-errors gcov,gcov - lcov --extract coverage.info \ - '*/BehaviorTree.CPP/include/*' \ - '*/BehaviorTree.CPP/src/*' \ - --output-file coverage.info \ - --ignore-errors unused - lcov --remove coverage.info \ - '*/contrib/*' \ - --output-file coverage.info \ - --ignore-errors unused - lcov --list coverage.info - - # - name: Upload coverage reports to Codecov - # uses: codecov/codecov-action@v5 - # continue-on-error: true - # with: - # files: coverage.info - # flags: unittests - # disable_search: true - # disable_file_fixes: false - # plugins: noop - # network_filter: >- - # include/behaviortree_cpp/,src/ - # token: ${{ secrets.CODECOV_TOKEN }} - - # --- Coveralls --- - - name: Upload to Coveralls - uses: coverallsapp/github-action@v2 - continue-on-error: true - with: - file: coverage.info - format: lcov - github-token: ${{ secrets.GITHUB_TOKEN }} - - # --- SonarCloud --- - - name: Run SonarCloud analysis - uses: SonarSource/sonarcloud-github-action@v5 - continue-on-error: true - env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/cmake_ubuntu_sanitizers.yml b/.github/workflows/cmake_ubuntu_sanitizers.yml deleted file mode 100644 index 07e3a4537..000000000 --- a/.github/workflows/cmake_ubuntu_sanitizers.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: cmake Ubuntu Sanitizers - -on: - push: - branches: - - master - pull_request: - types: [opened, synchronize, reopened] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -env: - # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) - BUILD_TYPE: Debug - -jobs: - build: - # The CMake configure and build commands are platform agnostic and should work equally - # well on Windows or Mac. You can convert this to a matrix build if you need - # cross-platform coverage. - # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-22.04] - sanitizer: [asan_ubsan, tsan] - - steps: - - uses: actions/checkout@v6 - - - name: Install Conan - id: conan - uses: turtlebrowser/get-conan@main - - - name: Create default profile - run: conan profile detect - - - name: Install conan dependencies - run: conan install conanfile.py -s build_type=${{env.BUILD_TYPE}} --build=missing - - - name: Normalize build type - shell: bash - # The build type is Capitalized, e.g. Release, but the preset is all lowercase, e.g. release. - # There is no built in way to do string manipulations on GHA as far as I know.` - run: echo "BUILD_TYPE_LOWERCASE=$(echo "${BUILD_TYPE}" | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV - - - name: Configure CMake - shell: bash - run: | - if [[ "${{ matrix.sanitizer }}" == "asan_ubsan" ]]; then - cmake --preset conan-${{ env.BUILD_TYPE_LOWERCASE }} \ - -DBTCPP_ENABLE_ASAN:BOOL=ON -DBTCPP_ENABLE_UBSAN:BOOL=ON - else - cmake --preset conan-${{ env.BUILD_TYPE_LOWERCASE }} \ - -DBTCPP_ENABLE_TSAN:BOOL=ON - fi - - - name: Build - shell: bash - run: cmake --build --preset conan-${{ env.BUILD_TYPE_LOWERCASE }} - - - name: run test (Linux + Address and Undefined Behavior Sanitizers) - env: - GTEST_COLOR: "On" - ASAN_OPTIONS: "color=always" - UBSAN_OPTIONS: "halt_on_error=1:print_stacktrace=1:color=always" - TSAN_OPTIONS: "suppressions=../../../tests/tsan_suppressions.txt:color=always" - # There is a known issue with TSAN on recent kernel versions. Without the vm.mmap_rnd_bits=28 - # workaround all binaries with TSan enabled crash with "FATAL: ThreadSanitizer: unexpected memory mapping" - run: sudo sysctl vm.mmap_rnd_bits=28 && ctest --test-dir build/${{env.BUILD_TYPE}} --output-on-failure diff --git a/.github/workflows/cmake_windows.yml b/.github/workflows/cmake_windows.yml deleted file mode 100644 index 0eb1f47a1..000000000 --- a/.github/workflows/cmake_windows.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: cmake Windows - -on: - push: - branches: - - master - pull_request: - types: [opened, synchronize, reopened] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - build: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [windows-latest] - build_type: [Release, Debug] - - steps: - - uses: actions/checkout@v6 - - - name: Install Conan - id: conan - uses: turtlebrowser/get-conan@main - - - name: Create default profile - run: conan profile detect - - - name: Install conan dependencies - run: conan install conanfile.py -s build_type=${{ matrix.build_type }} --build=missing --settings:host compiler.cppstd=17 - - - name: Normalize build type - shell: bash - run: echo "BUILD_TYPE_LOWERCASE=$(echo "${{ matrix.build_type }}" | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV - - - name: Configure CMake - shell: bash - run: cmake --preset conan-default - - - name: Build - shell: bash - run: cmake --build --preset conan-${{ env.BUILD_TYPE_LOWERCASE }} - - - name: Run tests - working-directory: ${{ github.workspace }}/build - run: $env:PATH+=";${{ matrix.build_type }}"; tests/${{ matrix.build_type }}/behaviortree_cpp_test.exe diff --git a/.github/workflows/codeql.yml.bkp b/.github/workflows/codeql.yml.bkp deleted file mode 100644 index a76a623ca..000000000 --- a/.github/workflows/codeql.yml.bkp +++ /dev/null @@ -1,63 +0,0 @@ -name: "CodeQL" - -on: - push: - branches: [ 'master' ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ 'master' ] - schedule: - - cron: '36 19 * * 2' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'cpp' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - queries: +security-and-quality - - - # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 - with: - category: "/language:${{matrix.language}}" diff --git a/.github/workflows/doxygen-gh-pages.yml b/.github/workflows/doxygen-gh-pages.yml deleted file mode 100644 index bbb575e0c..000000000 --- a/.github/workflows/doxygen-gh-pages.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Doxygen GitHub Pages Deploy Action - -on: - push: - branches: - - main - - master - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - deploy: - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: DenverCoder1/doxygen-github-pages-action@v2.0.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - folder: doc/html diff --git a/.github/workflows/pixi.yaml b/.github/workflows/pixi.yaml deleted file mode 100644 index 848613ccb..000000000 --- a/.github/workflows/pixi.yaml +++ /dev/null @@ -1,31 +0,0 @@ -name: Pixi (conda) - -on: - push: - branches: - - master - pull_request: - types: [opened, synchronize, reopened] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - pixi_conda_build: - strategy: - matrix: - os: - - windows-latest - - ubuntu-latest - runs-on: ${{ matrix.os }} - steps: - # Pixi is the tool used to create/manage conda environment - - uses: actions/checkout@v6 - - uses: prefix-dev/setup-pixi@v0.9.4 - with: - pixi-version: v0.40.3 - - name: Build - run: pixi run build - - name: Run tests - run: pixi run test diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml deleted file mode 100644 index 4b28706a8..000000000 --- a/.github/workflows/pre-commit.yaml +++ /dev/null @@ -1,43 +0,0 @@ -name: pre-commit - -on: - push: - branches: - - master - pull_request: - types: [opened, synchronize, reopened] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - pre-commit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 - - uses: pre-commit/action@v3.0.1 - - clang-tidy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Install LLVM 21 - run: | - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh 21 - sudo apt-get install -y clangd-21 clang-tidy-21 - - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install -y libzmq3-dev libsqlite3-dev - - - name: Configure CMake - run: cmake -B build -DBUILD_TESTING=OFF - - - name: Run clang-tidy - run: ./run_clang_tidy.sh diff --git a/.github/workflows/ros2-rolling.yaml b/.github/workflows/ros2-rolling.yaml deleted file mode 100644 index 1eb8584ac..000000000 --- a/.github/workflows/ros2-rolling.yaml +++ /dev/null @@ -1,26 +0,0 @@ -name: ros2-rolling - -on: - push: - branches: - - master - pull_request: - types: [opened, synchronize, reopened] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - industrial_ci: - strategy: - matrix: - env: - - {ROS_DISTRO: rolling, ROS_REPO: main} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: 'ros-industrial/industrial_ci@master' - env: ${{matrix.env}} - with: - package-name: behaviortree_cpp diff --git a/.github/workflows/ros2.yaml b/.github/workflows/ros2.yaml deleted file mode 100644 index 494e9471e..000000000 --- a/.github/workflows/ros2.yaml +++ /dev/null @@ -1,27 +0,0 @@ -name: ros2 - -on: - push: - branches: - - master - pull_request: - types: [opened, synchronize, reopened] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - industrial_ci: - strategy: - matrix: - env: - - {ROS_DISTRO: humble, ROS_REPO: main} - - {ROS_DISTRO: jazzy, ROS_REPO: main} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: 'ros-industrial/industrial_ci@master' - env: ${{matrix.env}} - with: - package-name: behaviortree_cpp diff --git a/.github/workflows/sonarcube.yml.bkp b/.github/workflows/sonarcube.yml.bkp deleted file mode 100644 index 926306125..000000000 --- a/.github/workflows/sonarcube.yml.bkp +++ /dev/null @@ -1,42 +0,0 @@ -name: Sonarcube Scan - -on: - push: - branches: - - master - pull_request: - types: [opened, synchronize, reopened] - -jobs: - build: - name: Build - runs-on: ubuntu-latest - env: - BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - name: Install Build Wrapper - uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v4 - - - name: Install Dependencies - run: | - sudo apt-get update - sudo apt-get install -y libzmq3-dev libsqlite3-dev - - - name: Install googletest - uses: Bacondish2023/setup-googletest@v1 - - - name: Run Build Wrapper - run: | - mkdir build - cmake -S . -B build - build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build/ --config Release - - name: SonarQube Scan - uses: SonarSource/sonarqube-scan-action@v4 - env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # Put the name of your token here - with: - args: > - --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" diff --git a/.gitignore b/.gitignore deleted file mode 100644 index ddf344b2e..000000000 --- a/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -*~ -/CMakeLists.txt.user -build* -site/* -/.vscode/ -.vs/ - -# clangd cache and config (generated by CMake) -/.cache/* -/.clangd -CMakeSettings.json - -# OSX junk -.DS_Store - -# pixi environments -.pixi - -CMakeUserPresets.json - -tags -/clang_tidy_output.log -/.clang-tidy-venv/* -/llvm.sh -t11_groot_howto.btlog -minitrace.json - -TODO.md -/.worktrees/* -/docs/plans/* -/coverage_report/* -/coverage.info -/doc/html/* diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index ef395d8b9..000000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,64 +0,0 @@ - -# To use: -# -# pre-commit run -a -# -# Or: -# -# pre-commit install # (runs every time you commit in git) -# -# To update this file: -# -# pre-commit autoupdate -# -# See https://github.com/pre-commit/pre-commit - -exclude: ^3rdparty/|3rdparty|^include/behaviortree_cpp/contrib/|CHANGELOG.rst -repos: - - # Standard hooks - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 - hooks: - - id: check-added-large-files - - id: check-ast - - id: check-case-conflict - - id: check-docstring-first - - id: check-merge-conflict - - id: check-symlinks - - id: check-xml - - id: check-yaml - - id: debug-statements - - id: end-of-file-fixer - exclude_types: [svg] - - id: mixed-line-ending - - id: trailing-whitespace - exclude_types: [svg] - - id: fix-byte-order-marker - - # CPP hooks - - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v17.0.6 - hooks: - - id: clang-format - args: ['-fallback-style=none', '-i'] - - # C++ static analysis via clangd-21 (skips if not installed) - - repo: local - hooks: - - id: clang-tidy - name: clang-tidy - entry: ./run_clang_tidy_hook.sh - language: script - files: \.(cpp|hpp|h)$ - exclude: ^3rdparty/|^include/behaviortree_cpp/contrib/|^include/behaviortree_cpp/scripting/|^include/behaviortree_cpp/flatbuffers/|^examples/|^tools/|^fuzzing/|^tests/gtest_async_action_node\.cpp$|^tests/gtest_logger_zmq\.cpp$|^tests/include/environment\.h$|^tests/gtest_groot2_publisher\.cpp$ - - # Spell check - - repo: https://github.com/codespell-project/codespell - rev: v2.4.1 - hooks: - - id: codespell - additional_dependencies: - - tomli - args: - [--toml=./pyproject.toml] diff --git a/3rdparty/cppzmq/CMakeLists.txt b/3rdparty/cppzmq/CMakeLists.txt deleted file mode 100644 index 9a0bb86b0..000000000 --- a/3rdparty/cppzmq/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -find_package(ZeroMQ REQUIRED) - -add_library(cppzmq INTERFACE) - -# This library doesn't use modern targets unfortunately. -#add_library(cppzmq::cppzmq ALIAS cppzmq) - -target_include_directories(cppzmq - INTERFACE - ${CMAKE_CURRENT_SOURCE_DIR} -) - -if(TARGET libzmq-static) - target_link_libraries(cppzmq INTERFACE libzmq-static) -elseif(TARGET libzmq) - target_link_libraries(cppzmq INTERFACE libzmq) -else() - message(FATAL_ERROR "Unknown zeromq target name") -endif() diff --git a/3rdparty/cppzmq/LICENSE b/3rdparty/cppzmq/LICENSE deleted file mode 100644 index ae98bd859..000000000 --- a/3rdparty/cppzmq/LICENSE +++ /dev/null @@ -1,17 +0,0 @@ - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to - deal in the Software without restriction, including without limitation the - rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - sell copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. diff --git a/3rdparty/cppzmq/README.md b/3rdparty/cppzmq/README.md deleted file mode 100644 index 5d804d0c8..000000000 --- a/3rdparty/cppzmq/README.md +++ /dev/null @@ -1,200 +0,0 @@ -[![CI](https://github.com/zeromq/cppzmq/actions/workflows/ci.yml/badge.svg)](https://github.com/zeromq/cppzmq/actions) -[![Coverage Status](https://coveralls.io/repos/github/zeromq/cppzmq/badge.svg?branch=master)](https://coveralls.io/github/zeromq/cppzmq?branch=master) -[![License](https://img.shields.io/github/license/zeromq/cppzmq.svg)](https://github.com/zeromq/cppzmq/blob/master/LICENSE) - -Introduction & Design Goals -=========================== - -cppzmq is a C++ binding for libzmq. It has the following design goals: - - cppzmq maps the libzmq C API to C++ concepts. In particular: - - it is type-safe (the libzmq C API exposes various class-like concepts as void*) - - it provides exception-based error handling (the libzmq C API provides errno-based error handling) - - it provides RAII-style classes that automate resource management (the libzmq C API requires the user to take care to free resources explicitly) - - cppzmq is a light-weight, header-only binding. You only need to include the header file zmq.hpp (and maybe zmq_addon.hpp) to use it. - - zmq.hpp is meant to contain direct mappings of the abstractions provided by the libzmq C API, while zmq_addon.hpp provides additional higher-level abstractions. - -There are other C++ bindings for ZeroMQ with different design goals. In particular, none of the following bindings are header-only: - - [zmqpp](https://github.com/zeromq/zmqpp) is a high-level binding to libzmq. - - [czmqpp](https://github.com/zeromq/czmqpp) is a binding based on the high-level czmq API. - - [fbzmq](https://github.com/facebook/fbzmq) is a binding that integrates with Apache Thrift and provides higher-level abstractions in addition. It requires C++14. - -Supported platforms -=================== - - - Only a subset of the platforms that are supported by libzmq itself are supported. Some features already require a compiler supporting C++11. In the future, probably all features will require C++11. To build and run the tests, CMake and Catch are required. - - Any libzmq 4.x version is expected to work. DRAFT features may only work for the most recent tested version. Currently explicitly tested libzmq versions are - - 4.2.0 (without DRAFT API) - - 4.3.4 (with and without DRAFT API) - - Platforms with full support (i.e. CI executing build and tests) - - Ubuntu 18.04 x64 (with gcc 4.8.5, 5.5.0, 7.5.0) - - Ubuntu 20.04 x64 (with gcc 9.3.0, 10.3.0 and clang 12) - - Visual Studio 2017 x64 - - Visual Studio 2019 x64 - - macOS 10.15 (with clang 12, without DRAFT API) - - Additional platforms that are known to work: - - We have no current reports on additional platforms that are known to work yet. Please add your platform here. If CI can be provided for them with a cloud-based CI service working with GitHub, you are invited to add CI, and make it possible to be included in the list above. - - Additional platforms that probably work: - - Any platform supported by libzmq that provides a sufficiently recent gcc (4.8.1 or newer) or clang (3.4.1 or newer) - - Visual Studio 2012+ x86/x64 - -Examples -======== -These examples require at least C++11. -```c++ -#include - -int main() -{ - zmq::context_t ctx; - zmq::socket_t sock(ctx, zmq::socket_type::push); - sock.bind("inproc://test"); - sock.send(zmq::str_buffer("Hello, world"), zmq::send_flags::dontwait); -} -``` -This a more complex example where we send and receive multi-part messages over TCP with a wildcard port. -```c++ -#include -#include - -int main() -{ - zmq::context_t ctx; - zmq::socket_t sock1(ctx, zmq::socket_type::push); - zmq::socket_t sock2(ctx, zmq::socket_type::pull); - sock1.bind("tcp://127.0.0.1:*"); - const std::string last_endpoint = - sock1.get(zmq::sockopt::last_endpoint); - std::cout << "Connecting to " - << last_endpoint << std::endl; - sock2.connect(last_endpoint); - - std::array send_msgs = { - zmq::str_buffer("foo"), - zmq::str_buffer("bar!") - }; - if (!zmq::send_multipart(sock1, send_msgs)) - return 1; - - std::vector recv_msgs; - const auto ret = zmq::recv_multipart( - sock2, std::back_inserter(recv_msgs)); - if (!ret) - return 1; - std::cout << "Got " << *ret - << " messages" << std::endl; - return 0; -} -``` - -See the `examples` directory for more examples. When the project is compiled with tests enabled, each example gets compiled to an executable. - - -API Overview -============ - -For an extensive overview of the `zmq.hpp` API in use, see this [Tour of CPPZMQ by @brettviren](https://brettviren.github.io/cppzmq-tour/index.html). - -Bindings for libzmq in `zmq.hpp`: - -Types: -* class `zmq::context_t` -* enum `zmq::ctxopt` -* class `zmq::socket_t` -* class `zmq::socket_ref` -* enum `zmq::socket_type` -* enum `zmq::sockopt` -* enum `zmq::send_flags` -* enum `zmq::recv_flags` -* class `zmq::message_t` -* class `zmq::const_buffer` -* class `zmq::mutable_buffer` -* struct `zmq::recv_buffer_size` -* alias `zmq::send_result_t` -* alias `zmq::recv_result_t` -* alias `zmq::recv_buffer_result_t` -* class `zmq::error_t` -* class `zmq::monitor_t` -* struct `zmq_event_t`, -* alias `zmq::free_fn`, -* alias `zmq::pollitem_t`, -* alias `zmq::fd_t` -* class `zmq::poller_t` DRAFT -* enum `zmq::event_flags` DRAFT -* enum `zmq::poller_event` DRAFT - -Functions: -* `zmq::version` -* `zmq::poll` -* `zmq::proxy` -* `zmq::proxy_steerable` -* `zmq::buffer` -* `zmq::str_buffer` - -Extra high-level types and functions `zmq_addon.hpp`: - -Types: -* class `zmq::multipart_t` -* class `zmq::active_poller_t` DRAFT - -Functions: -* `zmq::recv_multipart` -* `zmq::send_multipart` -* `zmq::send_multipart_n` -* `zmq::encode` -* `zmq::decode` - -Compatibility Guidelines -======================== - -The users of cppzmq are expected to follow the guidelines below to ensure not to break when upgrading cppzmq to newer versions (non-exhaustive list): - -* Do not depend on any macros defined in cppzmq unless explicitly declared public here. - -The following macros may be used by consumers of cppzmq: `CPPZMQ_VERSION`, `CPPZMQ_VERSION_MAJOR`, `CPPZMQ_VERSION_MINOR`, `CPPZMQ_VERSION_PATCH`. - -Contribution policy -=================== - -The contribution policy is at: http://rfc.zeromq.org/spec:22 - -Build instructions -================== - -Build steps: - -1. Build [libzmq](https://github.com/zeromq/libzmq) via cmake. This does an out of source build and installs the build files - - `git clone https://github.com/zeromq/libzmq.git` - - `cd libzmq` - - `mkdir build` - - `cd build` - - `cmake ..` - - `sudo make -j4 install` - -2. Build cppzmq via cmake. This does an out of source build and installs the build files - - `git clone https://github.com/zeromq/cppzmq.git` - - `cd cppzmq` - - `mkdir build` - - `cd build` - - `cmake ..` or `cmake -DCPPZMQ_BUILD_TESTS=OFF ..` to skip building tests - - `sudo make -j4 install` - -3. Alternatively, build cppzmq via [vcpkg](https://github.com/Microsoft/vcpkg/). This does an out of source build and installs the build files - - `git clone https://github.com/Microsoft/vcpkg.git` - - `cd vcpkg` - - `./bootstrap-vcpkg.sh` (bootstrap-vcpkg.bat for Powershell) - - `./vcpkg integrate install` - - `./vcpkg install cppzmq` - -Using this: - -A cmake find package scripts is provided for you to easily include this library. -Add these lines in your CMakeLists.txt to include the headers and library files of -cpp zmq (which will also include libzmq for you). - -``` -#find cppzmq wrapper, installed by make of cppzmq -find_package(cppzmq) -target_link_libraries(*Your Project Name* cppzmq) -# Or use static library to link -target_link_libraries(*Your Project Name* cppzmq-static) -``` diff --git a/3rdparty/cppzmq/zmq.hpp b/3rdparty/cppzmq/zmq.hpp deleted file mode 100644 index ad0509e89..000000000 --- a/3rdparty/cppzmq/zmq.hpp +++ /dev/null @@ -1,2879 +0,0 @@ -/* - Copyright (c) 2016-2017 ZeroMQ community - Copyright (c) 2009-2011 250bpm s.r.o. - Copyright (c) 2011 Botond Ballo - Copyright (c) 2007-2009 iMatix Corporation - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to - deal in the Software without restriction, including without limitation the - rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - sell copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. -*/ - -#ifndef __ZMQ_HPP_INCLUDED__ -#define __ZMQ_HPP_INCLUDED__ - -#ifdef _WIN32 -#ifndef NOMINMAX -#define NOMINMAX -#endif -#endif - -// included here for _HAS_CXX* macros -#include - -#if defined(_MSVC_LANG) -#define CPPZMQ_LANG _MSVC_LANG -#else -#define CPPZMQ_LANG __cplusplus -#endif -// overwrite if specific language macros indicate higher version -#if defined(_HAS_CXX14) && _HAS_CXX14 && CPPZMQ_LANG < 201402L -#undef CPPZMQ_LANG -#define CPPZMQ_LANG 201402L -#endif -#if defined(_HAS_CXX17) && _HAS_CXX17 && CPPZMQ_LANG < 201703L -#undef CPPZMQ_LANG -#define CPPZMQ_LANG 201703L -#endif - -// macros defined if has a specific standard or greater -#if CPPZMQ_LANG >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) -#define ZMQ_CPP11 -#endif -#if CPPZMQ_LANG >= 201402L -#define ZMQ_CPP14 -#endif -#if CPPZMQ_LANG >= 201703L -#define ZMQ_CPP17 -#endif - -#if defined(ZMQ_CPP14) && !defined(_MSC_VER) -#define ZMQ_DEPRECATED(msg) [[deprecated(msg)]] -#elif defined(_MSC_VER) -#define ZMQ_DEPRECATED(msg) __declspec(deprecated(msg)) -#elif defined(__GNUC__) -#define ZMQ_DEPRECATED(msg) __attribute__((deprecated(msg))) -#else -#define ZMQ_DEPRECATED(msg) -#endif - -#if defined(ZMQ_CPP17) -#define ZMQ_NODISCARD [[nodiscard]] -#else -#define ZMQ_NODISCARD -#endif - -#if defined(ZMQ_CPP11) -#define ZMQ_NOTHROW noexcept -#define ZMQ_EXPLICIT explicit -#define ZMQ_OVERRIDE override -#define ZMQ_NULLPTR nullptr -#define ZMQ_CONSTEXPR_FN constexpr -#define ZMQ_CONSTEXPR_VAR constexpr -#define ZMQ_CPP11_DEPRECATED(msg) ZMQ_DEPRECATED(msg) -#else -#define ZMQ_NOTHROW throw() -#define ZMQ_EXPLICIT -#define ZMQ_OVERRIDE -#define ZMQ_NULLPTR 0 -#define ZMQ_CONSTEXPR_FN -#define ZMQ_CONSTEXPR_VAR const -#define ZMQ_CPP11_DEPRECATED(msg) -#endif -#if defined(ZMQ_CPP14) && (!defined(_MSC_VER) || _MSC_VER > 1900) && (!defined(__GNUC__) || __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ > 3)) -#define ZMQ_EXTENDED_CONSTEXPR -#endif -#if defined(ZMQ_CPP17) -#define ZMQ_INLINE_VAR inline -#define ZMQ_CONSTEXPR_IF constexpr -#else -#define ZMQ_INLINE_VAR -#define ZMQ_CONSTEXPR_IF -#endif - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#ifdef ZMQ_CPP11 -#include -#include -#include -#include -#endif - -#if defined(__has_include) && defined(ZMQ_CPP17) -#define CPPZMQ_HAS_INCLUDE_CPP17(X) __has_include(X) -#else -#define CPPZMQ_HAS_INCLUDE_CPP17(X) 0 -#endif - -#if CPPZMQ_HAS_INCLUDE_CPP17() && !defined(CPPZMQ_HAS_OPTIONAL) -#define CPPZMQ_HAS_OPTIONAL 1 -#endif -#ifndef CPPZMQ_HAS_OPTIONAL -#define CPPZMQ_HAS_OPTIONAL 0 -#elif CPPZMQ_HAS_OPTIONAL -#include -#endif - -#if CPPZMQ_HAS_INCLUDE_CPP17() && !defined(CPPZMQ_HAS_STRING_VIEW) -#define CPPZMQ_HAS_STRING_VIEW 1 -#endif -#ifndef CPPZMQ_HAS_STRING_VIEW -#define CPPZMQ_HAS_STRING_VIEW 0 -#elif CPPZMQ_HAS_STRING_VIEW -#include -#endif - -/* Version macros for compile-time API version detection */ -#define CPPZMQ_VERSION_MAJOR 4 -#define CPPZMQ_VERSION_MINOR 11 -#define CPPZMQ_VERSION_PATCH 0 - -#define CPPZMQ_VERSION \ - ZMQ_MAKE_VERSION(CPPZMQ_VERSION_MAJOR, CPPZMQ_VERSION_MINOR, \ - CPPZMQ_VERSION_PATCH) - -// Detect whether the compiler supports C++11 rvalue references. -#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) \ - && defined(__GXX_EXPERIMENTAL_CXX0X__)) -#define ZMQ_HAS_RVALUE_REFS -#define ZMQ_DELETED_FUNCTION = delete -#elif defined(__clang__) -#if __has_feature(cxx_rvalue_references) -#define ZMQ_HAS_RVALUE_REFS -#endif - -#if __has_feature(cxx_deleted_functions) -#define ZMQ_DELETED_FUNCTION = delete -#else -#define ZMQ_DELETED_FUNCTION -#endif -#elif defined(_MSC_VER) && (_MSC_VER >= 1900) -#define ZMQ_HAS_RVALUE_REFS -#define ZMQ_DELETED_FUNCTION = delete -#elif defined(_MSC_VER) && (_MSC_VER >= 1600) -#define ZMQ_HAS_RVALUE_REFS -#define ZMQ_DELETED_FUNCTION -#else -#define ZMQ_DELETED_FUNCTION -#endif - -#if defined(ZMQ_CPP11) && !defined(__llvm__) && !defined(__INTEL_COMPILER) \ - && defined(__GNUC__) && __GNUC__ < 5 -#define ZMQ_CPP11_PARTIAL -#elif defined(__GLIBCXX__) && __GLIBCXX__ < 20160805 -//the date here is the last date of gcc 4.9.4, which -// effectively means libstdc++ from gcc 5.5 and higher won't trigger this branch -#define ZMQ_CPP11_PARTIAL -#endif - -#ifdef ZMQ_CPP11 -#ifdef ZMQ_CPP11_PARTIAL -#define ZMQ_IS_TRIVIALLY_COPYABLE(T) __has_trivial_copy(T) -#else -#include -#define ZMQ_IS_TRIVIALLY_COPYABLE(T) std::is_trivially_copyable::value -#endif -#endif - -#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3, 3, 0) -#define ZMQ_NEW_MONITOR_EVENT_LAYOUT -#endif - -#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 1, 0) -#define ZMQ_HAS_PROXY_STEERABLE -/* Socket event data */ -typedef struct -{ - uint16_t event; // id of the event as bitfield - int32_t value; // value is either error code, fd or reconnect interval -} zmq_event_t; -#endif - -// Avoid using deprecated message receive function when possible -#if ZMQ_VERSION < ZMQ_MAKE_VERSION(3, 2, 0) -#define zmq_msg_recv(msg, socket, flags) zmq_recvmsg(socket, msg, flags) -#endif - - -// In order to prevent unused variable warnings when building in non-debug -// mode use this macro to make assertions. -#ifndef NDEBUG -#define ZMQ_ASSERT(expression) assert(expression) -#else -#define ZMQ_ASSERT(expression) (void) (expression) -#endif - -namespace zmq -{ -#ifdef ZMQ_CPP11 -namespace detail -{ -namespace ranges -{ -using std::begin; -using std::end; -template auto begin(T &&r) -> decltype(begin(std::forward(r))) -{ - return begin(std::forward(r)); -} -template auto end(T &&r) -> decltype(end(std::forward(r))) -{ - return end(std::forward(r)); -} -} // namespace ranges - -template using void_t = void; - -template -using iter_value_t = typename std::iterator_traits::value_type; - -template -using range_iter_t = decltype( - ranges::begin(std::declval::type &>())); - -template using range_value_t = iter_value_t>; - -template struct is_range : std::false_type -{ -}; - -template -struct is_range< - T, - void_t::type &>()) - == ranges::end(std::declval::type &>()))>> - : std::true_type -{ -}; - -} // namespace detail -#endif - -typedef zmq_free_fn free_fn; -typedef zmq_pollitem_t pollitem_t; - -// duplicate definition from libzmq 4.3.3 -#if defined _WIN32 -#if defined _WIN64 -typedef unsigned __int64 fd_t; -#else -typedef unsigned int fd_t; -#endif -#else -typedef int fd_t; -#endif - -class error_t : public std::exception -{ - public: - error_t() ZMQ_NOTHROW : errnum(zmq_errno()) {} - explicit error_t(int err) ZMQ_NOTHROW : errnum(err) {} - virtual const char *what() const ZMQ_NOTHROW ZMQ_OVERRIDE - { - return zmq_strerror(errnum); - } - int num() const ZMQ_NOTHROW { return errnum; } - - private: - int errnum; -}; - -namespace detail { -inline int poll(zmq_pollitem_t *items_, size_t nitems_, long timeout_) -{ - int rc = zmq_poll(items_, static_cast(nitems_), timeout_); - if (rc < 0) - throw error_t(); - return rc; -} -} - -#ifdef ZMQ_CPP11 -ZMQ_DEPRECATED("from 4.8.0, use poll taking std::chrono::duration instead of long") -inline int poll(zmq_pollitem_t *items_, size_t nitems_, long timeout_) -#else -inline int poll(zmq_pollitem_t *items_, size_t nitems_, long timeout_ = -1) -#endif -{ - return detail::poll(items_, nitems_, timeout_); -} - -ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items") -inline int poll(zmq_pollitem_t const *items_, size_t nitems_, long timeout_ = -1) -{ - return detail::poll(const_cast(items_), nitems_, timeout_); -} - -#ifdef ZMQ_CPP11 -ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items") -inline int -poll(zmq_pollitem_t const *items, size_t nitems, std::chrono::milliseconds timeout) -{ - return detail::poll(const_cast(items), nitems, - static_cast(timeout.count())); -} - -ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items") -inline int poll(std::vector const &items, - std::chrono::milliseconds timeout) -{ - return detail::poll(const_cast(items.data()), items.size(), - static_cast(timeout.count())); -} - -ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items") -inline int poll(std::vector const &items, long timeout_ = -1) -{ - return detail::poll(const_cast(items.data()), items.size(), timeout_); -} - -inline int -poll(zmq_pollitem_t *items, size_t nitems, std::chrono::milliseconds timeout = std::chrono::milliseconds{-1}) -{ - return detail::poll(items, nitems, static_cast(timeout.count())); -} - -inline int poll(std::vector &items, - std::chrono::milliseconds timeout = std::chrono::milliseconds{-1}) -{ - return detail::poll(items.data(), items.size(), static_cast(timeout.count())); -} - -ZMQ_DEPRECATED("from 4.3.1, use poll taking std::chrono::duration instead of long") -inline int poll(std::vector &items, long timeout_) -{ - return detail::poll(items.data(), items.size(), timeout_); -} - -template -inline int poll(std::array &items, - std::chrono::milliseconds timeout = std::chrono::milliseconds{-1}) -{ - return detail::poll(items.data(), items.size(), static_cast(timeout.count())); -} -#endif - - -inline void version(int *major_, int *minor_, int *patch_) -{ - zmq_version(major_, minor_, patch_); -} - -#ifdef ZMQ_CPP11 -inline std::tuple version() -{ - std::tuple v; - zmq_version(&std::get<0>(v), &std::get<1>(v), &std::get<2>(v)); - return v; -} - -#if !defined(ZMQ_CPP11_PARTIAL) -namespace detail -{ -template struct is_char_type -{ - // true if character type for string literals in C++11 - static constexpr bool value = - std::is_same::value || std::is_same::value - || std::is_same::value || std::is_same::value; -}; -} -#endif - -#endif - -class message_t -{ - public: - message_t() ZMQ_NOTHROW - { - int rc = zmq_msg_init(&msg); - ZMQ_ASSERT(rc == 0); - } - - explicit message_t(size_t size_) - { - int rc = zmq_msg_init_size(&msg, size_); - if (rc != 0) - throw error_t(); - } - - template message_t(ForwardIter first, ForwardIter last) - { - typedef typename std::iterator_traits::value_type value_t; - - assert(std::distance(first, last) >= 0); - size_t const size_ = - static_cast(std::distance(first, last)) * sizeof(value_t); - int const rc = zmq_msg_init_size(&msg, size_); - if (rc != 0) - throw error_t(); - std::copy(first, last, data()); - } - - message_t(const void *data_, size_t size_) - { - int rc = zmq_msg_init_size(&msg, size_); - if (rc != 0) - throw error_t(); - if (size_) { - // this constructor allows (nullptr, 0), - // memcpy with a null pointer is UB - memcpy(data(), data_, size_); - } - } - - message_t(void *data_, size_t size_, free_fn *ffn_, void *hint_ = ZMQ_NULLPTR) - { - int rc = zmq_msg_init_data(&msg, data_, size_, ffn_, hint_); - if (rc != 0) - throw error_t(); - } - - // overload set of string-like types and generic containers -#if defined(ZMQ_CPP11) && !defined(ZMQ_CPP11_PARTIAL) - // NOTE this constructor will include the null terminator - // when called with a string literal. - // An overload taking const char* can not be added because - // it would be preferred over this function and break compatiblity. - template< - class Char, - size_t N, - typename = typename std::enable_if::value>::type> - ZMQ_DEPRECATED("from 4.7.0, use constructors taking iterators, (pointer, size) " - "or strings instead") - explicit message_t(const Char (&data)[N]) : - message_t(detail::ranges::begin(data), detail::ranges::end(data)) - { - } - - template::value - && ZMQ_IS_TRIVIALLY_COPYABLE(detail::range_value_t) - && !detail::is_char_type>::value - && !std::is_same::value>::type> - explicit message_t(const Range &rng) : - message_t(detail::ranges::begin(rng), detail::ranges::end(rng)) - { - } - - explicit message_t(const std::string &str) : message_t(str.data(), str.size()) {} - -#if CPPZMQ_HAS_STRING_VIEW - explicit message_t(std::string_view str) : message_t(str.data(), str.size()) {} -#endif - -#endif - -#ifdef ZMQ_HAS_RVALUE_REFS - message_t(message_t &&rhs) ZMQ_NOTHROW : msg(rhs.msg) - { - int rc = zmq_msg_init(&rhs.msg); - ZMQ_ASSERT(rc == 0); - } - - message_t &operator=(message_t &&rhs) ZMQ_NOTHROW - { - std::swap(msg, rhs.msg); - return *this; - } -#endif - - ~message_t() ZMQ_NOTHROW - { - int rc = zmq_msg_close(&msg); - ZMQ_ASSERT(rc == 0); - } - - void rebuild() - { - int rc = zmq_msg_close(&msg); - if (rc != 0) - throw error_t(); - rc = zmq_msg_init(&msg); - ZMQ_ASSERT(rc == 0); - } - - void rebuild(size_t size_) - { - int rc = zmq_msg_close(&msg); - if (rc != 0) - throw error_t(); - rc = zmq_msg_init_size(&msg, size_); - if (rc != 0) - throw error_t(); - } - - void rebuild(const void *data_, size_t size_) - { - int rc = zmq_msg_close(&msg); - if (rc != 0) - throw error_t(); - rc = zmq_msg_init_size(&msg, size_); - if (rc != 0) - throw error_t(); - memcpy(data(), data_, size_); - } - - void rebuild(const std::string &str) - { - rebuild(str.data(), str.size()); - } - - void rebuild(void *data_, size_t size_, free_fn *ffn_, void *hint_ = ZMQ_NULLPTR) - { - int rc = zmq_msg_close(&msg); - if (rc != 0) - throw error_t(); - rc = zmq_msg_init_data(&msg, data_, size_, ffn_, hint_); - if (rc != 0) - throw error_t(); - } - - ZMQ_DEPRECATED("from 4.3.1, use move taking non-const reference instead") - void move(message_t const *msg_) - { - int rc = zmq_msg_move(&msg, const_cast(msg_->handle())); - if (rc != 0) - throw error_t(); - } - - void move(message_t &msg_) - { - int rc = zmq_msg_move(&msg, msg_.handle()); - if (rc != 0) - throw error_t(); - } - - ZMQ_DEPRECATED("from 4.3.1, use copy taking non-const reference instead") - void copy(message_t const *msg_) - { - int rc = zmq_msg_copy(&msg, const_cast(msg_->handle())); - if (rc != 0) - throw error_t(); - } - - void copy(message_t &msg_) - { - int rc = zmq_msg_copy(&msg, msg_.handle()); - if (rc != 0) - throw error_t(); - } - - bool more() const ZMQ_NOTHROW - { - int rc = zmq_msg_more(const_cast(&msg)); - return rc != 0; - } - - void *data() ZMQ_NOTHROW { return zmq_msg_data(&msg); } - - const void *data() const ZMQ_NOTHROW - { - return zmq_msg_data(const_cast(&msg)); - } - - size_t size() const ZMQ_NOTHROW - { - return zmq_msg_size(const_cast(&msg)); - } - - ZMQ_NODISCARD bool empty() const ZMQ_NOTHROW { return size() == 0u; } - - template T *data() ZMQ_NOTHROW { return static_cast(data()); } - - template T const *data() const ZMQ_NOTHROW - { - return static_cast(data()); - } - - ZMQ_DEPRECATED("from 4.3.0, use operator== instead") - bool equal(const message_t *other) const ZMQ_NOTHROW { return *this == *other; } - - bool operator==(const message_t &other) const ZMQ_NOTHROW - { - const size_t my_size = size(); - return my_size == other.size() && 0 == memcmp(data(), other.data(), my_size); - } - - bool operator!=(const message_t &other) const ZMQ_NOTHROW - { - return !(*this == other); - } - -#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3, 2, 0) - int get(int property_) - { - int value = zmq_msg_get(&msg, property_); - if (value == -1) - throw error_t(); - return value; - } -#endif - -#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 1, 0) - const char *gets(const char *property_) - { - const char *value = zmq_msg_gets(&msg, property_); - if (value == ZMQ_NULLPTR) - throw error_t(); - return value; - } -#endif - -#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0) - uint32_t routing_id() const - { - return zmq_msg_routing_id(const_cast(&msg)); - } - - void set_routing_id(uint32_t routing_id) - { - int rc = zmq_msg_set_routing_id(&msg, routing_id); - if (rc != 0) - throw error_t(); - } - - const char *group() const - { - return zmq_msg_group(const_cast(&msg)); - } - - void set_group(const char *group) - { - int rc = zmq_msg_set_group(&msg, group); - if (rc != 0) - throw error_t(); - } -#endif - - // interpret message content as a string - std::string to_string() const - { - return std::string(static_cast(data()), size()); - } -#if CPPZMQ_HAS_STRING_VIEW - // interpret message content as a string - std::string_view to_string_view() const noexcept - { - return std::string_view(static_cast(data()), size()); - } -#endif - - /** Dump content to string for debugging. - * Ascii chars are readable, the rest is printed as hex. - * Probably ridiculously slow. - * Use to_string() or to_string_view() for - * interpreting the message as a string. - */ - std::string str(size_t max_size = 1000) const - { - // Partly mutuated from the same method in zmq::multipart_t - std::stringstream os; - - const unsigned char *msg_data = this->data(); - size_t size_to_print = (std::min)(this->size(), max_size); - int is_ascii[2] = {0, 0}; - // Set is_ascii for the first character - if (size_to_print > 0) - is_ascii[0] = (*msg_data >= 32 && *msg_data < 127); - - os << "zmq::message_t [size " << std::dec << std::setw(3) - << std::setfill('0') << this->size() << "] ("; - while (size_to_print--) { - const unsigned char byte = *msg_data++; - - is_ascii[1] = (byte >= 32 && byte < 127); - if (is_ascii[1] != is_ascii[0]) - os << " "; // Separate text/non text - - if (is_ascii[1]) { - os << byte; - } else { - os << std::hex << std::uppercase << std::setw(2) << std::setfill('0') - << static_cast(byte); - } - is_ascii[0] = is_ascii[1]; - } - // Elide the rest if the message is too large - if (max_size < this->size()) - os << "... too big to print)"; - else - os << ")"; - return os.str(); - } - - void swap(message_t &other) ZMQ_NOTHROW - { - // this assumes zmq::msg_t from libzmq is trivially relocatable - std::swap(msg, other.msg); - } - - ZMQ_NODISCARD zmq_msg_t *handle() ZMQ_NOTHROW { return &msg; } - ZMQ_NODISCARD const zmq_msg_t *handle() const ZMQ_NOTHROW { return &msg; } - - private: - // The underlying message - zmq_msg_t msg; - - // Disable implicit message copying, so that users won't use shared - // messages (less efficient) without being aware of the fact. - message_t(const message_t &) ZMQ_DELETED_FUNCTION; - void operator=(const message_t &) ZMQ_DELETED_FUNCTION; -}; - -inline void swap(message_t &a, message_t &b) ZMQ_NOTHROW -{ - a.swap(b); -} - -#ifdef ZMQ_CPP11 -enum class ctxopt -{ -#ifdef ZMQ_BLOCKY - blocky = ZMQ_BLOCKY, -#endif -#ifdef ZMQ_IO_THREADS - io_threads = ZMQ_IO_THREADS, -#endif -#ifdef ZMQ_THREAD_SCHED_POLICY - thread_sched_policy = ZMQ_THREAD_SCHED_POLICY, -#endif -#ifdef ZMQ_THREAD_PRIORITY - thread_priority = ZMQ_THREAD_PRIORITY, -#endif -#ifdef ZMQ_THREAD_AFFINITY_CPU_ADD - thread_affinity_cpu_add = ZMQ_THREAD_AFFINITY_CPU_ADD, -#endif -#ifdef ZMQ_THREAD_AFFINITY_CPU_REMOVE - thread_affinity_cpu_remove = ZMQ_THREAD_AFFINITY_CPU_REMOVE, -#endif -#ifdef ZMQ_THREAD_NAME_PREFIX - thread_name_prefix = ZMQ_THREAD_NAME_PREFIX, -#endif -#ifdef ZMQ_MAX_MSGSZ - max_msgsz = ZMQ_MAX_MSGSZ, -#endif -#ifdef ZMQ_ZERO_COPY_RECV - zero_copy_recv = ZMQ_ZERO_COPY_RECV, -#endif -#ifdef ZMQ_MAX_SOCKETS - max_sockets = ZMQ_MAX_SOCKETS, -#endif -#ifdef ZMQ_SOCKET_LIMIT - socket_limit = ZMQ_SOCKET_LIMIT, -#endif -#ifdef ZMQ_IPV6 - ipv6 = ZMQ_IPV6, -#endif -#ifdef ZMQ_MSG_T_SIZE - msg_t_size = ZMQ_MSG_T_SIZE -#endif -}; -#endif - -class context_t -{ - public: - context_t() - { - ptr = zmq_ctx_new(); - if (ptr == ZMQ_NULLPTR) - throw error_t(); - } - - - explicit context_t(int io_threads_, int max_sockets_ = ZMQ_MAX_SOCKETS_DFLT) - { - ptr = zmq_ctx_new(); - if (ptr == ZMQ_NULLPTR) - throw error_t(); - - int rc = zmq_ctx_set(ptr, ZMQ_IO_THREADS, io_threads_); - ZMQ_ASSERT(rc == 0); - - rc = zmq_ctx_set(ptr, ZMQ_MAX_SOCKETS, max_sockets_); - ZMQ_ASSERT(rc == 0); - } - -#ifdef ZMQ_HAS_RVALUE_REFS - context_t(context_t &&rhs) ZMQ_NOTHROW : ptr(rhs.ptr) { rhs.ptr = ZMQ_NULLPTR; } - context_t &operator=(context_t &&rhs) ZMQ_NOTHROW - { - close(); - std::swap(ptr, rhs.ptr); - return *this; - } -#endif - - ~context_t() ZMQ_NOTHROW { close(); } - - ZMQ_CPP11_DEPRECATED("from 4.7.0, use set taking zmq::ctxopt instead") - int setctxopt(int option_, int optval_) - { - int rc = zmq_ctx_set(ptr, option_, optval_); - ZMQ_ASSERT(rc == 0); - return rc; - } - - ZMQ_CPP11_DEPRECATED("from 4.7.0, use get taking zmq::ctxopt instead") - int getctxopt(int option_) { return zmq_ctx_get(ptr, option_); } - -#ifdef ZMQ_CPP11 - void set(ctxopt option, int optval) - { - int rc = zmq_ctx_set(ptr, static_cast(option), optval); - if (rc == -1) - throw error_t(); - } - - ZMQ_NODISCARD int get(ctxopt option) - { - int rc = zmq_ctx_get(ptr, static_cast(option)); - // some options have a default value of -1 - // which is unfortunate, and may result in errors - // that don't make sense - if (rc == -1) - throw error_t(); - return rc; - } -#endif - - // Terminates context (see also shutdown()). - void close() ZMQ_NOTHROW - { - if (ptr == ZMQ_NULLPTR) - return; - - int rc; - do { - rc = zmq_ctx_term(ptr); - } while (rc == -1 && errno == EINTR); - - ZMQ_ASSERT(rc == 0); - ptr = ZMQ_NULLPTR; - } - - // Shutdown context in preparation for termination (close()). - // Causes all blocking socket operations and any further - // socket operations to return with ETERM. - void shutdown() ZMQ_NOTHROW - { - if (ptr == ZMQ_NULLPTR) - return; - int rc = zmq_ctx_shutdown(ptr); - ZMQ_ASSERT(rc == 0); - } - - // Be careful with this, it's probably only useful for - // using the C api together with an existing C++ api. - // Normally you should never need to use this. - ZMQ_EXPLICIT operator void *() ZMQ_NOTHROW { return ptr; } - - ZMQ_EXPLICIT operator void const *() const ZMQ_NOTHROW { return ptr; } - - ZMQ_NODISCARD void *handle() ZMQ_NOTHROW { return ptr; } - - ZMQ_DEPRECATED("from 4.7.0, use handle() != nullptr instead") - operator bool() const ZMQ_NOTHROW { return ptr != ZMQ_NULLPTR; } - - void swap(context_t &other) ZMQ_NOTHROW { std::swap(ptr, other.ptr); } - - private: - void *ptr; - - context_t(const context_t &) ZMQ_DELETED_FUNCTION; - void operator=(const context_t &) ZMQ_DELETED_FUNCTION; -}; - -inline void swap(context_t &a, context_t &b) ZMQ_NOTHROW -{ - a.swap(b); -} - -#ifdef ZMQ_CPP11 - -struct recv_buffer_size -{ - size_t size; // number of bytes written to buffer - size_t untruncated_size; // untruncated message size in bytes - - ZMQ_NODISCARD bool truncated() const noexcept - { - return size != untruncated_size; - } -}; - -#if CPPZMQ_HAS_OPTIONAL - -using send_result_t = std::optional; -using recv_result_t = std::optional; -using recv_buffer_result_t = std::optional; - -#else - -namespace detail -{ -// A C++11 type emulating the most basic -// operations of std::optional for trivial types -template class trivial_optional -{ - public: - static_assert(std::is_trivial::value, "T must be trivial"); - using value_type = T; - - trivial_optional() = default; - trivial_optional(T value) noexcept : _value(value), _has_value(true) {} - - const T *operator->() const noexcept - { - assert(_has_value); - return &_value; - } - T *operator->() noexcept - { - assert(_has_value); - return &_value; - } - - const T &operator*() const noexcept - { - assert(_has_value); - return _value; - } - T &operator*() noexcept - { - assert(_has_value); - return _value; - } - - T &value() - { - if (!_has_value) - throw std::exception(); - return _value; - } - const T &value() const - { - if (!_has_value) - throw std::exception(); - return _value; - } - - explicit operator bool() const noexcept { return _has_value; } - bool has_value() const noexcept { return _has_value; } - - private: - T _value{}; - bool _has_value{false}; -}; -} // namespace detail - -using send_result_t = detail::trivial_optional; -using recv_result_t = detail::trivial_optional; -using recv_buffer_result_t = detail::trivial_optional; - -#endif - -namespace detail -{ -template constexpr T enum_bit_or(T a, T b) noexcept -{ - static_assert(std::is_enum::value, "must be enum"); - using U = typename std::underlying_type::type; - return static_cast(static_cast(a) | static_cast(b)); -} -template constexpr T enum_bit_and(T a, T b) noexcept -{ - static_assert(std::is_enum::value, "must be enum"); - using U = typename std::underlying_type::type; - return static_cast(static_cast(a) & static_cast(b)); -} -template constexpr T enum_bit_xor(T a, T b) noexcept -{ - static_assert(std::is_enum::value, "must be enum"); - using U = typename std::underlying_type::type; - return static_cast(static_cast(a) ^ static_cast(b)); -} -template constexpr T enum_bit_not(T a) noexcept -{ - static_assert(std::is_enum::value, "must be enum"); - using U = typename std::underlying_type::type; - return static_cast(~static_cast(a)); -} -} // namespace detail - -// partially satisfies named requirement BitmaskType -enum class send_flags : int -{ - none = 0, - dontwait = ZMQ_DONTWAIT, - sndmore = ZMQ_SNDMORE -}; - -constexpr send_flags operator|(send_flags a, send_flags b) noexcept -{ - return detail::enum_bit_or(a, b); -} -constexpr send_flags operator&(send_flags a, send_flags b) noexcept -{ - return detail::enum_bit_and(a, b); -} -constexpr send_flags operator^(send_flags a, send_flags b) noexcept -{ - return detail::enum_bit_xor(a, b); -} -constexpr send_flags operator~(send_flags a) noexcept -{ - return detail::enum_bit_not(a); -} - -// partially satisfies named requirement BitmaskType -enum class recv_flags : int -{ - none = 0, - dontwait = ZMQ_DONTWAIT -}; - -constexpr recv_flags operator|(recv_flags a, recv_flags b) noexcept -{ - return detail::enum_bit_or(a, b); -} -constexpr recv_flags operator&(recv_flags a, recv_flags b) noexcept -{ - return detail::enum_bit_and(a, b); -} -constexpr recv_flags operator^(recv_flags a, recv_flags b) noexcept -{ - return detail::enum_bit_xor(a, b); -} -constexpr recv_flags operator~(recv_flags a) noexcept -{ - return detail::enum_bit_not(a); -} - - -// mutable_buffer, const_buffer and buffer are based on -// the Networking TS specification, draft: -// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/n4771.pdf - -class mutable_buffer -{ - public: - constexpr mutable_buffer() noexcept : _data(nullptr), _size(0) {} - constexpr mutable_buffer(void *p, size_t n) noexcept : _data(p), _size(n) - { -#ifdef ZMQ_EXTENDED_CONSTEXPR - assert(p != nullptr || n == 0); -#endif - } - - constexpr void *data() const noexcept { return _data; } - constexpr size_t size() const noexcept { return _size; } - mutable_buffer &operator+=(size_t n) noexcept - { - // (std::min) is a workaround for when a min macro is defined - const auto shift = (std::min)(n, _size); - _data = static_cast(_data) + shift; - _size -= shift; - return *this; - } - - private: - void *_data; - size_t _size; -}; - -inline mutable_buffer operator+(const mutable_buffer &mb, size_t n) noexcept -{ - return mutable_buffer(static_cast(mb.data()) + (std::min)(n, mb.size()), - mb.size() - (std::min)(n, mb.size())); -} -inline mutable_buffer operator+(size_t n, const mutable_buffer &mb) noexcept -{ - return mb + n; -} - -class const_buffer -{ - public: - constexpr const_buffer() noexcept : _data(nullptr), _size(0) {} - constexpr const_buffer(const void *p, size_t n) noexcept : _data(p), _size(n) - { -#ifdef ZMQ_EXTENDED_CONSTEXPR - assert(p != nullptr || n == 0); -#endif - } - constexpr const_buffer(const mutable_buffer &mb) noexcept : - _data(mb.data()), _size(mb.size()) - { - } - - constexpr const void *data() const noexcept { return _data; } - constexpr size_t size() const noexcept { return _size; } - const_buffer &operator+=(size_t n) noexcept - { - const auto shift = (std::min)(n, _size); - _data = static_cast(_data) + shift; - _size -= shift; - return *this; - } - - private: - const void *_data; - size_t _size; -}; - -inline const_buffer operator+(const const_buffer &cb, size_t n) noexcept -{ - return const_buffer(static_cast(cb.data()) - + (std::min)(n, cb.size()), - cb.size() - (std::min)(n, cb.size())); -} -inline const_buffer operator+(size_t n, const const_buffer &cb) noexcept -{ - return cb + n; -} - -// buffer creation - -constexpr mutable_buffer buffer(void *p, size_t n) noexcept -{ - return mutable_buffer(p, n); -} -constexpr const_buffer buffer(const void *p, size_t n) noexcept -{ - return const_buffer(p, n); -} -constexpr mutable_buffer buffer(const mutable_buffer &mb) noexcept -{ - return mb; -} -inline mutable_buffer buffer(const mutable_buffer &mb, size_t n) noexcept -{ - return mutable_buffer(mb.data(), (std::min)(mb.size(), n)); -} -constexpr const_buffer buffer(const const_buffer &cb) noexcept -{ - return cb; -} -inline const_buffer buffer(const const_buffer &cb, size_t n) noexcept -{ - return const_buffer(cb.data(), (std::min)(cb.size(), n)); -} - -namespace detail -{ -template struct is_buffer -{ - static constexpr bool value = - std::is_same::value || std::is_same::value; -}; - -template struct is_pod_like -{ - // NOTE: The networking draft N4771 section 16.11 requires - // T in the buffer functions below to be - // trivially copyable OR standard layout. - // Here we decide to be conservative and require both. - static constexpr bool value = - ZMQ_IS_TRIVIALLY_COPYABLE(T) && std::is_standard_layout::value; -}; - -template constexpr auto seq_size(const C &c) noexcept -> decltype(c.size()) -{ - return c.size(); -} -template -constexpr size_t seq_size(const T (&/*array*/)[N]) noexcept -{ - return N; -} - -template -auto buffer_contiguous_sequence(Seq &&seq) noexcept - -> decltype(buffer(std::addressof(*std::begin(seq)), size_t{})) -{ - using T = typename std::remove_cv< - typename std::remove_reference::type>::type; - static_assert(detail::is_pod_like::value, "T must be POD"); - - const auto size = seq_size(seq); - return buffer(size != 0u ? std::addressof(*std::begin(seq)) : nullptr, - size * sizeof(T)); -} -template -auto buffer_contiguous_sequence(Seq &&seq, size_t n_bytes) noexcept - -> decltype(buffer_contiguous_sequence(seq)) -{ - using T = typename std::remove_cv< - typename std::remove_reference::type>::type; - static_assert(detail::is_pod_like::value, "T must be POD"); - - const auto size = seq_size(seq); - return buffer(size != 0u ? std::addressof(*std::begin(seq)) : nullptr, - (std::min)(size * sizeof(T), n_bytes)); -} - -} // namespace detail - -// C array -template mutable_buffer buffer(T (&data)[N]) noexcept -{ - return detail::buffer_contiguous_sequence(data); -} -template -mutable_buffer buffer(T (&data)[N], size_t n_bytes) noexcept -{ - return detail::buffer_contiguous_sequence(data, n_bytes); -} -template const_buffer buffer(const T (&data)[N]) noexcept -{ - return detail::buffer_contiguous_sequence(data); -} -template -const_buffer buffer(const T (&data)[N], size_t n_bytes) noexcept -{ - return detail::buffer_contiguous_sequence(data, n_bytes); -} -// std::array -template mutable_buffer buffer(std::array &data) noexcept -{ - return detail::buffer_contiguous_sequence(data); -} -template -mutable_buffer buffer(std::array &data, size_t n_bytes) noexcept -{ - return detail::buffer_contiguous_sequence(data, n_bytes); -} -template -const_buffer buffer(std::array &data) noexcept -{ - return detail::buffer_contiguous_sequence(data); -} -template -const_buffer buffer(std::array &data, size_t n_bytes) noexcept -{ - return detail::buffer_contiguous_sequence(data, n_bytes); -} -template -const_buffer buffer(const std::array &data) noexcept -{ - return detail::buffer_contiguous_sequence(data); -} -template -const_buffer buffer(const std::array &data, size_t n_bytes) noexcept -{ - return detail::buffer_contiguous_sequence(data, n_bytes); -} -// std::vector -template -mutable_buffer buffer(std::vector &data) noexcept -{ - return detail::buffer_contiguous_sequence(data); -} -template -mutable_buffer buffer(std::vector &data, size_t n_bytes) noexcept -{ - return detail::buffer_contiguous_sequence(data, n_bytes); -} -template -const_buffer buffer(const std::vector &data) noexcept -{ - return detail::buffer_contiguous_sequence(data); -} -template -const_buffer buffer(const std::vector &data, size_t n_bytes) noexcept -{ - return detail::buffer_contiguous_sequence(data, n_bytes); -} -// std::basic_string -template -mutable_buffer buffer(std::basic_string &data) noexcept -{ - return detail::buffer_contiguous_sequence(data); -} -template -mutable_buffer buffer(std::basic_string &data, - size_t n_bytes) noexcept -{ - return detail::buffer_contiguous_sequence(data, n_bytes); -} -template -const_buffer buffer(const std::basic_string &data) noexcept -{ - return detail::buffer_contiguous_sequence(data); -} -template -const_buffer buffer(const std::basic_string &data, - size_t n_bytes) noexcept -{ - return detail::buffer_contiguous_sequence(data, n_bytes); -} - -#if CPPZMQ_HAS_STRING_VIEW -// std::basic_string_view -template -const_buffer buffer(std::basic_string_view data) noexcept -{ - return detail::buffer_contiguous_sequence(data); -} -template -const_buffer buffer(std::basic_string_view data, size_t n_bytes) noexcept -{ - return detail::buffer_contiguous_sequence(data, n_bytes); -} -#endif - -// Buffer for a string literal (null terminated) -// where the buffer size excludes the terminating character. -// Equivalent to zmq::buffer(std::string_view("...")). -template -constexpr const_buffer str_buffer(const Char (&data)[N]) noexcept -{ - static_assert(detail::is_pod_like::value, "Char must be POD"); -#ifdef ZMQ_EXTENDED_CONSTEXPR - assert(data[N - 1] == Char{0}); -#endif - return const_buffer(static_cast(data), (N - 1) * sizeof(Char)); -} - -namespace literals -{ -constexpr const_buffer operator""_zbuf(const char *str, size_t len) noexcept -{ - return const_buffer(str, len * sizeof(char)); -} -constexpr const_buffer operator""_zbuf(const wchar_t *str, size_t len) noexcept -{ - return const_buffer(str, len * sizeof(wchar_t)); -} -constexpr const_buffer operator""_zbuf(const char16_t *str, size_t len) noexcept -{ - return const_buffer(str, len * sizeof(char16_t)); -} -constexpr const_buffer operator""_zbuf(const char32_t *str, size_t len) noexcept -{ - return const_buffer(str, len * sizeof(char32_t)); -} -} - -#ifdef ZMQ_CPP11 -enum class socket_type : int -{ - req = ZMQ_REQ, - rep = ZMQ_REP, - dealer = ZMQ_DEALER, - router = ZMQ_ROUTER, - pub = ZMQ_PUB, - sub = ZMQ_SUB, - xpub = ZMQ_XPUB, - xsub = ZMQ_XSUB, - push = ZMQ_PUSH, - pull = ZMQ_PULL, -#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0) - server = ZMQ_SERVER, - client = ZMQ_CLIENT, - radio = ZMQ_RADIO, - dish = ZMQ_DISH, - gather = ZMQ_GATHER, - scatter = ZMQ_SCATTER, - dgram = ZMQ_DGRAM, -#endif -#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 3) - peer = ZMQ_PEER, - channel = ZMQ_CHANNEL, -#endif -#if ZMQ_VERSION_MAJOR >= 4 - stream = ZMQ_STREAM, -#endif - pair = ZMQ_PAIR -}; -#endif - -namespace sockopt -{ -// There are two types of options, -// integral type with known compiler time size (int, bool, int64_t, uint64_t) -// and arrays with dynamic size (strings, binary data). - -// BoolUnit: if true accepts values of type bool (but passed as T into libzmq) -template struct integral_option -{ -}; - -// NullTerm: -// 0: binary data -// 1: null-terminated string (`getsockopt` size includes null) -// 2: binary (size 32) or Z85 encoder string of size 41 (null included) -template struct array_option -{ -}; - -#define ZMQ_DEFINE_INTEGRAL_OPT(OPT, NAME, TYPE) \ - using NAME##_t = integral_option; \ - ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} -#define ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(OPT, NAME, TYPE) \ - using NAME##_t = integral_option; \ - ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} -#define ZMQ_DEFINE_ARRAY_OPT(OPT, NAME) \ - using NAME##_t = array_option; \ - ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} -#define ZMQ_DEFINE_ARRAY_OPT_BINARY(OPT, NAME) \ - using NAME##_t = array_option; \ - ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} -#define ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(OPT, NAME) \ - using NAME##_t = array_option; \ - ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} - -// deprecated, use zmq::fd_t -using cppzmq_fd_t = ::zmq::fd_t; - -#ifdef ZMQ_AFFINITY -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_AFFINITY, affinity, uint64_t); -#endif -#ifdef ZMQ_BACKLOG -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_BACKLOG, backlog, int); -#endif -#ifdef ZMQ_BINDTODEVICE -ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_BINDTODEVICE, bindtodevice); -#endif -#ifdef ZMQ_BUSY_POLL -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_BUSY_POLL, busy_poll, int); -#endif -#ifdef ZMQ_CONFLATE -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_CONFLATE, conflate, int); -#endif -#ifdef ZMQ_CONNECT_ROUTING_ID -ZMQ_DEFINE_ARRAY_OPT(ZMQ_CONNECT_ROUTING_ID, connect_routing_id); -#endif -#ifdef ZMQ_CONNECT_TIMEOUT -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_CONNECT_TIMEOUT, connect_timeout, int); -#endif -#ifdef ZMQ_CURVE_PUBLICKEY -ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_PUBLICKEY, curve_publickey); -#endif -#ifdef ZMQ_CURVE_SECRETKEY -ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_SECRETKEY, curve_secretkey); -#endif -#ifdef ZMQ_CURVE_SERVER -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_CURVE_SERVER, curve_server, int); -#endif -#ifdef ZMQ_CURVE_SERVERKEY -ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_SERVERKEY, curve_serverkey); -#endif -#ifdef ZMQ_DISCONNECT_MSG -ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_DISCONNECT_MSG, disconnect_msg); -#endif -#ifdef ZMQ_EVENTS -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_EVENTS, events, int); -#endif -#ifdef ZMQ_FD -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_FD, fd, ::zmq::fd_t); -#endif -#ifdef ZMQ_GSSAPI_PLAINTEXT -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_GSSAPI_PLAINTEXT, gssapi_plaintext, int); -#endif -#ifdef ZMQ_GSSAPI_SERVER -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_GSSAPI_SERVER, gssapi_server, int); -#endif -#ifdef ZMQ_GSSAPI_SERVICE_PRINCIPAL -ZMQ_DEFINE_ARRAY_OPT(ZMQ_GSSAPI_SERVICE_PRINCIPAL, gssapi_service_principal); -#endif -#ifdef ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE, - gssapi_service_principal_nametype, - int); -#endif -#ifdef ZMQ_GSSAPI_PRINCIPAL -ZMQ_DEFINE_ARRAY_OPT(ZMQ_GSSAPI_PRINCIPAL, gssapi_principal); -#endif -#ifdef ZMQ_GSSAPI_PRINCIPAL_NAMETYPE -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_GSSAPI_PRINCIPAL_NAMETYPE, - gssapi_principal_nametype, - int); -#endif -#ifdef ZMQ_HANDSHAKE_IVL -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HANDSHAKE_IVL, handshake_ivl, int); -#endif -#ifdef ZMQ_HEARTBEAT_IVL -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_IVL, heartbeat_ivl, int); -#endif -#ifdef ZMQ_HEARTBEAT_TIMEOUT -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_TIMEOUT, heartbeat_timeout, int); -#endif -#ifdef ZMQ_HEARTBEAT_TTL -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_TTL, heartbeat_ttl, int); -#endif -#ifdef ZMQ_HELLO_MSG -ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_HELLO_MSG, hello_msg); -#endif -#ifdef ZMQ_IMMEDIATE -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_IMMEDIATE, immediate, int); -#endif -#ifdef ZMQ_INVERT_MATCHING -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_INVERT_MATCHING, invert_matching, int); -#endif -#ifdef ZMQ_IPV6 -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_IPV6, ipv6, int); -#endif -#ifdef ZMQ_LAST_ENDPOINT -ZMQ_DEFINE_ARRAY_OPT(ZMQ_LAST_ENDPOINT, last_endpoint); -#endif -#ifdef ZMQ_LINGER -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_LINGER, linger, int); -#endif -#ifdef ZMQ_MAXMSGSIZE -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MAXMSGSIZE, maxmsgsize, int64_t); -#endif -#ifdef ZMQ_MECHANISM -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MECHANISM, mechanism, int); -#endif -#ifdef ZMQ_METADATA -ZMQ_DEFINE_ARRAY_OPT(ZMQ_METADATA, metadata); -#endif -#ifdef ZMQ_MULTICAST_HOPS -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MULTICAST_HOPS, multicast_hops, int); -#endif -#ifdef ZMQ_MULTICAST_LOOP -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_MULTICAST_LOOP, multicast_loop, int); -#endif -#ifdef ZMQ_MULTICAST_MAXTPDU -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MULTICAST_MAXTPDU, multicast_maxtpdu, int); -#endif -#ifdef ZMQ_ONLY_FIRST_SUBSCRIBE -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ONLY_FIRST_SUBSCRIBE, only_first_subscribe, int); -#endif -#ifdef ZMQ_PLAIN_SERVER -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_PLAIN_SERVER, plain_server, int); -#endif -#ifdef ZMQ_PLAIN_PASSWORD -ZMQ_DEFINE_ARRAY_OPT(ZMQ_PLAIN_PASSWORD, plain_password); -#endif -#ifdef ZMQ_PLAIN_USERNAME -ZMQ_DEFINE_ARRAY_OPT(ZMQ_PLAIN_USERNAME, plain_username); -#endif -#ifdef ZMQ_PRIORITY -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_PRIORITY, priority, int); -#endif -#ifdef ZMQ_USE_FD -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_USE_FD, use_fd, int); -#endif -#ifdef ZMQ_PROBE_ROUTER -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_PROBE_ROUTER, probe_router, int); -#endif -#ifdef ZMQ_RATE -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RATE, rate, int); -#endif -#ifdef ZMQ_RCVBUF -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RCVBUF, rcvbuf, int); -#endif -#ifdef ZMQ_RCVHWM -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RCVHWM, rcvhwm, int); -#endif -#ifdef ZMQ_RCVMORE -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_RCVMORE, rcvmore, int); -#endif -#ifdef ZMQ_RCVTIMEO -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RCVTIMEO, rcvtimeo, int); -#endif -#ifdef ZMQ_RECONNECT_IVL -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_IVL, reconnect_ivl, int); -#endif -#ifdef ZMQ_RECONNECT_IVL_MAX -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_IVL_MAX, reconnect_ivl_max, int); -#endif -#ifdef ZMQ_RECONNECT_STOP -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_STOP, reconnect_stop, int); -#endif -#ifdef ZMQ_RECOVERY_IVL -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECOVERY_IVL, recovery_ivl, int); -#endif -#ifdef ZMQ_REQ_CORRELATE -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_REQ_CORRELATE, req_correlate, int); -#endif -#ifdef ZMQ_REQ_RELAXED -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_REQ_RELAXED, req_relaxed, int); -#endif -#ifdef ZMQ_ROUTER_HANDOVER -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ROUTER_HANDOVER, router_handover, int); -#endif -#ifdef ZMQ_ROUTER_MANDATORY -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ROUTER_MANDATORY, router_mandatory, int); -#endif -#ifdef ZMQ_ROUTER_NOTIFY -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_ROUTER_NOTIFY, router_notify, int); -#endif -#ifdef ZMQ_ROUTER_RAW -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_ROUTER_RAW, router_raw, int); -#endif -#ifdef ZMQ_ROUTING_ID -ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_ROUTING_ID, routing_id); -#endif -#ifdef ZMQ_SNDBUF -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDBUF, sndbuf, int); -#endif -#ifdef ZMQ_SNDHWM -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDHWM, sndhwm, int); -#endif -#ifdef ZMQ_SNDTIMEO -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDTIMEO, sndtimeo, int); -#endif -#ifdef ZMQ_SOCKS_PASSWORD -ZMQ_DEFINE_ARRAY_OPT(ZMQ_SOCKS_PASSWORD, socks_password); -#endif -#ifdef ZMQ_SOCKS_PROXY -ZMQ_DEFINE_ARRAY_OPT(ZMQ_SOCKS_PROXY, socks_proxy); -#endif -#ifdef ZMQ_SOCKS_USERNAME -ZMQ_DEFINE_ARRAY_OPT(ZMQ_SOCKS_USERNAME, socks_username); -#endif -#ifdef ZMQ_STREAM_NOTIFY -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_STREAM_NOTIFY, stream_notify, int); -#endif -#ifdef ZMQ_SUBSCRIBE -ZMQ_DEFINE_ARRAY_OPT(ZMQ_SUBSCRIBE, subscribe); -#endif -#ifdef ZMQ_TCP_KEEPALIVE -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE, tcp_keepalive, int); -#endif -#ifdef ZMQ_TCP_KEEPALIVE_CNT -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE_CNT, tcp_keepalive_cnt, int); -#endif -#ifdef ZMQ_TCP_KEEPALIVE_IDLE -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE_IDLE, tcp_keepalive_idle, int); -#endif -#ifdef ZMQ_TCP_KEEPALIVE_INTVL -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE_INTVL, tcp_keepalive_intvl, int); -#endif -#ifdef ZMQ_TCP_MAXRT -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_MAXRT, tcp_maxrt, int); -#endif -#ifdef ZMQ_THREAD_SAFE -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_THREAD_SAFE, thread_safe, int); -#endif -#ifdef ZMQ_TOS -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TOS, tos, int); -#endif -#ifdef ZMQ_TYPE -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TYPE, type, int); -#ifdef ZMQ_CPP11 -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TYPE, socket_type, socket_type); -#endif // ZMQ_CPP11 -#endif // ZMQ_TYPE -#ifdef ZMQ_UNSUBSCRIBE -ZMQ_DEFINE_ARRAY_OPT(ZMQ_UNSUBSCRIBE, unsubscribe); -#endif -#ifdef ZMQ_VMCI_BUFFER_SIZE -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_BUFFER_SIZE, vmci_buffer_size, uint64_t); -#endif -#ifdef ZMQ_VMCI_BUFFER_MIN_SIZE -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_BUFFER_MIN_SIZE, vmci_buffer_min_size, uint64_t); -#endif -#ifdef ZMQ_VMCI_BUFFER_MAX_SIZE -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_BUFFER_MAX_SIZE, vmci_buffer_max_size, uint64_t); -#endif -#ifdef ZMQ_VMCI_CONNECT_TIMEOUT -ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_CONNECT_TIMEOUT, vmci_connect_timeout, int); -#endif -#ifdef ZMQ_XPUB_VERBOSE -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_VERBOSE, xpub_verbose, int); -#endif -#ifdef ZMQ_XPUB_VERBOSER -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_VERBOSER, xpub_verboser, int); -#endif -#ifdef ZMQ_XPUB_MANUAL -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_MANUAL, xpub_manual, int); -#endif -#ifdef ZMQ_XPUB_MANUAL_LAST_VALUE -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_MANUAL_LAST_VALUE, xpub_manual_last_value, int); -#endif -#ifdef ZMQ_XPUB_NODROP -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_NODROP, xpub_nodrop, int); -#endif -#ifdef ZMQ_XPUB_WELCOME_MSG -ZMQ_DEFINE_ARRAY_OPT(ZMQ_XPUB_WELCOME_MSG, xpub_welcome_msg); -#endif -#ifdef ZMQ_ZAP_ENFORCE_DOMAIN -ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ZAP_ENFORCE_DOMAIN, zap_enforce_domain, int); -#endif -#ifdef ZMQ_ZAP_DOMAIN -ZMQ_DEFINE_ARRAY_OPT(ZMQ_ZAP_DOMAIN, zap_domain); -#endif - -} // namespace sockopt -#endif // ZMQ_CPP11 - - -namespace detail -{ -class socket_base -{ - public: - socket_base() ZMQ_NOTHROW : _handle(ZMQ_NULLPTR) {} - ZMQ_EXPLICIT socket_base(void *handle) ZMQ_NOTHROW : _handle(handle) {} - - template - ZMQ_CPP11_DEPRECATED("from 4.7.0, use `set` taking option from zmq::sockopt") - void setsockopt(int option_, T const &optval) - { - setsockopt(option_, &optval, sizeof(T)); - } - - ZMQ_CPP11_DEPRECATED("from 4.7.0, use `set` taking option from zmq::sockopt") - void setsockopt(int option_, const void *optval_, size_t optvallen_) - { - int rc = zmq_setsockopt(_handle, option_, optval_, optvallen_); - if (rc != 0) - throw error_t(); - } - - ZMQ_CPP11_DEPRECATED("from 4.7.0, use `get` taking option from zmq::sockopt") - void getsockopt(int option_, void *optval_, size_t *optvallen_) const - { - int rc = zmq_getsockopt(_handle, option_, optval_, optvallen_); - if (rc != 0) - throw error_t(); - } - - template - ZMQ_CPP11_DEPRECATED("from 4.7.0, use `get` taking option from zmq::sockopt") - T getsockopt(int option_) const - { - T optval; - size_t optlen = sizeof(T); - getsockopt(option_, &optval, &optlen); - return optval; - } - -#ifdef ZMQ_CPP11 - // Set integral socket option, e.g. - // `socket.set(zmq::sockopt::linger, 0)` - template - void set(sockopt::integral_option, const T &val) - { - static_assert(std::is_integral::value, "T must be integral"); - set_option(Opt, &val, sizeof val); - } - - // Set integral socket option from boolean, e.g. - // `socket.set(zmq::sockopt::immediate, false)` - template - void set(sockopt::integral_option, bool val) - { - static_assert(std::is_integral::value, "T must be integral"); - T rep_val = val; - set_option(Opt, &rep_val, sizeof rep_val); - } - - // Set array socket option, e.g. - // `socket.set(zmq::sockopt::plain_username, "foo123")` - template - void set(sockopt::array_option, const char *buf) - { - set_option(Opt, buf, std::strlen(buf)); - } - - // Set array socket option, e.g. - // `socket.set(zmq::sockopt::routing_id, zmq::buffer(id))` - template - void set(sockopt::array_option, const_buffer buf) - { - set_option(Opt, buf.data(), buf.size()); - } - - // Set array socket option, e.g. - // `socket.set(zmq::sockopt::routing_id, id_str)` - template - void set(sockopt::array_option, const std::string &buf) - { - set_option(Opt, buf.data(), buf.size()); - } - -#if CPPZMQ_HAS_STRING_VIEW - // Set array socket option, e.g. - // `socket.set(zmq::sockopt::routing_id, id_str)` - template - void set(sockopt::array_option, std::string_view buf) - { - set_option(Opt, buf.data(), buf.size()); - } -#endif - - // Get scalar socket option, e.g. - // `auto opt = socket.get(zmq::sockopt::linger)` - template - ZMQ_NODISCARD T get(sockopt::integral_option) const - { - static_assert(std::is_scalar::value, "T must be scalar"); - T val; - size_t size = sizeof val; - get_option(Opt, &val, &size); - assert(size == sizeof val); - return val; - } - - // Get array socket option, writes to buf, returns option size in bytes, e.g. - // `size_t optsize = socket.get(zmq::sockopt::routing_id, zmq::buffer(id))` - template - ZMQ_NODISCARD size_t get(sockopt::array_option, - mutable_buffer buf) const - { - size_t size = buf.size(); - get_option(Opt, buf.data(), &size); - return size; - } - - // Get array socket option as string (initializes the string buffer size to init_size) e.g. - // `auto s = socket.get(zmq::sockopt::routing_id)` - // Note: removes the null character from null-terminated string options, - // i.e. the string size excludes the null character. - template - ZMQ_NODISCARD std::string get(sockopt::array_option, - size_t init_size = 1024) const - { - if ZMQ_CONSTEXPR_IF (NullTerm == 2) { - if (init_size == 1024) { - init_size = 41; // get as Z85 string - } - } - std::string str(init_size, '\0'); - size_t size = get(sockopt::array_option{}, buffer(str)); - if ZMQ_CONSTEXPR_IF (NullTerm == 1) { - if (size > 0) { - assert(str[size - 1] == '\0'); - --size; - } - } else if ZMQ_CONSTEXPR_IF (NullTerm == 2) { - assert(size == 32 || size == 41); - if (size == 41) { - assert(str[size - 1] == '\0'); - --size; - } - } - str.resize(size); - return str; - } -#endif - - void bind(std::string const &addr) { bind(addr.c_str()); } - - void bind(const char *addr_) - { - int rc = zmq_bind(_handle, addr_); - if (rc != 0) - throw error_t(); - } - - void unbind(std::string const &addr) { unbind(addr.c_str()); } - - void unbind(const char *addr_) - { - int rc = zmq_unbind(_handle, addr_); - if (rc != 0) - throw error_t(); - } - - void connect(std::string const &addr) { connect(addr.c_str()); } - - void connect(const char *addr_) - { - int rc = zmq_connect(_handle, addr_); - if (rc != 0) - throw error_t(); - } - - void disconnect(std::string const &addr) { disconnect(addr.c_str()); } - - void disconnect(const char *addr_) - { - int rc = zmq_disconnect(_handle, addr_); - if (rc != 0) - throw error_t(); - } - - ZMQ_DEPRECATED("from 4.7.1, use handle() != nullptr or operator bool") - bool connected() const ZMQ_NOTHROW { return (_handle != ZMQ_NULLPTR); } - - ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking a const_buffer and send_flags") - size_t send(const void *buf_, size_t len_, int flags_ = 0) - { - int nbytes = zmq_send(_handle, buf_, len_, flags_); - if (nbytes >= 0) - return static_cast(nbytes); - if (zmq_errno() == EAGAIN) - return 0; - throw error_t(); - } - - ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking message_t and send_flags") - bool send(message_t &msg_, - int flags_ = 0) // default until removed - { - int nbytes = zmq_msg_send(msg_.handle(), _handle, flags_); - if (nbytes >= 0) - return true; - if (zmq_errno() == EAGAIN) - return false; - throw error_t(); - } - - template - ZMQ_CPP11_DEPRECATED( - "from 4.4.1, use send taking message_t or buffer (for contiguous " - "ranges), and send_flags") - bool send(T first, T last, int flags_ = 0) - { - zmq::message_t msg(first, last); - int nbytes = zmq_msg_send(msg.handle(), _handle, flags_); - if (nbytes >= 0) - return true; - if (zmq_errno() == EAGAIN) - return false; - throw error_t(); - } - -#ifdef ZMQ_HAS_RVALUE_REFS - ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking message_t and send_flags") - bool send(message_t &&msg_, - int flags_ = 0) // default until removed - { -#ifdef ZMQ_CPP11 - return send(msg_, static_cast(flags_)).has_value(); -#else - return send(msg_, flags_); -#endif - } -#endif - -#ifdef ZMQ_CPP11 - send_result_t send(const_buffer buf, send_flags flags = send_flags::none) - { - const int nbytes = - zmq_send(_handle, buf.data(), buf.size(), static_cast(flags)); - if (nbytes >= 0) - return static_cast(nbytes); - if (zmq_errno() == EAGAIN) - return {}; - throw error_t(); - } - - send_result_t send(message_t &msg, send_flags flags) - { - int nbytes = zmq_msg_send(msg.handle(), _handle, static_cast(flags)); - if (nbytes >= 0) - return static_cast(nbytes); - if (zmq_errno() == EAGAIN) - return {}; - throw error_t(); - } - - send_result_t send(message_t &&msg, send_flags flags) - { - return send(msg, flags); - } -#endif - - ZMQ_CPP11_DEPRECATED( - "from 4.3.1, use recv taking a mutable_buffer and recv_flags") - size_t recv(void *buf_, size_t len_, int flags_ = 0) - { - int nbytes = zmq_recv(_handle, buf_, len_, flags_); - if (nbytes >= 0) - return static_cast(nbytes); - if (zmq_errno() == EAGAIN) - return 0; - throw error_t(); - } - - ZMQ_CPP11_DEPRECATED( - "from 4.3.1, use recv taking a reference to message_t and recv_flags") - bool recv(message_t *msg_, int flags_ = 0) - { - int nbytes = zmq_msg_recv(msg_->handle(), _handle, flags_); - if (nbytes >= 0) - return true; - if (zmq_errno() == EAGAIN) - return false; - throw error_t(); - } - -#ifdef ZMQ_CPP11 - ZMQ_NODISCARD - recv_buffer_result_t recv(mutable_buffer buf, - recv_flags flags = recv_flags::none) - { - const int nbytes = - zmq_recv(_handle, buf.data(), buf.size(), static_cast(flags)); - if (nbytes >= 0) { - return recv_buffer_size{ - (std::min)(static_cast(nbytes), buf.size()), - static_cast(nbytes)}; - } - if (zmq_errno() == EAGAIN) - return {}; - throw error_t(); - } - - ZMQ_NODISCARD - recv_result_t recv(message_t &msg, recv_flags flags = recv_flags::none) - { - const int nbytes = - zmq_msg_recv(msg.handle(), _handle, static_cast(flags)); - if (nbytes >= 0) { - assert(msg.size() == static_cast(nbytes)); - return static_cast(nbytes); - } - if (zmq_errno() == EAGAIN) - return {}; - throw error_t(); - } -#endif - -#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0) - void join(const char *group) - { - int rc = zmq_join(_handle, group); - if (rc != 0) - throw error_t(); - } - - void leave(const char *group) - { - int rc = zmq_leave(_handle, group); - if (rc != 0) - throw error_t(); - } -#endif - - ZMQ_NODISCARD void *handle() ZMQ_NOTHROW { return _handle; } - ZMQ_NODISCARD const void *handle() const ZMQ_NOTHROW { return _handle; } - - ZMQ_EXPLICIT operator bool() const ZMQ_NOTHROW { return _handle != ZMQ_NULLPTR; } - // note: non-const operator bool can be removed once - // operator void* is removed from socket_t - ZMQ_EXPLICIT operator bool() ZMQ_NOTHROW { return _handle != ZMQ_NULLPTR; } - - protected: - void *_handle; - - private: - void set_option(int option_, const void *optval_, size_t optvallen_) - { - int rc = zmq_setsockopt(_handle, option_, optval_, optvallen_); - if (rc != 0) - throw error_t(); - } - - void get_option(int option_, void *optval_, size_t *optvallen_) const - { - int rc = zmq_getsockopt(_handle, option_, optval_, optvallen_); - if (rc != 0) - throw error_t(); - } -}; -} // namespace detail - -struct from_handle_t -{ - struct _private - { - }; // disabling use other than with from_handle - ZMQ_CONSTEXPR_FN ZMQ_EXPLICIT from_handle_t(_private /*p*/) ZMQ_NOTHROW {} -}; - -ZMQ_CONSTEXPR_VAR from_handle_t from_handle = - from_handle_t(from_handle_t::_private()); - -// A non-owning nullable reference to a socket. -// The reference is invalidated on socket close or destruction. -class socket_ref : public detail::socket_base -{ - public: - socket_ref() ZMQ_NOTHROW : detail::socket_base() {} -#ifdef ZMQ_CPP11 - socket_ref(std::nullptr_t) ZMQ_NOTHROW : detail::socket_base() {} -#endif - socket_ref(from_handle_t /*fh*/, void *handle) ZMQ_NOTHROW - : detail::socket_base(handle) - { - } -}; - -#ifdef ZMQ_CPP11 -inline bool operator==(socket_ref sr, std::nullptr_t /*p*/) ZMQ_NOTHROW -{ - return sr.handle() == nullptr; -} -inline bool operator==(std::nullptr_t /*p*/, socket_ref sr) ZMQ_NOTHROW -{ - return sr.handle() == nullptr; -} -inline bool operator!=(socket_ref sr, std::nullptr_t /*p*/) ZMQ_NOTHROW -{ - return !(sr == nullptr); -} -inline bool operator!=(std::nullptr_t /*p*/, socket_ref sr) ZMQ_NOTHROW -{ - return !(sr == nullptr); -} -#endif - -inline bool operator==(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW -{ - return std::equal_to()(a.handle(), b.handle()); -} -inline bool operator!=(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW -{ - return !(a == b); -} -inline bool operator<(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW -{ - return std::less()(a.handle(), b.handle()); -} -inline bool operator>(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW -{ - return b < a; -} -inline bool operator<=(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW -{ - return !(a > b); -} -inline bool operator>=(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW -{ - return !(a < b); -} - -} // namespace zmq - -#ifdef ZMQ_CPP11 -namespace std -{ -template<> struct hash -{ - size_t operator()(zmq::socket_ref sr) const ZMQ_NOTHROW - { - return hash()(sr.handle()); - } -}; -} // namespace std -#endif - -namespace zmq -{ -class socket_t : public detail::socket_base -{ - friend class monitor_t; - - public: - socket_t() ZMQ_NOTHROW : detail::socket_base(ZMQ_NULLPTR), ctxptr(ZMQ_NULLPTR) {} - - socket_t(context_t &context_, int type_) : - detail::socket_base(zmq_socket(context_.handle(), type_)), - ctxptr(context_.handle()) - { - if (_handle == ZMQ_NULLPTR) - throw error_t(); - } - -#ifdef ZMQ_CPP11 - socket_t(context_t &context_, socket_type type_) : - socket_t(context_, static_cast(type_)) - { - } -#endif - -#ifdef ZMQ_HAS_RVALUE_REFS - socket_t(socket_t &&rhs) ZMQ_NOTHROW : detail::socket_base(rhs._handle), - ctxptr(rhs.ctxptr) - { - rhs._handle = ZMQ_NULLPTR; - rhs.ctxptr = ZMQ_NULLPTR; - } - socket_t &operator=(socket_t &&rhs) ZMQ_NOTHROW - { - close(); - std::swap(_handle, rhs._handle); - std::swap(ctxptr, rhs.ctxptr); - return *this; - } -#endif - - ~socket_t() ZMQ_NOTHROW { close(); } - - operator void *() ZMQ_NOTHROW { return _handle; } - - operator void const *() const ZMQ_NOTHROW { return _handle; } - - void close() ZMQ_NOTHROW - { - if (_handle == ZMQ_NULLPTR) - // already closed - return; - int rc = zmq_close(_handle); - ZMQ_ASSERT(rc == 0); - _handle = ZMQ_NULLPTR; - ctxptr = ZMQ_NULLPTR; - } - - void swap(socket_t &other) ZMQ_NOTHROW - { - std::swap(_handle, other._handle); - std::swap(ctxptr, other.ctxptr); - } - - operator socket_ref() ZMQ_NOTHROW { return socket_ref(from_handle, _handle); } - - private: - void *ctxptr; - - socket_t(const socket_t &) ZMQ_DELETED_FUNCTION; - void operator=(const socket_t &) ZMQ_DELETED_FUNCTION; - - // used by monitor_t - socket_t(void *context_, int type_) : - detail::socket_base(zmq_socket(context_, type_)), ctxptr(context_) - { - if (_handle == ZMQ_NULLPTR) - throw error_t(); - if (ctxptr == ZMQ_NULLPTR) - throw error_t(); - } -}; - -inline void swap(socket_t &a, socket_t &b) ZMQ_NOTHROW -{ - a.swap(b); -} - -ZMQ_DEPRECATED("from 4.3.1, use proxy taking socket_t objects") -inline void proxy(void *frontend, void *backend, void *capture) -{ - int rc = zmq_proxy(frontend, backend, capture); - if (rc != 0) - throw error_t(); -} - -inline void -proxy(socket_ref frontend, socket_ref backend, socket_ref capture = socket_ref()) -{ - int rc = zmq_proxy(frontend.handle(), backend.handle(), capture.handle()); - if (rc != 0) - throw error_t(); -} - -#ifdef ZMQ_HAS_PROXY_STEERABLE -ZMQ_DEPRECATED("from 4.3.1, use proxy_steerable taking socket_t objects") -inline void -proxy_steerable(void *frontend, void *backend, void *capture, void *control) -{ - int rc = zmq_proxy_steerable(frontend, backend, capture, control); - if (rc != 0) - throw error_t(); -} - -inline void proxy_steerable(socket_ref frontend, - socket_ref backend, - socket_ref capture, - socket_ref control) -{ - int rc = zmq_proxy_steerable(frontend.handle(), backend.handle(), - capture.handle(), control.handle()); - if (rc != 0) - throw error_t(); -} -#endif - -class monitor_t -{ - public: - monitor_t() : _socket(), _monitor_socket() {} - - virtual ~monitor_t() { close(); } - -#ifdef ZMQ_HAS_RVALUE_REFS - monitor_t(monitor_t &&rhs) ZMQ_NOTHROW : _socket(), _monitor_socket() - { - std::swap(_socket, rhs._socket); - std::swap(_monitor_socket, rhs._monitor_socket); - } - - monitor_t &operator=(monitor_t &&rhs) ZMQ_NOTHROW - { - close(); - _socket = socket_ref(); - std::swap(_socket, rhs._socket); - std::swap(_monitor_socket, rhs._monitor_socket); - return *this; - } -#endif - - - void - monitor(socket_t &socket, std::string const &addr, int events = ZMQ_EVENT_ALL) - { - monitor(socket, addr.c_str(), events); - } - - void monitor(socket_t &socket, const char *addr_, int events = ZMQ_EVENT_ALL) - { - init(socket, addr_, events); - while (true) { - check_event(-1); - } - } - - void init(socket_t &socket, std::string const &addr, int events = ZMQ_EVENT_ALL) - { - init(socket, addr.c_str(), events); - } - - void init(socket_t &socket, const char *addr_, int events = ZMQ_EVENT_ALL) - { - int rc = zmq_socket_monitor(socket.handle(), addr_, events); - if (rc != 0) - throw error_t(); - - _socket = socket; - _monitor_socket = socket_t(socket.ctxptr, ZMQ_PAIR); - _monitor_socket.connect(addr_); - - on_monitor_started(); - } - - bool check_event(int timeout = 0) - { - assert(_monitor_socket); - - zmq::pollitem_t items[] = { - {_monitor_socket.handle(), 0, ZMQ_POLLIN, 0}, - }; - - #ifdef ZMQ_CPP11 - zmq::poll(&items[0], 1, std::chrono::milliseconds(timeout)); - #else - zmq::poll(&items[0], 1, timeout); - #endif - - return process_event(items[0].revents); - } - -#ifdef ZMQ_EVENT_MONITOR_STOPPED - void abort() - { - if (_socket) - zmq_socket_monitor(_socket.handle(), ZMQ_NULLPTR, 0); - - _socket = socket_ref(); - } - - virtual void on_monitor_stopped() {} -#endif - virtual void on_monitor_started() {} - virtual void on_event_connected(const zmq_event_t &event_, const char *addr_) - { - (void) event_; - (void) addr_; - } - virtual void on_event_connect_delayed(const zmq_event_t &event_, - const char *addr_) - { - (void) event_; - (void) addr_; - } - virtual void on_event_connect_retried(const zmq_event_t &event_, - const char *addr_) - { - (void) event_; - (void) addr_; - } - virtual void on_event_listening(const zmq_event_t &event_, const char *addr_) - { - (void) event_; - (void) addr_; - } - virtual void on_event_bind_failed(const zmq_event_t &event_, const char *addr_) - { - (void) event_; - (void) addr_; - } - virtual void on_event_accepted(const zmq_event_t &event_, const char *addr_) - { - (void) event_; - (void) addr_; - } - virtual void on_event_accept_failed(const zmq_event_t &event_, const char *addr_) - { - (void) event_; - (void) addr_; - } - virtual void on_event_closed(const zmq_event_t &event_, const char *addr_) - { - (void) event_; - (void) addr_; - } - virtual void on_event_close_failed(const zmq_event_t &event_, const char *addr_) - { - (void) event_; - (void) addr_; - } - virtual void on_event_disconnected(const zmq_event_t &event_, const char *addr_) - { - (void) event_; - (void) addr_; - } -#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3) - virtual void on_event_handshake_failed_no_detail(const zmq_event_t &event_, - const char *addr_) - { - (void) event_; - (void) addr_; - } - virtual void on_event_handshake_failed_protocol(const zmq_event_t &event_, - const char *addr_) - { - (void) event_; - (void) addr_; - } - virtual void on_event_handshake_failed_auth(const zmq_event_t &event_, - const char *addr_) - { - (void) event_; - (void) addr_; - } - virtual void on_event_handshake_succeeded(const zmq_event_t &event_, - const char *addr_) - { - (void) event_; - (void) addr_; - } -#elif ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 1) - virtual void on_event_handshake_failed(const zmq_event_t &event_, - const char *addr_) - { - (void) event_; - (void) addr_; - } - virtual void on_event_handshake_succeed(const zmq_event_t &event_, - const char *addr_) - { - (void) event_; - (void) addr_; - } -#endif - virtual void on_event_unknown(const zmq_event_t &event_, const char *addr_) - { - (void) event_; - (void) addr_; - } - - protected: - bool process_event(short events) - { - zmq::message_t eventMsg; - - if (events & ZMQ_POLLIN) { - int rc = zmq_msg_recv(eventMsg.handle(), _monitor_socket.handle(), 0); - if (rc == -1 && zmq_errno() == ETERM) - return false; - assert(rc != -1); - - } else { - return false; - } - -#if ZMQ_VERSION_MAJOR >= 4 - const char *data = static_cast(eventMsg.data()); - zmq_event_t msgEvent; - memcpy(&msgEvent.event, data, sizeof(uint16_t)); - data += sizeof(uint16_t); - memcpy(&msgEvent.value, data, sizeof(int32_t)); - zmq_event_t *event = &msgEvent; -#else - zmq_event_t *event = static_cast(eventMsg.data()); -#endif - -#ifdef ZMQ_NEW_MONITOR_EVENT_LAYOUT - zmq::message_t addrMsg; - int rc = zmq_msg_recv(addrMsg.handle(), _monitor_socket.handle(), 0); - if (rc == -1 && zmq_errno() == ETERM) { - return false; - } - - assert(rc != -1); - std::string address = addrMsg.to_string(); -#else - // Bit of a hack, but all events in the zmq_event_t union have the same layout so this will work for all event types. - std::string address = event->data.connected.addr; -#endif - -#ifdef ZMQ_EVENT_MONITOR_STOPPED - if (event->event == ZMQ_EVENT_MONITOR_STOPPED) { - on_monitor_stopped(); - return false; - } - -#endif - - switch (event->event) { - case ZMQ_EVENT_CONNECTED: - on_event_connected(*event, address.c_str()); - break; - case ZMQ_EVENT_CONNECT_DELAYED: - on_event_connect_delayed(*event, address.c_str()); - break; - case ZMQ_EVENT_CONNECT_RETRIED: - on_event_connect_retried(*event, address.c_str()); - break; - case ZMQ_EVENT_LISTENING: - on_event_listening(*event, address.c_str()); - break; - case ZMQ_EVENT_BIND_FAILED: - on_event_bind_failed(*event, address.c_str()); - break; - case ZMQ_EVENT_ACCEPTED: - on_event_accepted(*event, address.c_str()); - break; - case ZMQ_EVENT_ACCEPT_FAILED: - on_event_accept_failed(*event, address.c_str()); - break; - case ZMQ_EVENT_CLOSED: - on_event_closed(*event, address.c_str()); - break; - case ZMQ_EVENT_CLOSE_FAILED: - on_event_close_failed(*event, address.c_str()); - break; - case ZMQ_EVENT_DISCONNECTED: - on_event_disconnected(*event, address.c_str()); - break; -#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 0) || (defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3)) - case ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL: - on_event_handshake_failed_no_detail(*event, address.c_str()); - break; - case ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL: - on_event_handshake_failed_protocol(*event, address.c_str()); - break; - case ZMQ_EVENT_HANDSHAKE_FAILED_AUTH: - on_event_handshake_failed_auth(*event, address.c_str()); - break; - case ZMQ_EVENT_HANDSHAKE_SUCCEEDED: - on_event_handshake_succeeded(*event, address.c_str()); - break; -#elif defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 1) - case ZMQ_EVENT_HANDSHAKE_FAILED: - on_event_handshake_failed(*event, address.c_str()); - break; - case ZMQ_EVENT_HANDSHAKE_SUCCEED: - on_event_handshake_succeed(*event, address.c_str()); - break; -#endif - default: - on_event_unknown(*event, address.c_str()); - break; - } - - return true; - } - - socket_ref monitor_socket() {return _monitor_socket;} - - private: - monitor_t(const monitor_t &) ZMQ_DELETED_FUNCTION; - void operator=(const monitor_t &) ZMQ_DELETED_FUNCTION; - - socket_ref _socket; - socket_t _monitor_socket; - - void close() ZMQ_NOTHROW - { - if (_socket) - zmq_socket_monitor(_socket.handle(), ZMQ_NULLPTR, 0); - _monitor_socket.close(); - } -}; - -#if defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER) - -// polling events -enum class event_flags : short -{ - none = 0, - pollin = ZMQ_POLLIN, - pollout = ZMQ_POLLOUT, - pollerr = ZMQ_POLLERR, - pollpri = ZMQ_POLLPRI -}; - -constexpr event_flags operator|(event_flags a, event_flags b) noexcept -{ - return detail::enum_bit_or(a, b); -} -constexpr event_flags operator&(event_flags a, event_flags b) noexcept -{ - return detail::enum_bit_and(a, b); -} -constexpr event_flags operator^(event_flags a, event_flags b) noexcept -{ - return detail::enum_bit_xor(a, b); -} -constexpr event_flags operator~(event_flags a) noexcept -{ - return detail::enum_bit_not(a); -} - -struct no_user_data; - -// layout compatible with zmq_poller_event_t -template struct poller_event -{ - socket_ref socket; - ::zmq::fd_t fd; - T *user_data; - event_flags events; -}; - -template class poller_t -{ - public: - using event_type = poller_event; - - poller_t() : poller_ptr(zmq_poller_new()) - { - if (!poller_ptr) - throw error_t(); - } - - template< - typename Dummy = void, - typename = - typename std::enable_if::value, Dummy>::type> - void add(zmq::socket_ref socket, event_flags events, T *user_data) - { - add_impl(socket, events, user_data); - } - - void add(zmq::socket_ref socket, event_flags events) - { - add_impl(socket, events, nullptr); - } - - template< - typename Dummy = void, - typename = - typename std::enable_if::value, Dummy>::type> - void add(fd_t fd, event_flags events, T *user_data) - { - add_impl(fd, events, user_data); - } - - void add(fd_t fd, event_flags events) { add_impl(fd, events, nullptr); } - - void remove(zmq::socket_ref socket) - { - if (0 != zmq_poller_remove(poller_ptr.get(), socket.handle())) { - throw error_t(); - } - } - - void remove(fd_t fd) - { - if (0 != zmq_poller_remove_fd(poller_ptr.get(), fd)) { - throw error_t(); - } - } - - void modify(zmq::socket_ref socket, event_flags events) - { - if (0 - != zmq_poller_modify(poller_ptr.get(), socket.handle(), - static_cast(events))) { - throw error_t(); - } - } - - void modify(fd_t fd, event_flags events) - { - if (0 - != zmq_poller_modify_fd(poller_ptr.get(), fd, - static_cast(events))) { - throw error_t(); - } - } - - template - size_t wait_all(Sequence &poller_events, - const std::chrono::milliseconds timeout) - { - static_assert(std::is_same::value, - "Sequence::value_type must be of poller_t::event_type"); - int rc = zmq_poller_wait_all( - poller_ptr.get(), - reinterpret_cast(poller_events.data()), - static_cast(poller_events.size()), - static_cast(timeout.count())); - if (rc > 0) - return static_cast(rc); - -#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3) - if (zmq_errno() == EAGAIN) -#else - if (zmq_errno() == ETIMEDOUT) -#endif - return 0; - - throw error_t(); - } - -#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 3) - size_t size() const noexcept - { - int rc = zmq_poller_size(const_cast(poller_ptr.get())); - ZMQ_ASSERT(rc >= 0); - return static_cast((std::max)(rc, 0)); - } -#endif - - private: - struct destroy_poller_t - { - void operator()(void *ptr) noexcept - { - int rc = zmq_poller_destroy(&ptr); - ZMQ_ASSERT(rc == 0); - } - }; - - std::unique_ptr poller_ptr; - - void add_impl(zmq::socket_ref socket, event_flags events, T *user_data) - { - if (0 - != zmq_poller_add(poller_ptr.get(), socket.handle(), user_data, - static_cast(events))) { - throw error_t(); - } - } - - void add_impl(fd_t fd, event_flags events, T *user_data) - { - if (0 - != zmq_poller_add_fd(poller_ptr.get(), fd, user_data, - static_cast(events))) { - throw error_t(); - } - } -}; -#endif // defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER) - -inline std::ostream &operator<<(std::ostream &os, const message_t &msg) -{ - return os << msg.str(); -} - -#if defined(ZMQ_CPP11) && defined(ZMQ_HAVE_TIMERS) - -class timers -{ - public: - using id_t = int; - using fn_t = zmq_timer_fn; - -#if CPPZMQ_HAS_OPTIONAL - using timeout_result_t = std::optional; -#else - using timeout_result_t = detail::trivial_optional; -#endif - - timers() : _timers(zmq_timers_new()) - { - if (_timers == nullptr) - throw error_t(); - } - - timers(const timers &other) = delete; - timers &operator=(const timers &other) = delete; - - ~timers() - { - int rc = zmq_timers_destroy(&_timers); - ZMQ_ASSERT(rc == 0); - } - - id_t add(std::chrono::milliseconds interval, zmq_timer_fn handler, void *arg) - { - id_t timer_id = zmq_timers_add(_timers, interval.count(), handler, arg); - if (timer_id == -1) - throw zmq::error_t(); - return timer_id; - } - - void cancel(id_t timer_id) - { - int rc = zmq_timers_cancel(_timers, timer_id); - if (rc == -1) - throw zmq::error_t(); - } - - void set_interval(id_t timer_id, std::chrono::milliseconds interval) - { - int rc = zmq_timers_set_interval(_timers, timer_id, interval.count()); - if (rc == -1) - throw zmq::error_t(); - } - - void reset(id_t timer_id) - { - int rc = zmq_timers_reset(_timers, timer_id); - if (rc == -1) - throw zmq::error_t(); - } - - timeout_result_t timeout() const - { - int timeout = zmq_timers_timeout(_timers); - if (timeout == -1) - return timeout_result_t{}; - return std::chrono::milliseconds{timeout}; - } - - void execute() - { - int rc = zmq_timers_execute(_timers); - if (rc == -1) - throw zmq::error_t(); - } - - private: - void *_timers; -}; - -#endif // defined(ZMQ_CPP11) && defined(ZMQ_HAVE_TIMERS) - -} // namespace zmq - -#endif // __ZMQ_HPP_INCLUDED__ diff --git a/3rdparty/cppzmq/zmq_addon.hpp b/3rdparty/cppzmq/zmq_addon.hpp deleted file mode 100644 index c6b4462cb..000000000 --- a/3rdparty/cppzmq/zmq_addon.hpp +++ /dev/null @@ -1,848 +0,0 @@ -/* - Copyright (c) 2016-2017 ZeroMQ community - Copyright (c) 2016 VOCA AS / Harald Nøkland - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to - deal in the Software without restriction, including without limitation the - rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - sell copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. -*/ - -#ifndef __ZMQ_ADDON_HPP_INCLUDED__ -#define __ZMQ_ADDON_HPP_INCLUDED__ - -#include "zmq.hpp" - -#include -#include -#include -#include -#ifdef ZMQ_CPP11 -#include -#include -#include - -namespace zmq -{ - // socket ref or native file descriptor for poller - class poller_ref_t - { - public: - enum RefType - { - RT_SOCKET, - RT_FD - }; - - poller_ref_t() : poller_ref_t(socket_ref{}) - {} - - poller_ref_t(const zmq::socket_ref& socket) : data{RT_SOCKET, socket, {}} - {} - - poller_ref_t(zmq::fd_t fd) : data{RT_FD, {}, fd} - {} - - size_t hash() const ZMQ_NOTHROW - { - std::size_t h = 0; - hash_combine(h, std::get<0>(data)); - hash_combine(h, std::get<1>(data)); - hash_combine(h, std::get<2>(data)); - return h; - } - - bool operator == (const poller_ref_t& o) const ZMQ_NOTHROW - { - return data == o.data; - } - - private: - template - static void hash_combine(std::size_t& seed, const T& v) ZMQ_NOTHROW - { - std::hash hasher; - seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); - } - - std::tuple data; - - }; // class poller_ref_t - -} // namespace zmq - -// std::hash<> specialization for std::unordered_map -template <> struct std::hash -{ - size_t operator()(const zmq::poller_ref_t& ref) const ZMQ_NOTHROW - { - return ref.hash(); - } -}; -#endif // ZMQ_CPP11 - -namespace zmq -{ -#ifdef ZMQ_CPP11 - -namespace detail -{ -template -recv_result_t -recv_multipart_n(socket_ref s, OutputIt out, size_t n, recv_flags flags) -{ - size_t msg_count = 0; - message_t msg; - while (true) { - if ZMQ_CONSTEXPR_IF (CheckN) { - if (msg_count >= n) - throw std::runtime_error( - "Too many message parts in recv_multipart_n"); - } - if (!s.recv(msg, flags)) { - // zmq ensures atomic delivery of messages - assert(msg_count == 0); - return {}; - } - ++msg_count; - const bool more = msg.more(); - *out++ = std::move(msg); - if (!more) - break; - } - return msg_count; -} - -inline bool is_little_endian() -{ - const uint16_t i = 0x01; - return *reinterpret_cast(&i) == 0x01; -} - -inline void write_network_order(unsigned char *buf, const uint32_t value) -{ - if (is_little_endian()) { - ZMQ_CONSTEXPR_VAR uint32_t mask = (std::numeric_limits::max)(); - *buf++ = static_cast((value >> 24) & mask); - *buf++ = static_cast((value >> 16) & mask); - *buf++ = static_cast((value >> 8) & mask); - *buf++ = static_cast(value & mask); - } else { - std::memcpy(buf, &value, sizeof(value)); - } -} - -inline uint32_t read_u32_network_order(const unsigned char *buf) -{ - if (is_little_endian()) { - return (static_cast(buf[0]) << 24) - + (static_cast(buf[1]) << 16) - + (static_cast(buf[2]) << 8) - + static_cast(buf[3]); - } else { - uint32_t value; - std::memcpy(&value, buf, sizeof(value)); - return value; - } -} -} // namespace detail - -/* Receive a multipart message. - - Writes the zmq::message_t objects to OutputIterator out. - The out iterator must handle an unspecified number of writes, - e.g. by using std::back_inserter. - - Returns: the number of messages received or nullopt (on EAGAIN). - Throws: if recv throws. Any exceptions thrown - by the out iterator will be propagated and the message - may have been only partially received with pending - message parts. It is adviced to close this socket in that event. -*/ -template -ZMQ_NODISCARD recv_result_t recv_multipart(socket_ref s, - OutputIt out, - recv_flags flags = recv_flags::none) -{ - return detail::recv_multipart_n(s, std::move(out), 0, flags); -} - -/* Receive a multipart message. - - Writes at most n zmq::message_t objects to OutputIterator out. - If the number of message parts of the incoming message exceeds n - then an exception will be thrown. - - Returns: the number of messages received or nullopt (on EAGAIN). - Throws: if recv throws. Throws std::runtime_error if the number - of message parts exceeds n (exactly n messages will have been written - to out). Any exceptions thrown - by the out iterator will be propagated and the message - may have been only partially received with pending - message parts. It is adviced to close this socket in that event. -*/ -template -ZMQ_NODISCARD recv_result_t recv_multipart_n(socket_ref s, - OutputIt out, - size_t n, - recv_flags flags = recv_flags::none) -{ - return detail::recv_multipart_n(s, std::move(out), n, flags); -} - -/* Send a multipart message. - - The range must be a ForwardRange of zmq::message_t, - zmq::const_buffer or zmq::mutable_buffer. - The flags may be zmq::send_flags::sndmore if there are - more message parts to be sent after the call to this function. - - Returns: the number of messages sent (exactly msgs.size()) or nullopt (on EAGAIN). - Throws: if send throws. Any exceptions thrown - by the msgs range will be propagated and the message - may have been only partially sent. It is adviced to close this socket in that event. -*/ -template::value - && (std::is_same, message_t>::value - || detail::is_buffer>::value)>::type -#endif - > -send_result_t -send_multipart(socket_ref s, Range &&msgs, send_flags flags = send_flags::none) -{ - using std::begin; - using std::end; - auto it = begin(msgs); - const auto end_it = end(msgs); - size_t msg_count = 0; - while (it != end_it) { - const auto next = std::next(it); - const auto msg_flags = - flags | (next == end_it ? send_flags::none : send_flags::sndmore); - if (!s.send(*it, msg_flags)) { - // zmq ensures atomic delivery of messages - assert(it == begin(msgs)); - return {}; - } - ++msg_count; - it = next; - } - return msg_count; -} - -/* Encode a multipart message. - - The range must be a ForwardRange of zmq::message_t. A - zmq::multipart_t or STL container may be passed for encoding. - - Returns: a zmq::message_t holding the encoded multipart data. - - Throws: std::range_error is thrown if the size of any single part - can not fit in an unsigned 32 bit integer. - - The encoding is compatible with that used by the CZMQ function - zmsg_encode(), see https://rfc.zeromq.org/spec/50/. - Each part consists of a size followed by the data. - These are placed contiguously into the output message. A part of - size less than 255 bytes will have a single byte size value. - Larger parts will have a five byte size value with the first byte - set to 0xFF and the remaining four bytes holding the size of the - part's data. -*/ -template::value - && (std::is_same, message_t>::value - || detail::is_buffer>::value)>::type -#endif - > -message_t encode(const Range &parts) -{ - size_t mmsg_size = 0; - - // First pass check sizes - for (const auto &part : parts) { - const size_t part_size = part.size(); - if (part_size > (std::numeric_limits::max)()) { - // Size value must fit into uint32_t. - throw std::range_error("Invalid size, message part too large"); - } - const size_t count_size = - part_size < (std::numeric_limits::max)() ? 1 : 5; - mmsg_size += part_size + count_size; - } - - message_t encoded(mmsg_size); - unsigned char *buf = encoded.data(); - for (const auto &part : parts) { - const uint32_t part_size = static_cast(part.size()); - const unsigned char *part_data = - static_cast(part.data()); - - if (part_size < (std::numeric_limits::max)()) { - // small part - *buf++ = static_cast(part_size); - } else { - // big part - *buf++ = (std::numeric_limits::max)(); - detail::write_network_order(buf, part_size); - buf += sizeof(part_size); - } - std::memcpy(buf, part_data, part_size); - buf += part_size; - } - - assert(static_cast(buf - encoded.data()) == mmsg_size); - return encoded; -} - -/* Decode an encoded message to multiple parts. - - The given output iterator must be a ForwardIterator to a container - holding zmq::message_t such as a zmq::multipart_t or various STL - containers. - - Returns the ForwardIterator advanced once past the last decoded - part. - - Throws: a std::out_of_range is thrown if the encoded part sizes - lead to exceeding the message data bounds. - - The decoding assumes the message is encoded in the manner - performed by zmq::encode(), see https://rfc.zeromq.org/spec/50/. - */ -template OutputIt decode(const message_t &encoded, OutputIt out) -{ - const unsigned char *source = encoded.data(); - const unsigned char *const limit = source + encoded.size(); - - while (source < limit) { - size_t part_size = *source++; - if (part_size == (std::numeric_limits::max)()) { - if (static_cast(limit - source) < sizeof(uint32_t)) { - throw std::out_of_range( - "Malformed encoding, overflow in reading size"); - } - part_size = detail::read_u32_network_order(source); - // the part size is allowed to be less than 0xFF - source += sizeof(uint32_t); - } - - if (static_cast(limit - source) < part_size) { - throw std::out_of_range("Malformed encoding, overflow in reading part"); - } - *out = message_t(source, part_size); - ++out; - source += part_size; - } - - assert(source == limit); - return out; -} - -#endif - - -#ifdef ZMQ_HAS_RVALUE_REFS - -/* - This class handles multipart messaging. It is the C++ equivalent of zmsg.h, - which is part of CZMQ (the high-level C binding). Furthermore, it is a major - improvement compared to zmsg.hpp, which is part of the examples in the ØMQ - Guide. Unnecessary copying is avoided by using move semantics to efficiently - add/remove parts. -*/ -class multipart_t -{ - private: - std::deque m_parts; - - public: - typedef std::deque::value_type value_type; - - typedef std::deque::iterator iterator; - typedef std::deque::const_iterator const_iterator; - - typedef std::deque::reverse_iterator reverse_iterator; - typedef std::deque::const_reverse_iterator const_reverse_iterator; - - // Default constructor - multipart_t() {} - - // Construct from socket receive - multipart_t(socket_ref socket) { recv(socket); } - - // Construct from memory block - multipart_t(const void *src, size_t size) { addmem(src, size); } - - // Construct from string - multipart_t(const std::string &string) { addstr(string); } - - // Construct from message part - multipart_t(message_t &&message) { add(std::move(message)); } - - // Move constructor - multipart_t(multipart_t &&other) ZMQ_NOTHROW { m_parts = std::move(other.m_parts); } - - // Move assignment operator - multipart_t &operator=(multipart_t &&other) ZMQ_NOTHROW - { - m_parts = std::move(other.m_parts); - return *this; - } - - // Destructor - virtual ~multipart_t() { clear(); } - - message_t &operator[](size_t n) { return m_parts[n]; } - - const message_t &operator[](size_t n) const { return m_parts[n]; } - - message_t &at(size_t n) { return m_parts.at(n); } - - const message_t &at(size_t n) const { return m_parts.at(n); } - - iterator begin() { return m_parts.begin(); } - - const_iterator begin() const { return m_parts.begin(); } - - const_iterator cbegin() const { return m_parts.cbegin(); } - - reverse_iterator rbegin() { return m_parts.rbegin(); } - - const_reverse_iterator rbegin() const { return m_parts.rbegin(); } - - iterator end() { return m_parts.end(); } - - const_iterator end() const { return m_parts.end(); } - - const_iterator cend() const { return m_parts.cend(); } - - reverse_iterator rend() { return m_parts.rend(); } - - const_reverse_iterator rend() const { return m_parts.rend(); } - - // Delete all parts - void clear() { m_parts.clear(); } - - // Get number of parts - size_t size() const { return m_parts.size(); } - - // Check if number of parts is zero - bool empty() const { return m_parts.empty(); } - - // Receive multipart message from socket - bool recv(socket_ref socket, int flags = 0) - { - clear(); - bool more = true; - while (more) { - message_t message; -#ifdef ZMQ_CPP11 - if (!socket.recv(message, static_cast(flags))) - return false; -#else - if (!socket.recv(&message, flags)) - return false; -#endif - more = message.more(); - add(std::move(message)); - } - return true; - } - - // Send multipart message to socket - bool send(socket_ref socket, int flags = 0) - { - flags &= ~(ZMQ_SNDMORE); - bool more = size() > 0; - while (more) { - message_t message = pop(); - more = size() > 0; -#ifdef ZMQ_CPP11 - if (!socket.send(message, static_cast( - (more ? ZMQ_SNDMORE : 0) | flags))) - return false; -#else - if (!socket.send(message, (more ? ZMQ_SNDMORE : 0) | flags)) - return false; -#endif - } - clear(); - return true; - } - - // Concatenate other multipart to front - void prepend(multipart_t &&other) - { - while (!other.empty()) - push(other.remove()); - } - - // Concatenate other multipart to back - void append(multipart_t &&other) - { - while (!other.empty()) - add(other.pop()); - } - - // Push memory block to front - void pushmem(const void *src, size_t size) - { - m_parts.push_front(message_t(src, size)); - } - - // Push memory block to back - void addmem(const void *src, size_t size) - { - m_parts.push_back(message_t(src, size)); - } - - // Push string to front - void pushstr(const std::string &string) - { - m_parts.push_front(message_t(string.data(), string.size())); - } - - // Push string to back - void addstr(const std::string &string) - { - m_parts.push_back(message_t(string.data(), string.size())); - } - - // Push type (fixed-size) to front - template void pushtyp(const T &type) - { - static_assert(!std::is_same::value, - "Use pushstr() instead of pushtyp()"); - m_parts.push_front(message_t(&type, sizeof(type))); - } - - // Push type (fixed-size) to back - template void addtyp(const T &type) - { - static_assert(!std::is_same::value, - "Use addstr() instead of addtyp()"); - m_parts.push_back(message_t(&type, sizeof(type))); - } - - // Push message part to front - void push(message_t &&message) { m_parts.push_front(std::move(message)); } - - // Push message part to back - void add(message_t &&message) { m_parts.push_back(std::move(message)); } - - // Alias to allow std::back_inserter() - void push_back(message_t &&message) { m_parts.push_back(std::move(message)); } - - // Pop string from front - std::string popstr() - { - std::string string(m_parts.front().data(), m_parts.front().size()); - m_parts.pop_front(); - return string; - } - - // Pop type (fixed-size) from front - template T poptyp() - { - static_assert(!std::is_same::value, - "Use popstr() instead of poptyp()"); - if (sizeof(T) != m_parts.front().size()) - throw std::runtime_error( - "Invalid type, size does not match the message size"); - T type = *m_parts.front().data(); - m_parts.pop_front(); - return type; - } - - // Pop message part from front - message_t pop() - { - message_t message = std::move(m_parts.front()); - m_parts.pop_front(); - return message; - } - - // Pop message part from back - message_t remove() - { - message_t message = std::move(m_parts.back()); - m_parts.pop_back(); - return message; - } - - // get message part from front - const message_t &front() { return m_parts.front(); } - - // get message part from back - const message_t &back() { return m_parts.back(); } - - // Get pointer to a specific message part - const message_t *peek(size_t index) const { return &m_parts[index]; } - - // Get a string copy of a specific message part - std::string peekstr(size_t index) const - { - std::string string(m_parts[index].data(), m_parts[index].size()); - return string; - } - - // Peek type (fixed-size) from front - template T peektyp(size_t index) const - { - static_assert(!std::is_same::value, - "Use peekstr() instead of peektyp()"); - if (sizeof(T) != m_parts[index].size()) - throw std::runtime_error( - "Invalid type, size does not match the message size"); - T type = *m_parts[index].data(); - return type; - } - - // Create multipart from type (fixed-size) - template static multipart_t create(const T &type) - { - multipart_t multipart; - multipart.addtyp(type); - return multipart; - } - - // Copy multipart - multipart_t clone() const - { - multipart_t multipart; - for (size_t i = 0; i < size(); i++) - multipart.addmem(m_parts[i].data(), m_parts[i].size()); - return multipart; - } - - // Dump content to string - std::string str() const - { - std::stringstream ss; - for (size_t i = 0; i < m_parts.size(); i++) { - const unsigned char *data = m_parts[i].data(); - size_t size = m_parts[i].size(); - - // Dump the message as text or binary - bool isText = true; - for (size_t j = 0; j < size; j++) { - if (data[j] < 32 || data[j] > 127) { - isText = false; - break; - } - } - ss << "\n[" << std::dec << std::setw(3) << std::setfill('0') << size - << "] "; - if (size >= 1000) { - ss << "... (too big to print)"; - continue; - } - for (size_t j = 0; j < size; j++) { - if (isText) - ss << static_cast(data[j]); - else - ss << std::hex << std::setw(2) << std::setfill('0') - << static_cast(data[j]); - } - } - return ss.str(); - } - - // Check if equal to other multipart - bool equal(const multipart_t *other) const ZMQ_NOTHROW - { - return *this == *other; - } - - bool operator==(const multipart_t &other) const ZMQ_NOTHROW - { - if (size() != other.size()) - return false; - for (size_t i = 0; i < size(); i++) - if (at(i) != other.at(i)) - return false; - return true; - } - - bool operator!=(const multipart_t &other) const ZMQ_NOTHROW - { - return !(*this == other); - } - -#ifdef ZMQ_CPP11 - - // Return single part message_t encoded from this multipart_t. - message_t encode() const { return zmq::encode(*this); } - - // Decode encoded message into multiple parts and append to self. - void decode_append(const message_t &encoded) - { - zmq::decode(encoded, std::back_inserter(*this)); - } - - // Return a new multipart_t containing the decoded message_t. - static multipart_t decode(const message_t &encoded) - { - multipart_t tmp; - zmq::decode(encoded, std::back_inserter(tmp)); - return tmp; - } - -#endif - - private: - // Disable implicit copying (moving is more efficient) - multipart_t(const multipart_t &other) ZMQ_DELETED_FUNCTION; - void operator=(const multipart_t &other) ZMQ_DELETED_FUNCTION; -}; // class multipart_t - -inline std::ostream &operator<<(std::ostream &os, const multipart_t &msg) -{ - return os << msg.str(); -} - -#endif // ZMQ_HAS_RVALUE_REFS - -#if defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER) -class active_poller_t -{ - public: - active_poller_t() = default; - ~active_poller_t() = default; - - active_poller_t(const active_poller_t &) = delete; - active_poller_t &operator=(const active_poller_t &) = delete; - - active_poller_t(active_poller_t &&src) = default; - active_poller_t &operator=(active_poller_t &&src) = default; - - using handler_type = std::function; - - void add(zmq::socket_ref socket, event_flags events, handler_type handler) - { - const poller_ref_t ref{socket}; - - if (!handler) - throw std::invalid_argument("null handler in active_poller_t::add (socket)"); - auto ret = handlers.emplace( - ref, std::make_shared(std::move(handler))); - if (!ret.second) - throw error_t(EINVAL); // already added - try { - base_poller.add(socket, events, ret.first->second.get()); - need_rebuild = true; - } - catch (...) { - // rollback - handlers.erase(ref); - throw; - } - } - - void add(fd_t fd, event_flags events, handler_type handler) - { - const poller_ref_t ref{fd}; - - if (!handler) - throw std::invalid_argument("null handler in active_poller_t::add (fd)"); - auto ret = handlers.emplace( - ref, std::make_shared(std::move(handler))); - if (!ret.second) - throw error_t(EINVAL); // already added - try { - base_poller.add(fd, events, ret.first->second.get()); - need_rebuild = true; - } - catch (...) { - // rollback - handlers.erase(ref); - throw; - } - } - - void remove(zmq::socket_ref socket) - { - base_poller.remove(socket); - handlers.erase(socket); - need_rebuild = true; - } - - void remove(fd_t fd) - { - base_poller.remove(fd); - handlers.erase(fd); - need_rebuild = true; - } - - void modify(zmq::socket_ref socket, event_flags events) - { - base_poller.modify(socket, events); - } - - void modify(fd_t fd, event_flags events) - { - base_poller.modify(fd, events); - } - - size_t wait(std::chrono::milliseconds timeout) - { - if (need_rebuild) { - poller_events.resize(handlers.size()); - poller_handlers.clear(); - poller_handlers.reserve(handlers.size()); - for (const auto &handler : handlers) { - poller_handlers.push_back(handler.second); - } - need_rebuild = false; - } - const auto count = base_poller.wait_all(poller_events, timeout); - std::for_each(poller_events.begin(), - poller_events.begin() + static_cast(count), - [](decltype(base_poller)::event_type &event) { - assert(event.user_data != nullptr); - (*event.user_data)(event.events); - }); - return count; - } - - ZMQ_NODISCARD bool empty() const noexcept { return handlers.empty(); } - - size_t size() const noexcept { return handlers.size(); } - - private: - bool need_rebuild{false}; - - poller_t base_poller{}; - - std::unordered_map> handlers{}; - - std::vector poller_events{}; - std::vector> poller_handlers{}; -}; // class active_poller_t -#endif // defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER) - - -} // namespace zmq - -#endif // __ZMQ_ADDON_HPP_INCLUDED__ diff --git a/3rdparty/doxygen-awesome-css/LICENSE b/3rdparty/doxygen-awesome-css/LICENSE deleted file mode 100644 index 8bf804a2a..000000000 --- a/3rdparty/doxygen-awesome-css/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 - 2023 jothepro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/3rdparty/doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js b/3rdparty/doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js deleted file mode 100644 index 440e4e08f..000000000 --- a/3rdparty/doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js +++ /dev/null @@ -1,138 +0,0 @@ -// SPDX-License-Identifier: MIT -/** - -Doxygen Awesome -https://github.com/jothepro/doxygen-awesome-css - -Copyright (c) 2021 - 2025 jothepro - -*/ - -class DoxygenAwesomeDarkModeToggle extends HTMLElement { - // SVG icons from https://fonts.google.com/icons - // Licensed under the Apache 2.0 license: - // https://www.apache.org/licenses/LICENSE-2.0.html - static lightModeIcon = `` - static darkModeIcon = `` - static title = "Toggle Light/Dark Mode" - - static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode" - static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode" - - static _staticConstructor = function() { - DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.userPreference) - // Update the color scheme when the browsers preference changes - // without user interaction on the website. - window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => { - DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged() - }) - // Update the color scheme when the tab is made visible again. - // It is possible that the appearance was changed in another tab - // while this tab was in the background. - document.addEventListener("visibilitychange", visibilityState => { - if (document.visibilityState === 'visible') { - DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged() - } - }); - }() - - static init() { - $(function() { - $(document).ready(function() { - const toggleButton = document.createElement('doxygen-awesome-dark-mode-toggle') - toggleButton.title = DoxygenAwesomeDarkModeToggle.title - toggleButton.updateIcon() - - window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => { - toggleButton.updateIcon() - }) - document.addEventListener("visibilitychange", visibilityState => { - if (document.visibilityState === 'visible') { - toggleButton.updateIcon() - } - }); - - $(document).ready(function(){ - document.getElementById("MSearchBox").parentNode.appendChild(toggleButton) - }) - $(window).resize(function(){ - document.getElementById("MSearchBox").parentNode.appendChild(toggleButton) - }) - }) - }) - } - - constructor() { - super(); - this.onclick=this.toggleDarkMode - } - - /** - * @returns `true` for dark-mode, `false` for light-mode system preference - */ - static get systemPreference() { - return window.matchMedia('(prefers-color-scheme: dark)').matches - } - - /** - * @returns `true` for dark-mode, `false` for light-mode user preference - */ - static get userPreference() { - return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) || - (DoxygenAwesomeDarkModeToggle.systemPreference && !localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey)) - } - - static set userPreference(userPreference) { - DoxygenAwesomeDarkModeToggle.darkModeEnabled = userPreference - if(!userPreference) { - if(DoxygenAwesomeDarkModeToggle.systemPreference) { - localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey, true) - } else { - localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey) - } - } else { - if(!DoxygenAwesomeDarkModeToggle.systemPreference) { - localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey, true) - } else { - localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey) - } - } - DoxygenAwesomeDarkModeToggle.onUserPreferenceChanged() - } - - static enableDarkMode(enable) { - if(enable) { - DoxygenAwesomeDarkModeToggle.darkModeEnabled = true - document.documentElement.classList.add("dark-mode") - document.documentElement.classList.remove("light-mode") - } else { - DoxygenAwesomeDarkModeToggle.darkModeEnabled = false - document.documentElement.classList.remove("dark-mode") - document.documentElement.classList.add("light-mode") - } - } - - static onSystemPreferenceChanged() { - DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference - DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled) - } - - static onUserPreferenceChanged() { - DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled) - } - - toggleDarkMode() { - DoxygenAwesomeDarkModeToggle.userPreference = !DoxygenAwesomeDarkModeToggle.userPreference - this.updateIcon() - } - - updateIcon() { - if(DoxygenAwesomeDarkModeToggle.darkModeEnabled) { - this.innerHTML = DoxygenAwesomeDarkModeToggle.darkModeIcon - } else { - this.innerHTML = DoxygenAwesomeDarkModeToggle.lightModeIcon - } - } -} - -customElements.define("doxygen-awesome-dark-mode-toggle", DoxygenAwesomeDarkModeToggle); diff --git a/3rdparty/flatbuffers/CMakeLists.txt b/3rdparty/flatbuffers/CMakeLists.txt deleted file mode 100644 index bc91f8e27..000000000 --- a/3rdparty/flatbuffers/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -add_library(flatbuffers INTERFACE) - -add_library(flatbuffers::flatbuffers ALIAS flatbuffers) - -target_include_directories(flatbuffers - INTERFACE - ${CMAKE_CURRENT_SOURCE_DIR} -) diff --git a/3rdparty/flatbuffers/flatbuffers/base.h b/3rdparty/flatbuffers/flatbuffers/base.h deleted file mode 100644 index 1c19dde98..000000000 --- a/3rdparty/flatbuffers/flatbuffers/base.h +++ /dev/null @@ -1,496 +0,0 @@ -#ifndef FLATBUFFERS_BASE_H_ -#define FLATBUFFERS_BASE_H_ - -// clang-format off - -// If activate should be declared and included first. -#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \ - defined(_MSC_VER) && defined(_DEBUG) - // The _CRTDBG_MAP_ALLOC inside will replace - // calloc/free (etc) to its debug version using #define directives. - #define _CRTDBG_MAP_ALLOC - #include - #include - // Replace operator new by trace-enabled version. - #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) - #define new DEBUG_NEW -#endif - -#if !defined(FLATBUFFERS_ASSERT) -#include -#define FLATBUFFERS_ASSERT assert -#elif defined(FLATBUFFERS_ASSERT_INCLUDE) -// Include file with forward declaration -#include FLATBUFFERS_ASSERT_INCLUDE -#endif - -#ifndef ARDUINO -#include -#endif - -#include -#include -#include - -#if defined(ARDUINO) && !defined(ARDUINOSTL_M_H) && defined(__AVR__) - #include -#else - #include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__unix__) && !defined(FLATBUFFERS_LOCALE_INDEPENDENT) - #include -#endif - -#ifdef __ANDROID__ - #include -#endif - -#if defined(__ICCARM__) -#include -#endif - -// Note the __clang__ check is needed, because clang presents itself -// as an older GNUC compiler (4.2). -// Clang 3.3 and later implement all of the ISO C++ 2011 standard. -// Clang 3.4 and later implement all of the ISO C++ 2014 standard. -// http://clang.llvm.org/cxx_status.html - -// Note the MSVC value '__cplusplus' may be incorrect: -// The '__cplusplus' predefined macro in the MSVC stuck at the value 199711L, -// indicating (erroneously!) that the compiler conformed to the C++98 Standard. -// This value should be correct starting from MSVC2017-15.7-Preview-3. -// The '__cplusplus' will be valid only if MSVC2017-15.7-P3 and the `/Zc:__cplusplus` switch is set. -// Workaround (for details see MSDN): -// Use the _MSC_VER and _MSVC_LANG definition instead of the __cplusplus for compatibility. -// The _MSVC_LANG macro reports the Standard version regardless of the '/Zc:__cplusplus' switch. - -#if defined(__GNUC__) && !defined(__clang__) - #define FLATBUFFERS_GCC (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) -#else - #define FLATBUFFERS_GCC 0 -#endif - -#if defined(__clang__) - #define FLATBUFFERS_CLANG (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) -#else - #define FLATBUFFERS_CLANG 0 -#endif - -/// @cond FLATBUFFERS_INTERNAL -#if __cplusplus <= 199711L && \ - (!defined(_MSC_VER) || _MSC_VER < 1600) && \ - (!defined(__GNUC__) || \ - (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400)) - #error A C++11 compatible compiler with support for the auto typing is \ - required for FlatBuffers. - #error __cplusplus _MSC_VER __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__ -#endif - -#if !defined(__clang__) && \ - defined(__GNUC__) && \ - (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600) - // Backwards compatibility for g++ 4.4, and 4.5 which don't have the nullptr - // and constexpr keywords. Note the __clang__ check is needed, because clang - // presents itself as an older GNUC compiler. - #ifndef nullptr_t - const class nullptr_t { - public: - template inline operator T*() const { return 0; } - private: - void operator&() const; - } nullptr = {}; - #endif - #ifndef constexpr - #define constexpr const - #endif -#endif - -// The wire format uses a little endian encoding (since that's efficient for -// the common platforms). -#if defined(__s390x__) - #define FLATBUFFERS_LITTLEENDIAN 0 -#endif // __s390x__ -#if !defined(FLATBUFFERS_LITTLEENDIAN) - #if defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__) - #if (defined(__BIG_ENDIAN__) || \ - (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) - #define FLATBUFFERS_LITTLEENDIAN 0 - #else - #define FLATBUFFERS_LITTLEENDIAN 1 - #endif // __BIG_ENDIAN__ - #elif defined(_MSC_VER) - #if defined(_M_PPC) - #define FLATBUFFERS_LITTLEENDIAN 0 - #else - #define FLATBUFFERS_LITTLEENDIAN 1 - #endif - #else - #error Unable to determine endianness, define FLATBUFFERS_LITTLEENDIAN. - #endif -#endif // !defined(FLATBUFFERS_LITTLEENDIAN) - -#define FLATBUFFERS_VERSION_MAJOR 24 -#define FLATBUFFERS_VERSION_MINOR 3 -#define FLATBUFFERS_VERSION_REVISION 25 -#define FLATBUFFERS_STRING_EXPAND(X) #X -#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X) -namespace flatbuffers { - // Returns version as string "MAJOR.MINOR.REVISION". - const char* FLATBUFFERS_VERSION(); -} - -#if (!defined(_MSC_VER) || _MSC_VER > 1600) && \ - (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407)) || \ - defined(__clang__) - #define FLATBUFFERS_FINAL_CLASS final - #define FLATBUFFERS_OVERRIDE override - #define FLATBUFFERS_EXPLICIT_CPP11 explicit - #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE : ::flatbuffers::voffset_t -#else - #define FLATBUFFERS_FINAL_CLASS - #define FLATBUFFERS_OVERRIDE - #define FLATBUFFERS_EXPLICIT_CPP11 - #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE -#endif - -#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \ - (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \ - (defined(__cpp_constexpr) && __cpp_constexpr >= 200704) - #define FLATBUFFERS_CONSTEXPR constexpr - #define FLATBUFFERS_CONSTEXPR_CPP11 constexpr - #define FLATBUFFERS_CONSTEXPR_DEFINED -#else - #define FLATBUFFERS_CONSTEXPR const - #define FLATBUFFERS_CONSTEXPR_CPP11 -#endif - -#if (defined(__cplusplus) && __cplusplus >= 201402L) || \ - (defined(__cpp_constexpr) && __cpp_constexpr >= 201304) - #define FLATBUFFERS_CONSTEXPR_CPP14 FLATBUFFERS_CONSTEXPR_CPP11 -#else - #define FLATBUFFERS_CONSTEXPR_CPP14 -#endif - -#if (defined(__GXX_EXPERIMENTAL_CXX0X__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \ - (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023026)) || \ - defined(__clang__) - #define FLATBUFFERS_NOEXCEPT noexcept -#else - #define FLATBUFFERS_NOEXCEPT -#endif - -// NOTE: the FLATBUFFERS_DELETE_FUNC macro may change the access mode to -// private, so be sure to put it at the end or reset access mode explicitly. -#if (!defined(_MSC_VER) || _MSC_FULL_VER >= 180020827) && \ - (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)) || \ - defined(__clang__) - #define FLATBUFFERS_DELETE_FUNC(func) func = delete -#else - #define FLATBUFFERS_DELETE_FUNC(func) private: func -#endif - -#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \ - (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)) || \ - defined(__clang__) - #define FLATBUFFERS_DEFAULT_DECLARATION -#endif - -// Check if we can use template aliases -// Not possible if Microsoft Compiler before 2012 -// Possible is the language feature __cpp_alias_templates is defined well -// Or possible if the C++ std is C+11 or newer -#if (defined(_MSC_VER) && _MSC_VER > 1700 /* MSVC2012 */) \ - || (defined(__cpp_alias_templates) && __cpp_alias_templates >= 200704) \ - || (defined(__cplusplus) && __cplusplus >= 201103L) - #define FLATBUFFERS_TEMPLATES_ALIASES -#endif - -#ifndef FLATBUFFERS_HAS_STRING_VIEW - // Only provide flatbuffers::string_view if __has_include can be used - // to detect a header that provides an implementation - #if defined(__has_include) - // Check for std::string_view (in c++17) - #if __has_include() && (__cplusplus >= 201606 || (defined(_HAS_CXX17) && _HAS_CXX17)) - #include - namespace flatbuffers { - typedef std::string_view string_view; - } - #define FLATBUFFERS_HAS_STRING_VIEW 1 - // Check for std::experimental::string_view (in c++14, compiler-dependent) - #elif __has_include() && (__cplusplus >= 201411) - #include - namespace flatbuffers { - typedef std::experimental::string_view string_view; - } - #define FLATBUFFERS_HAS_STRING_VIEW 1 - // Check for absl::string_view - #elif __has_include("absl/strings/string_view.h") && \ - __has_include("absl/base/config.h") && \ - (__cplusplus >= 201411) - #include "absl/base/config.h" - #if !defined(ABSL_USES_STD_STRING_VIEW) - #include "absl/strings/string_view.h" - namespace flatbuffers { - typedef absl::string_view string_view; - } - #define FLATBUFFERS_HAS_STRING_VIEW 1 - #endif - #endif - #endif // __has_include -#endif // !FLATBUFFERS_HAS_STRING_VIEW - -#ifndef FLATBUFFERS_GENERAL_HEAP_ALLOC_OK - // Allow heap allocations to be used - #define FLATBUFFERS_GENERAL_HEAP_ALLOC_OK 1 -#endif // !FLATBUFFERS_GENERAL_HEAP_ALLOC_OK - -#ifndef FLATBUFFERS_HAS_NEW_STRTOD - // Modern (C++11) strtod and strtof functions are available for use. - // 1) nan/inf strings as argument of strtod; - // 2) hex-float as argument of strtod/strtof. - #if (defined(_MSC_VER) && _MSC_VER >= 1900) || \ - (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)) || \ - (defined(__clang__)) - #define FLATBUFFERS_HAS_NEW_STRTOD 1 - #endif -#endif // !FLATBUFFERS_HAS_NEW_STRTOD - -#ifndef FLATBUFFERS_LOCALE_INDEPENDENT - // Enable locale independent functions {strtof_l, strtod_l,strtoll_l, - // strtoull_l}. - #if (defined(_MSC_VER) && _MSC_VER >= 1800) || \ - (defined(__ANDROID_API__) && __ANDROID_API__>= 21) || \ - (defined(_XOPEN_VERSION) && (_XOPEN_VERSION >= 700)) && \ - (!defined(__Fuchsia__) && !defined(__ANDROID_API__)) - #define FLATBUFFERS_LOCALE_INDEPENDENT 1 - #else - #define FLATBUFFERS_LOCALE_INDEPENDENT 0 - #endif -#endif // !FLATBUFFERS_LOCALE_INDEPENDENT - -// Suppress Undefined Behavior Sanitizer (recoverable only). Usage: -// - FLATBUFFERS_SUPPRESS_UBSAN("undefined") -// - FLATBUFFERS_SUPPRESS_UBSAN("signed-integer-overflow") -#if defined(__clang__) && (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >=7)) - #define FLATBUFFERS_SUPPRESS_UBSAN(type) __attribute__((no_sanitize(type))) -#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409) - #define FLATBUFFERS_SUPPRESS_UBSAN(type) __attribute__((no_sanitize_undefined)) -#else - #define FLATBUFFERS_SUPPRESS_UBSAN(type) -#endif - -namespace flatbuffers { - // This is constexpr function used for checking compile-time constants. - // Avoid `#pragma warning(disable: 4127) // C4127: expression is constant`. - template FLATBUFFERS_CONSTEXPR inline bool IsConstTrue(T t) { - return !!t; - } -} - -// Enable C++ attribute [[]] if std:c++17 or higher. -#if ((__cplusplus >= 201703L) \ - || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L))) - // All attributes unknown to an implementation are ignored without causing an error. - #define FLATBUFFERS_ATTRIBUTE(attr) attr - - #define FLATBUFFERS_FALLTHROUGH() [[fallthrough]] -#else - #define FLATBUFFERS_ATTRIBUTE(attr) - - #if FLATBUFFERS_CLANG >= 30800 - #define FLATBUFFERS_FALLTHROUGH() [[clang::fallthrough]] - #elif FLATBUFFERS_GCC >= 70300 - #define FLATBUFFERS_FALLTHROUGH() [[gnu::fallthrough]] - #else - #define FLATBUFFERS_FALLTHROUGH() - #endif -#endif - -/// @endcond - -/// @file -namespace flatbuffers { - -/// @cond FLATBUFFERS_INTERNAL -// Our default offset / size type, 32bit on purpose on 64bit systems. -// Also, using a consistent offset type maintains compatibility of serialized -// offset values between 32bit and 64bit systems. -typedef uint32_t uoffset_t; -typedef uint64_t uoffset64_t; - -// Signed offsets for references that can go in both directions. -typedef int32_t soffset_t; -typedef int64_t soffset64_t; - -// Offset/index used in v-tables, can be changed to uint8_t in -// format forks to save a bit of space if desired. -typedef uint16_t voffset_t; - -typedef uintmax_t largest_scalar_t; - -// In 32bits, this evaluates to 2GB - 1 -#define FLATBUFFERS_MAX_BUFFER_SIZE std::numeric_limits<::flatbuffers::soffset_t>::max() -#define FLATBUFFERS_MAX_64_BUFFER_SIZE std::numeric_limits<::flatbuffers::soffset64_t>::max() - -// The minimum size buffer that can be a valid flatbuffer. -// Includes the offset to the root table (uoffset_t), the offset to the vtable -// of the root table (soffset_t), the size of the vtable (uint16_t), and the -// size of the referring table (uint16_t). -#define FLATBUFFERS_MIN_BUFFER_SIZE sizeof(uoffset_t) + sizeof(soffset_t) + \ - sizeof(uint16_t) + sizeof(uint16_t) - -// We support aligning the contents of buffers up to this size. -#ifndef FLATBUFFERS_MAX_ALIGNMENT - #define FLATBUFFERS_MAX_ALIGNMENT 32 -#endif - -/// @brief The length of a FlatBuffer file header. -static const size_t kFileIdentifierLength = 4; - -inline bool VerifyAlignmentRequirements(size_t align, size_t min_align = 1) { - return (min_align <= align) && (align <= (FLATBUFFERS_MAX_ALIGNMENT)) && - (align & (align - 1)) == 0; // must be power of 2 -} - -#if defined(_MSC_VER) - #pragma warning(push) - #pragma warning(disable: 4127) // C4127: conditional expression is constant -#endif - -template T EndianSwap(T t) { - #if defined(_MSC_VER) - #define FLATBUFFERS_BYTESWAP16 _byteswap_ushort - #define FLATBUFFERS_BYTESWAP32 _byteswap_ulong - #define FLATBUFFERS_BYTESWAP64 _byteswap_uint64 - #elif defined(__ICCARM__) - #define FLATBUFFERS_BYTESWAP16 __REV16 - #define FLATBUFFERS_BYTESWAP32 __REV - #define FLATBUFFERS_BYTESWAP64(x) \ - ((__REV(static_cast(x >> 32U))) | (static_cast(__REV(static_cast(x)))) << 32U) - #else - #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ < 408 && !defined(__clang__) - // __builtin_bswap16 was missing prior to GCC 4.8. - #define FLATBUFFERS_BYTESWAP16(x) \ - static_cast(__builtin_bswap32(static_cast(x) << 16)) - #else - #define FLATBUFFERS_BYTESWAP16 __builtin_bswap16 - #endif - #define FLATBUFFERS_BYTESWAP32 __builtin_bswap32 - #define FLATBUFFERS_BYTESWAP64 __builtin_bswap64 - #endif - if (sizeof(T) == 1) { // Compile-time if-then's. - return t; - } else if (sizeof(T) == 2) { - union { T t; uint16_t i; } u = { t }; - u.i = FLATBUFFERS_BYTESWAP16(u.i); - return u.t; - } else if (sizeof(T) == 4) { - union { T t; uint32_t i; } u = { t }; - u.i = FLATBUFFERS_BYTESWAP32(u.i); - return u.t; - } else if (sizeof(T) == 8) { - union { T t; uint64_t i; } u = { t }; - u.i = FLATBUFFERS_BYTESWAP64(u.i); - return u.t; - } else { - FLATBUFFERS_ASSERT(0); - return t; - } -} - -#if defined(_MSC_VER) - #pragma warning(pop) -#endif - - -template T EndianScalar(T t) { - #if FLATBUFFERS_LITTLEENDIAN - return t; - #else - return EndianSwap(t); - #endif -} - -template -// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details. -FLATBUFFERS_SUPPRESS_UBSAN("alignment") -T ReadScalar(const void *p) { - return EndianScalar(*reinterpret_cast(p)); -} - -// See https://github.com/google/flatbuffers/issues/5950 - -#if (FLATBUFFERS_GCC >= 100000) && (FLATBUFFERS_GCC < 110000) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wstringop-overflow" -#endif - -template -// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details. -FLATBUFFERS_SUPPRESS_UBSAN("alignment") -void WriteScalar(void *p, T t) { - *reinterpret_cast(p) = EndianScalar(t); -} - -template struct Offset; -template FLATBUFFERS_SUPPRESS_UBSAN("alignment") void WriteScalar(void *p, Offset t) { - *reinterpret_cast(p) = EndianScalar(t.o); -} - -#if (FLATBUFFERS_GCC >= 100000) && (FLATBUFFERS_GCC < 110000) - #pragma GCC diagnostic pop -#endif - -// Computes how many bytes you'd have to pad to be able to write an -// "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in -// memory). -FLATBUFFERS_SUPPRESS_UBSAN("unsigned-integer-overflow") -inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) { - return ((~buf_size) + 1) & (scalar_size - 1); -} - -// Generic 'operator==' with conditional specialisations. -// T e - new value of a scalar field. -// T def - default of scalar (is known at compile-time). -template inline bool IsTheSameAs(T e, T def) { return e == def; } - -#if defined(FLATBUFFERS_NAN_DEFAULTS) && \ - defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0) -// Like `operator==(e, def)` with weak NaN if T=(float|double). -template inline bool IsFloatTheSameAs(T e, T def) { - return (e == def) || ((def != def) && (e != e)); -} -template<> inline bool IsTheSameAs(float e, float def) { - return IsFloatTheSameAs(e, def); -} -template<> inline bool IsTheSameAs(double e, double def) { - return IsFloatTheSameAs(e, def); -} -#endif - -// Check 'v' is out of closed range [low; high]. -// Workaround for GCC warning [-Werror=type-limits]: -// comparison is always true due to limited range of data type. -template -inline bool IsOutRange(const T &v, const T &low, const T &high) { - return (v < low) || (high < v); -} - -// Check 'v' is in closed range [low; high]. -template -inline bool IsInRange(const T &v, const T &low, const T &high) { - return !IsOutRange(v, low, high); -} - -} // namespace flatbuffers -#endif // FLATBUFFERS_BASE_H_ diff --git a/3rdparty/minicoro/CMakeLists.txt b/3rdparty/minicoro/CMakeLists.txt deleted file mode 100644 index 9508d8445..000000000 --- a/3rdparty/minicoro/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -add_library(minicoro INTERFACE) - -add_library(minicoro::minicoro ALIAS minicoro) - -target_include_directories(minicoro - INTERFACE - ${CMAKE_CURRENT_SOURCE_DIR} -) diff --git a/3rdparty/minicoro/LICENSE b/3rdparty/minicoro/LICENSE deleted file mode 100644 index 2c46487fe..000000000 --- a/3rdparty/minicoro/LICENSE +++ /dev/null @@ -1,47 +0,0 @@ -This software is available as a choice of the following licenses. Choose -whichever you prefer. - -=============================================================================== -ALTERNATIVE 1 - Public Domain (www.unlicense.org) -=============================================================================== -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. - -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to - -=============================================================================== -ALTERNATIVE 2 - MIT No Attribution -=============================================================================== -Copyright (c) 2021-2022 Eduardo Bart (https://github.com/edubart/minicoro) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/3rdparty/minicoro/README.md b/3rdparty/minicoro/README.md deleted file mode 100644 index d4c7743e9..000000000 --- a/3rdparty/minicoro/README.md +++ /dev/null @@ -1,357 +0,0 @@ -# minicoro - -Minicoro is single-file library for using asymmetric coroutines in C. -The API is inspired by [Lua coroutines](https://www.lua.org/manual/5.4/manual.html#6.2) but with C use in mind. - -The project is being developed mainly to be a coroutine backend -for the [Nelua](https://github.com/edubart/nelua-lang) programming language. - -The library assembly implementation is inspired by [Lua Coco](https://coco.luajit.org/index.html) by Mike Pall. - -# Features - -- Stackful asymmetric coroutines. -- Supports nesting coroutines (resuming a coroutine from another coroutine). -- Supports custom allocators. -- Storage system to allow passing values between yield and resume. -- Customizable stack size. -- Coroutine API design inspired by Lua with C use in mind. -- Yield across any C function. -- Made to work in multithread applications. -- Cross platform. -- Minimal, self contained and no external dependencies. -- Readable sources and documented. -- Implemented via assembly, ucontext or fibers. -- Lightweight and very efficient. -- Works in most C89 compilers. -- Error prone API, returning proper error codes on misuse. -- Support running with Valgrind, ASan (AddressSanitizer) and TSan (ThreadSanitizer). - -# Supported Platforms - -Most platforms are supported through different methods: - -| Platform | Assembly Method | Fallback Method | -|--------------|------------------|-------------------| -| Android | ARM/ARM64 | N/A | -| iOS | ARM/ARM64 | N/A | -| Windows | x86_64 | Windows fibers | -| Linux | x86_64/i686 | ucontext | -| Mac OS X | x86_64/ARM/ARM64 | ucontext | -| WebAssembly | N/A | Emscripten fibers / Binaryen asyncify | -| Raspberry Pi | ARM | ucontext | -| RISC-V | rv64/rv32 | ucontext | - -The assembly method is used by default if supported by the compiler and CPU, -otherwise ucontext or fiber method is used as a fallback. - -The assembly method is very efficient, it just take a few cycles -to create, resume, yield or destroy a coroutine. - -# Caveats - -- Don't use coroutines with C++ exceptions, this is not supported. -- When using C++ RAII (i.e. destructors) you must resume the coroutine until it dies to properly execute all destructors. -- To use in multithread applications, you must compile with C compiler that supports `thread_local` qualifier. -- Some unsupported sanitizers for C may trigger false warnings when using coroutines. -- The `mco_coro` object is not thread safe, you should lock each coroutine into a thread. -- Stack space is fixed, it cannot grow. By default it has about 56KB of space, this can be changed on coroutine creation. -- Take care to not cause stack overflows (run out of stack space), otherwise your program may crash or not, the behavior is undefined. -- On WebAssembly you must compile with Emscripten flag `-s ASYNCIFY=1`. -- The WebAssembly Binaryen asyncify method can be used when explicitly enabled, -you may want to do this only to use minicoro with WebAssembly native interpreters -(no Web browser). This method is confirmed to work well with Emscripten toolchain, -however it fails on other WebAssembly toolchains like WASI SDK. - -# Introduction - -A coroutine represents an independent "green" thread of execution. -Unlike threads in multithread systems, however, -a coroutine only suspends its execution by explicitly calling a yield function. - -You create a coroutine by calling `mco_create`. -Its sole argument is a `mco_desc` structure with a description for the coroutine. -The `mco_create` function only creates a new coroutine and returns a handle to it, it does not start the coroutine. - -You execute a coroutine by calling `mco_resume`. -When calling a resume function the coroutine starts its execution by calling its body function. -After the coroutine starts running, it runs until it terminates or yields. - -A coroutine yields by calling `mco_yield`. -When a coroutine yields, the corresponding resume returns immediately, -even if the yield happens inside nested function calls (that is, not in the main function). -The next time you resume the same coroutine, it continues its execution from the point where it yielded. - -To associate a persistent value with the coroutine, -you can optionally set `user_data` on its creation and later retrieve with `mco_get_user_data`. - -To pass values between resume and yield, -you can optionally use `mco_push` and `mco_pop` APIs, -they are intended to pass temporary values using a LIFO (Last In, First Out) style buffer. -The storage system can also be used to send and receive initial values on coroutine creation or before it finishes. - -# Usage - -To use minicoro, do the following in one .c file: - -```c -#define MINICORO_IMPL -#include "minicoro.h" -``` - -You can do `#include "minicoro.h"` in other parts of the program just like any other header. - -## Minimal Example - -The following simple example demonstrates on how to use the library: - -```c -#define MINICORO_IMPL -#include "minicoro.h" -#include - -// Coroutine entry function. -void coro_entry(mco_coro* co) { - printf("coroutine 1\n"); - mco_yield(co); - printf("coroutine 2\n"); -} - -int main() { - // First initialize a `desc` object through `mco_desc_init`. - mco_desc desc = mco_desc_init(coro_entry, 0); - // Configure `desc` fields when needed (e.g. customize user_data or allocation functions). - desc.user_data = NULL; - // Call `mco_create` with the output coroutine pointer and `desc` pointer. - mco_coro* co; - mco_result res = mco_create(&co, &desc); - assert(res == MCO_SUCCESS); - // The coroutine should be now in suspended state. - assert(mco_status(co) == MCO_SUSPENDED); - // Call `mco_resume` to start for the first time, switching to its context. - res = mco_resume(co); // Should print "coroutine 1". - assert(res == MCO_SUCCESS); - // We get back from coroutine context in suspended state (because it's unfinished). - assert(mco_status(co) == MCO_SUSPENDED); - // Call `mco_resume` to resume for a second time. - res = mco_resume(co); // Should print "coroutine 2". - assert(res == MCO_SUCCESS); - // The coroutine finished and should be now dead. - assert(mco_status(co) == MCO_DEAD); - // Call `mco_destroy` to destroy the coroutine. - res = mco_destroy(co); - assert(res == MCO_SUCCESS); - return 0; -} -``` - -_NOTE_: In case you don't want to use the minicoro allocator system you should -allocate a coroutine object yourself using `mco_desc.coro_size` and call `mco_init`, -then later to destroy call `mco_uninit` and deallocate it. - -## Yielding from anywhere - -You can yield the current running coroutine from anywhere -without having to pass `mco_coro` pointers around, -to this just use `mco_yield(mco_running())`. - -## Passing data between yield and resume - -The library has the storage interface to assist passing data between yield and resume. -It's usage is straightforward, -use `mco_push` to send data before a `mco_resume` or `mco_yield`, -then later use `mco_pop` after a `mco_resume` or `mco_yield` to receive data. -Take care to not mismatch a push and pop, otherwise these functions will return -an error. - -## Error handling - -The library return error codes in most of its API in case of misuse or system error, -the user is encouraged to handle them properly. - -## Library customization - -The following can be defined to change the library behavior: - -- `MCO_API` - Public API qualifier. Default is `extern`. -- `MCO_MIN_STACK_SIZE` - Minimum stack size when creating a coroutine. Default is 32768. -- `MCO_DEFAULT_STORAGE_SIZE` - Size of coroutine storage buffer. Default is 1024. -- `MCO_DEFAULT_STACK_SIZE` - Default stack size when creating a coroutine. Default is 57344. -- `MCO_MALLOC` - Default allocation function. Default is `malloc`. -- `MCO_FREE` - Default deallocation function. Default is `free`. -- `MCO_DEBUG` - Enable debug mode, logging any runtime error to stdout. Defined automatically unless `NDEBUG` or `MCO_NO_DEBUG` is defined. -- `MCO_NO_DEBUG` - Disable debug mode. -- `MCO_NO_MULTITHREAD` - Disable multithread usage. Multithread is supported when `thread_local` is supported. -- `MCO_NO_DEFAULT_ALLOCATORS` - Disable the default allocator using `MCO_MALLOC` and `MCO_FREE`. -- `MCO_ZERO_MEMORY` - Zero memory of stack for new coroutines and when poping storage, intended for garbage collected environments. -- `MCO_USE_ASM` - Force use of assembly context switch implementation. -- `MCO_USE_UCONTEXT` - Force use of ucontext context switch implementation. -- `MCO_USE_FIBERS` - Force use of fibers context switch implementation. -- `MCO_USE_ASYNCIFY` - Force use of Binaryen asyncify context switch implementation. -- `MCO_USE_VALGRIND` - Define if you want run with valgrind to fix accessing memory errors. - -# Benchmarks - -The coroutine library was benchmarked for x86_64 counting CPU cycles -for context switch (triggered in resume or yield) and initialization. - -| CPU Arch | OS | Method | Context switch | Initialize | Uninitialize | -|----------|----------|----------|----------------|--------------|--------------| -| x86_64 | Linux | assembly | 9 cycles | 31 cycles | 14 cycles | -| x86_64 | Linux | ucontext | 352 cycles | 383 cycles | 14 cycles | -| x86_64 | Windows | fibers | 69 cycles | 10564 cycles | 11167 cycles | -| x86_64 | Windows | assembly | 33 cycles | 74 cycles | 14 cycles | - -_NOTE_: Tested on Intel Core i7-8750H CPU @ 2.20GHz with pre allocated coroutines. - -# Cheatsheet - -Here is a list of all library functions for quick reference: - -```c -/* Structure used to initialize a coroutine. */ -typedef struct mco_desc { - void (*func)(mco_coro* co); /* Entry point function for the coroutine. */ - void* user_data; /* Coroutine user data, can be get with `mco_get_user_data`. */ - /* Custom allocation interface. */ - void* (*malloc_cb)(size_t size, void* allocator_data); /* Custom allocation function. */ - void (*free_cb)(void* ptr, void* allocator_data); /* Custom deallocation function. */ - void* allocator_data; /* User data pointer passed to `malloc`/`free` allocation functions. */ - size_t storage_size; /* Coroutine storage size, to be used with the storage APIs. */ - /* These must be initialized only through `mco_init_desc`. */ - size_t coro_size; /* Coroutine structure size. */ - size_t stack_size; /* Coroutine stack size. */ -} mco_desc; - -/* Coroutine functions. */ -mco_desc mco_desc_init(void (*func)(mco_coro* co), size_t stack_size); /* Initialize description of a coroutine. When stack size is 0 then MCO_DEFAULT_STACK_SIZE is used. */ -mco_result mco_init(mco_coro* co, mco_desc* desc); /* Initialize the coroutine. */ -mco_result mco_uninit(mco_coro* co); /* Uninitialize the coroutine, may fail if it's not dead or suspended. */ -mco_result mco_create(mco_coro** out_co, mco_desc* desc); /* Allocates and initializes a new coroutine. */ -mco_result mco_destroy(mco_coro* co); /* Uninitialize and deallocate the coroutine, may fail if it's not dead or suspended. */ -mco_result mco_resume(mco_coro* co); /* Starts or continues the execution of the coroutine. */ -mco_result mco_yield(mco_coro* co); /* Suspends the execution of a coroutine. */ -mco_state mco_status(mco_coro* co); /* Returns the status of the coroutine. */ -void* mco_get_user_data(mco_coro* co); /* Get coroutine user data supplied on coroutine creation. */ - -/* Storage interface functions, used to pass values between yield and resume. */ -mco_result mco_push(mco_coro* co, const void* src, size_t len); /* Push bytes to the coroutine storage. Use to send values between yield and resume. */ -mco_result mco_pop(mco_coro* co, void* dest, size_t len); /* Pop bytes from the coroutine storage. Use to get values between yield and resume. */ -mco_result mco_peek(mco_coro* co, void* dest, size_t len); /* Like `mco_pop` but it does not consumes the storage. */ -size_t mco_get_bytes_stored(mco_coro* co); /* Get the available bytes that can be retrieved with a `mco_pop`. */ -size_t mco_get_storage_size(mco_coro* co); /* Get the total storage size. */ - -/* Misc functions. */ -mco_coro* mco_running(void); /* Returns the running coroutine for the current thread. */ -const char* mco_result_description(mco_result res); /* Get the description of a result. */ -``` - -# Complete Example - -The following is a more complete example, generating Fibonacci numbers: - -```c -#define MINICORO_IMPL -#include "minicoro.h" -#include - -static void fail(const char* message, mco_result res) { - printf("%s: %s\n", message, mco_result_description(res)); - exit(-1); -} - -static void fibonacci_coro(mco_coro* co) { - unsigned long m = 1; - unsigned long n = 1; - - /* Retrieve max value. */ - unsigned long max; - mco_result res = mco_pop(co, &max, sizeof(max)); - if(res != MCO_SUCCESS) - fail("Failed to retrieve coroutine storage", res); - - while(1) { - /* Yield the next Fibonacci number. */ - mco_push(co, &m, sizeof(m)); - res = mco_yield(co); - if(res != MCO_SUCCESS) - fail("Failed to yield coroutine", res); - - unsigned long tmp = m + n; - m = n; - n = tmp; - if(m >= max) - break; - } - - /* Yield the last Fibonacci number. */ - mco_push(co, &m, sizeof(m)); -} - -int main() { - /* Create the coroutine. */ - mco_coro* co; - mco_desc desc = mco_desc_init(fibonacci_coro, 0); - mco_result res = mco_create(&co, &desc); - if(res != MCO_SUCCESS) - fail("Failed to create coroutine", res); - - /* Set storage. */ - unsigned long max = 1000000000; - mco_push(co, &max, sizeof(max)); - - int counter = 1; - while(mco_status(co) == MCO_SUSPENDED) { - /* Resume the coroutine. */ - res = mco_resume(co); - if(res != MCO_SUCCESS) - fail("Failed to resume coroutine", res); - - /* Retrieve storage set in last coroutine yield. */ - unsigned long ret = 0; - res = mco_pop(co, &ret, sizeof(ret)); - if(res != MCO_SUCCESS) - fail("Failed to retrieve coroutine storage", res); - printf("fib %d = %lu\n", counter, ret); - counter = counter + 1; - } - - /* Destroy the coroutine. */ - res = mco_destroy(co); - if(res != MCO_SUCCESS) - fail("Failed to destroy coroutine", res); - return 0; -} -``` - -# Updates - -- **08-Jun-2022**: Minicoro has been awarded by the [Icculus Microgrant 2021](https://icculus.org/microgrant/), thanks @icculus for supporting open source work. -- **26-Jan-2022**: Added support for WebAssembly outside the WebBrowser using Binaryen asyncify pass. -- **01-Sep-2021**: Added support for DOSBox (MS-DOS Emulator). -- **30-Aug-2021**: Fix stack overflow crash on Windows 32 bits. -- **22-Aug-2021**: Added checks for stack overflow and iOS support (thanks @srberg). -- **12-Mar-2021**: Added support for RISC-V RV32. -- **19-Jan-2021**: Fix compilation and issues on Mac OS X, release v0.1.1. -- **19-Jan-2021**: First release, v0.1.0. -- **18-Jan-2021**: Fix issues when using Clang on Linux. -- **17-Jan-2021**: Add support for RISC-V 64 bits. -- **16-Jan-2021**: Add support for Mac OS X x86_64, thanks @RandyGaul for testing, debugging and researching about it. -- **15-Jan-2021**: Make assembly method the default one on Windows x86_64. Redesigned the storage API, thanks @RandyGaul for the suggestion. -- **14-Jan-2021**: Add support for running with ASan (AddressSanitizer) and TSan (ThreadSanitizer). -- **13-Jan-2021**: Add support for ARM and WebAssembly. Add Public Domain and MIT No Attribution license. -- **12-Jan-2021**: Some API changes and improvements. -- **11-Jan-2021**: Support valgrind and add benchmarks. -- **10-Jan-2021**: Minor API improvements and document more. -- **09-Jan-2021**: Library created. - -# Donation - -I'm a full-time open source developer. -Any amount of the donation will be appreciated and could bring me encouragement to keep supporting this and other open source projects. - -[![Become a Patron](https://c5.patreon.com/external/logo/become_a_patron_button.png)](https://www.patreon.com/edubart) - -# License - -Your choice of either Public Domain or MIT No Attribution, see LICENSE file. diff --git a/3rdparty/minicoro/minicoro.h b/3rdparty/minicoro/minicoro.h deleted file mode 100644 index a93421db0..000000000 --- a/3rdparty/minicoro/minicoro.h +++ /dev/null @@ -1,1965 +0,0 @@ -/* -Minimal asymmetric stackful cross-platform coroutine library in pure C. -minicoro - v0.1.3 - 27/Jan/2022 -Eduardo Bart - edub4rt@gmail.com -https://github.com/edubart/minicoro - -Minicoro is single file library for using asymmetric coroutines in C. -The API is inspired by Lua coroutines but with C use in mind. - -# Features - -- Stackful asymmetric coroutines. -- Supports nesting coroutines (resuming a coroutine from another coroutine). -- Supports custom allocators. -- Storage system to allow passing values between yield and resume. -- Customizable stack size. -- Coroutine API design inspired by Lua with C use in mind. -- Yield across any C function. -- Made to work in multithread applications. -- Cross platform. -- Minimal, self contained and no external dependencies. -- Readable sources and documented. -- Implemented via assembly, ucontext or fibers. -- Lightweight and very efficient. -- Works in most C89 compilers. -- Error prone API, returning proper error codes on misuse. -- Support running with Valgrind, ASan (AddressSanitizer) and TSan (ThreadSanitizer). - -# Supported Platforms - -Most platforms are supported through different methods: - -| Platform | Assembly Method | Fallback Method | -|--------------|------------------|-------------------| -| Android | ARM/ARM64 | N/A | -| iOS | ARM/ARM64 | N/A | -| Windows | x86_64 | Windows fibers | -| Linux | x86_64/i686 | ucontext | -| Mac OS X | x86_64/ARM/ARM64 | ucontext | -| WebAssembly | N/A | Emscripten fibers / Binaryen asyncify | -| Raspberry Pi | ARM | ucontext | -| RISC-V | rv64/rv32 | ucontext | - -The assembly method is used by default if supported by the compiler and CPU, -otherwise ucontext or fiber method is used as a fallback. - -The assembly method is very efficient, it just take a few cycles -to create, resume, yield or destroy a coroutine. - -# Caveats - -- Don't use coroutines with C++ exceptions, this is not supported. -- When using C++ RAII (i.e. destructors) you must resume the coroutine until it dies to properly execute all destructors. -- To use in multithread applications, you must compile with C compiler that supports `thread_local` qualifier. -- Some unsupported sanitizers for C may trigger false warnings when using coroutines. -- The `mco_coro` object is not thread safe, you should lock each coroutine into a thread. -- Stack space is fixed, it cannot grow. By default it has about 56KB of space, this can be changed on coroutine creation. -- Take care to not cause stack overflows (run out of stack space), otherwise your program may crash or not, the behavior is undefined. -- On WebAssembly you must compile with Emscripten flag `-s ASYNCIFY=1`. -- The WebAssembly Binaryen asyncify method can be used when explicitly enabled, -you may want to do this only to use minicoro with WebAssembly native interpreters -(no Web browser). This method is confirmed to work well with Emscripten toolchain, -however it fails on other WebAssembly toolchains like WASI SDK. - -# Introduction - -A coroutine represents an independent "green" thread of execution. -Unlike threads in multithread systems, however, -a coroutine only suspends its execution by explicitly calling a yield function. - -You create a coroutine by calling `mco_create`. -Its sole argument is a `mco_desc` structure with a description for the coroutine. -The `mco_create` function only creates a new coroutine and returns a handle to it, it does not start the coroutine. - -You execute a coroutine by calling `mco_resume`. -When calling a resume function the coroutine starts its execution by calling its body function. -After the coroutine starts running, it runs until it terminates or yields. - -A coroutine yields by calling `mco_yield`. -When a coroutine yields, the corresponding resume returns immediately, -even if the yield happens inside nested function calls (that is, not in the main function). -The next time you resume the same coroutine, it continues its execution from the point where it yielded. - -To associate a persistent value with the coroutine, -you can optionally set `user_data` on its creation and later retrieve with `mco_get_user_data`. - -To pass values between resume and yield, -you can optionally use `mco_push` and `mco_pop` APIs, -they are intended to pass temporary values using a LIFO style buffer. -The storage system can also be used to send and receive initial values on coroutine creation or before it finishes. - -# Usage - -To use minicoro, do the following in one .c file: - -```c -#define MINICORO_IMPL -#include "minicoro.h" -``` - -You can do `#include "minicoro.h"` in other parts of the program just like any other header. - -## Minimal Example - -The following simple example demonstrates on how to use the library: - -```c -#define MINICORO_IMPL -#include "minicoro.h" -#include - -// Coroutine entry function. -void coro_entry(mco_coro* co) { - printf("coroutine 1\n"); - mco_yield(co); - printf("coroutine 2\n"); -} - -int main() { - // First initialize a `desc` object through `mco_desc_init`. - mco_desc desc = mco_desc_init(coro_entry, 0); - // Configure `desc` fields when needed (e.g. customize user_data or allocation functions). - desc.user_data = NULL; - // Call `mco_create` with the output coroutine pointer and `desc` pointer. - mco_coro* co; - mco_result res = mco_create(&co, &desc); - assert(res == MCO_SUCCESS); - // The coroutine should be now in suspended state. - assert(mco_status(co) == MCO_SUSPENDED); - // Call `mco_resume` to start for the first time, switching to its context. - res = mco_resume(co); // Should print "coroutine 1". - assert(res == MCO_SUCCESS); - // We get back from coroutine context in suspended state (because it's unfinished). - assert(mco_status(co) == MCO_SUSPENDED); - // Call `mco_resume` to resume for a second time. - res = mco_resume(co); // Should print "coroutine 2". - assert(res == MCO_SUCCESS); - // The coroutine finished and should be now dead. - assert(mco_status(co) == MCO_DEAD); - // Call `mco_destroy` to destroy the coroutine. - res = mco_destroy(co); - assert(res == MCO_SUCCESS); - return 0; -} -``` - -_NOTE_: In case you don't want to use the minicoro allocator system you should -allocate a coroutine object yourself using `mco_desc.coro_size` and call `mco_init`, -then later to destroy call `mco_uninit` and deallocate it. - -## Yielding from anywhere - -You can yield the current running coroutine from anywhere -without having to pass `mco_coro` pointers around, -to this just use `mco_yield(mco_running())`. - -## Passing data between yield and resume - -The library has the storage interface to assist passing data between yield and resume. -It's usage is straightforward, -use `mco_push` to send data before a `mco_resume` or `mco_yield`, -then later use `mco_pop` after a `mco_resume` or `mco_yield` to receive data. -Take care to not mismatch a push and pop, otherwise these functions will return -an error. - -## Error handling - -The library return error codes in most of its API in case of misuse or system error, -the user is encouraged to handle them properly. - -## Library customization - -The following can be defined to change the library behavior: - -- `MCO_API` - Public API qualifier. Default is `extern`. -- `MCO_MIN_STACK_SIZE` - Minimum stack size when creating a coroutine. Default is 32768. -- `MCO_DEFAULT_STORAGE_SIZE` - Size of coroutine storage buffer. Default is 1024. -- `MCO_DEFAULT_STACK_SIZE` - Default stack size when creating a coroutine. Default is 57344. -- `MCO_MALLOC` - Default allocation function. Default is `malloc`. -- `MCO_FREE` - Default deallocation function. Default is `free`. -- `MCO_DEBUG` - Enable debug mode, logging any runtime error to stdout. Defined automatically unless `NDEBUG` or `MCO_NO_DEBUG` is defined. -- `MCO_NO_DEBUG` - Disable debug mode. -- `MCO_NO_MULTITHREAD` - Disable multithread usage. Multithread is supported when `thread_local` is supported. -- `MCO_NO_DEFAULT_ALLOCATORS` - Disable the default allocator using `MCO_MALLOC` and `MCO_FREE`. -- `MCO_ZERO_MEMORY` - Zero memory of stack for new coroutines and when poping storage, intended for garbage collected environments. -- `MCO_USE_ASM` - Force use of assembly context switch implementation. -- `MCO_USE_UCONTEXT` - Force use of ucontext context switch implementation. -- `MCO_USE_FIBERS` - Force use of fibers context switch implementation. -- `MCO_USE_ASYNCIFY` - Force use of Binaryen asyncify context switch implementation. -- `MCO_USE_VALGRIND` - Define if you want run with valgrind to fix accessing memory errors. - -# License - -Your choice of either Public Domain or MIT No Attribution, see end of file. -*/ - - -#ifndef MINICORO_H -#define MINICORO_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Public API qualifier. */ -#ifndef MCO_API -#define MCO_API extern -#endif - -/* Size of coroutine storage buffer. */ -#ifndef MCO_DEFAULT_STORAGE_SIZE -#define MCO_DEFAULT_STORAGE_SIZE 1024 -#endif - -#include /* for size_t */ - -/* ---------------------------------------------------------------------------------------------- */ - -/* Coroutine states. */ -typedef enum mco_state { - MCO_DEAD = 0, /* The coroutine has finished normally or was uninitialized before finishing. */ - MCO_NORMAL, /* The coroutine is active but not running (that is, it has resumed another coroutine). */ - MCO_RUNNING, /* The coroutine is active and running. */ - MCO_SUSPENDED /* The coroutine is suspended (in a call to yield, or it has not started running yet). */ -} mco_state; - -/* Coroutine result codes. */ -typedef enum mco_result { - MCO_SUCCESS = 0, - MCO_GENERIC_ERROR, - MCO_INVALID_POINTER, - MCO_INVALID_COROUTINE, - MCO_NOT_SUSPENDED, - MCO_NOT_RUNNING, - MCO_MAKE_CONTEXT_ERROR, - MCO_SWITCH_CONTEXT_ERROR, - MCO_NOT_ENOUGH_SPACE, - MCO_OUT_OF_MEMORY, - MCO_INVALID_ARGUMENTS, - MCO_INVALID_OPERATION, - MCO_STACK_OVERFLOW, -} mco_result; - -/* Coroutine structure. */ -typedef struct mco_coro mco_coro; -struct mco_coro { - void* context; - mco_state state; - void (*func)(mco_coro* co); - mco_coro* prev_co; - void* user_data; - void* allocator_data; - void (*free_cb)(void* ptr, void* allocator_data); - void* stack_base; /* Stack base address, can be used to scan memory in a garbage collector. */ - size_t stack_size; - unsigned char* storage; - size_t bytes_stored; - size_t storage_size; - void* asan_prev_stack; /* Used by address sanitizer. */ - void* tsan_prev_fiber; /* Used by thread sanitizer. */ - void* tsan_fiber; /* Used by thread sanitizer. */ - size_t magic_number; /* Used to check stack overflow. */ -}; - -/* Structure used to initialize a coroutine. */ -typedef struct mco_desc { - void (*func)(mco_coro* co); /* Entry point function for the coroutine. */ - void* user_data; /* Coroutine user data, can be get with `mco_get_user_data`. */ - /* Custom allocation interface. */ - void* (*malloc_cb)(size_t size, void* allocator_data); /* Custom allocation function. */ - void (*free_cb)(void* ptr, void* allocator_data); /* Custom deallocation function. */ - void* allocator_data; /* User data pointer passed to `malloc`/`free` allocation functions. */ - size_t storage_size; /* Coroutine storage size, to be used with the storage APIs. */ - /* These must be initialized only through `mco_init_desc`. */ - size_t coro_size; /* Coroutine structure size. */ - size_t stack_size; /* Coroutine stack size. */ -} mco_desc; - -/* Coroutine functions. */ -MCO_API mco_desc mco_desc_init(void (*func)(mco_coro* co), size_t stack_size); /* Initialize description of a coroutine. When stack size is 0 then MCO_DEFAULT_STACK_SIZE is used. */ -MCO_API mco_result mco_init(mco_coro* co, mco_desc* desc); /* Initialize the coroutine. */ -MCO_API mco_result mco_uninit(mco_coro* co); /* Uninitialize the coroutine, may fail if it's not dead or suspended. */ -MCO_API mco_result mco_create(mco_coro** out_co, mco_desc* desc); /* Allocates and initializes a new coroutine. */ -MCO_API mco_result mco_destroy(mco_coro* co); /* Uninitialize and deallocate the coroutine, may fail if it's not dead or suspended. */ -MCO_API mco_result mco_resume(mco_coro* co); /* Starts or continues the execution of the coroutine. */ -MCO_API mco_result mco_yield(mco_coro* co); /* Suspends the execution of a coroutine. */ -MCO_API mco_state mco_status(mco_coro* co); /* Returns the status of the coroutine. */ -MCO_API void* mco_get_user_data(mco_coro* co); /* Get coroutine user data supplied on coroutine creation. */ - -/* Storage interface functions, used to pass values between yield and resume. */ -MCO_API mco_result mco_push(mco_coro* co, const void* src, size_t len); /* Push bytes to the coroutine storage. Use to send values between yield and resume. */ -MCO_API mco_result mco_pop(mco_coro* co, void* dest, size_t len); /* Pop bytes from the coroutine storage. Use to get values between yield and resume. */ -MCO_API mco_result mco_peek(mco_coro* co, void* dest, size_t len); /* Like `mco_pop` but it does not consumes the storage. */ -MCO_API size_t mco_get_bytes_stored(mco_coro* co); /* Get the available bytes that can be retrieved with a `mco_pop`. */ -MCO_API size_t mco_get_storage_size(mco_coro* co); /* Get the total storage size. */ - -/* Misc functions. */ -MCO_API mco_coro* mco_running(void); /* Returns the running coroutine for the current thread. */ -MCO_API const char* mco_result_description(mco_result res); /* Get the description of a result. */ - -#ifdef __cplusplus -} -#endif - -#endif /* MINICORO_H */ - -#ifdef MINICORO_IMPL - -#ifdef __cplusplus -extern "C" { -#endif - -/* ---------------------------------------------------------------------------------------------- */ - -/* Minimum stack size when creating a coroutine. */ -#ifndef MCO_MIN_STACK_SIZE -#define MCO_MIN_STACK_SIZE 32768 -#endif - -/* Default stack size when creating a coroutine. */ -#ifndef MCO_DEFAULT_STACK_SIZE -#define MCO_DEFAULT_STACK_SIZE 57344 /* Don't use multiples of 64K to avoid D-cache aliasing conflicts. */ -#endif - -/* Number used only to assist checking for stack overflows. */ -#define MCO_MAGIC_NUMBER 0x7E3CB1A9 - -/* Detect implementation based on OS, arch and compiler. */ -#if !defined(MCO_USE_UCONTEXT) && !defined(MCO_USE_FIBERS) && !defined(MCO_USE_ASM) && !defined(MCO_USE_ASYNCIFY) - #if defined(_WIN32) - #if (defined(__GNUC__) && defined(__x86_64__)) || (defined(_MSC_VER) && defined(_M_X64)) - #define MCO_USE_ASM - #else - #define MCO_USE_FIBERS - #endif - #elif defined(__CYGWIN__) /* MSYS */ - #define MCO_USE_UCONTEXT - #elif defined(__EMSCRIPTEN__) - #define MCO_USE_FIBERS - #elif defined(__wasm__) - #define MCO_USE_ASYNCIFY - #else - #if __GNUC__ >= 3 /* Assembly extension supported. */ - #if defined(__x86_64__) || \ - defined(__i386) || defined(__i386__) || \ - defined(__ARM_EABI__) || defined(__aarch64__) || \ - defined(__riscv) - #define MCO_USE_ASM - #else - #define MCO_USE_UCONTEXT - #endif - #else - #define MCO_USE_UCONTEXT - #endif - #endif -#endif - -#define _MCO_UNUSED(x) (void)(x) - -#if !defined(MCO_NO_DEBUG) && !defined(NDEBUG) && !defined(MCO_DEBUG) -#define MCO_DEBUG -#endif - -#ifndef MCO_LOG - #ifdef MCO_DEBUG - #include - #define MCO_LOG(s) puts(s) - #else - #define MCO_LOG(s) - #endif -#endif - -#ifndef MCO_ASSERT - #ifdef MCO_DEBUG - #include - #define MCO_ASSERT(c) assert(c) - #else - #define MCO_ASSERT(c) - #endif -#endif - -#ifndef MCO_THREAD_LOCAL - #ifdef MCO_NO_MULTITHREAD - #define MCO_THREAD_LOCAL - #else - #ifdef thread_local - #define MCO_THREAD_LOCAL thread_local - #elif __STDC_VERSION__ >= 201112 && !defined(__STDC_NO_THREADS__) - #define MCO_THREAD_LOCAL _Thread_local - #elif defined(_WIN32) && (defined(_MSC_VER) || defined(__ICL) || defined(__DMC__) || defined(__BORLANDC__)) - #define MCO_THREAD_LOCAL __declspec(thread) - #elif defined(__GNUC__) || defined(__SUNPRO_C) || defined(__xlC__) - #define MCO_THREAD_LOCAL __thread - #else /* No thread local support, `mco_running` will be thread unsafe. */ - #define MCO_THREAD_LOCAL - #define MCO_NO_MULTITHREAD - #endif - #endif -#endif - -#ifndef MCO_FORCE_INLINE - #ifdef _MSC_VER - #define MCO_FORCE_INLINE __forceinline - #elif defined(__GNUC__) - #if defined(__STRICT_ANSI__) - #define MCO_FORCE_INLINE __inline__ __attribute__((always_inline)) - #else - #define MCO_FORCE_INLINE inline __attribute__((always_inline)) - #endif - #elif defined(__BORLANDC__) || defined(__DMC__) || defined(__SC__) || defined(__WATCOMC__) || defined(__LCC__) || defined(__DECC) - #define MCO_FORCE_INLINE __inline - #else /* No inline support. */ - #define MCO_FORCE_INLINE - #endif -#endif - -#ifndef MCO_NO_INLINE - #ifdef __GNUC__ - #define MCO_NO_INLINE __attribute__((noinline)) - #elif defined(_MSC_VER) - #define MCO_NO_INLINE __declspec(noinline) - #else - #define MCO_NO_INLINE - #endif -#endif - -#ifndef MCO_NO_DEFAULT_ALLOCATORS -#ifndef MCO_MALLOC - #include - #define MCO_MALLOC malloc - #define MCO_FREE free -#endif -static void* mco_malloc(size_t size, void* allocator_data) { - _MCO_UNUSED(allocator_data); - return MCO_MALLOC(size); -} -static void mco_free(void* ptr, void* allocator_data) { - _MCO_UNUSED(allocator_data); - MCO_FREE(ptr); -} -#endif /* MCO_NO_DEFAULT_ALLOCATORS */ - -#if defined(__has_feature) - #if __has_feature(address_sanitizer) - #define _MCO_USE_ASAN - #endif - #if __has_feature(thread_sanitizer) - #define _MCO_USE_TSAN - #endif -#endif -#if defined(__SANITIZE_ADDRESS__) - #define _MCO_USE_ASAN -#endif -#if defined(__SANITIZE_THREAD__) - #define _MCO_USE_TSAN -#endif -#ifdef _MCO_USE_ASAN -void __sanitizer_start_switch_fiber(void** fake_stack_save, const void *bottom, size_t size); -void __sanitizer_finish_switch_fiber(void* fake_stack_save, const void **bottom_old, size_t *size_old); -#endif -#ifdef _MCO_USE_TSAN -void* __tsan_get_current_fiber(void); -void* __tsan_create_fiber(unsigned flags); -void __tsan_destroy_fiber(void* fiber); -void __tsan_switch_to_fiber(void* fiber, unsigned flags); -#endif - -#include /* For memcpy and memset. */ - -/* Utility for aligning addresses. */ -static MCO_FORCE_INLINE size_t _mco_align_forward(size_t addr, size_t align) { - return (addr + (align-1)) & ~(align-1); -} - -/* Variable holding the current running coroutine per thread. */ -static MCO_THREAD_LOCAL mco_coro* mco_current_co = NULL; - -static MCO_FORCE_INLINE void _mco_prepare_jumpin(mco_coro* co) { - /* Set the old coroutine to normal state and update it. */ - mco_coro* prev_co = mco_running(); /* Must access through `mco_running`. */ - MCO_ASSERT(co->prev_co == NULL); - co->prev_co = prev_co; - if(prev_co) { - MCO_ASSERT(prev_co->state == MCO_RUNNING); - prev_co->state = MCO_NORMAL; - } - mco_current_co = co; -#ifdef _MCO_USE_ASAN - if(prev_co) { - void* bottom_old = NULL; - size_t size_old = 0; - __sanitizer_finish_switch_fiber(prev_co->asan_prev_stack, (const void**)&bottom_old, &size_old); - prev_co->asan_prev_stack = NULL; - } - __sanitizer_start_switch_fiber(&co->asan_prev_stack, co->stack_base, co->stack_size); -#endif -#ifdef _MCO_USE_TSAN - co->tsan_prev_fiber = __tsan_get_current_fiber(); - __tsan_switch_to_fiber(co->tsan_fiber, 0); -#endif -} - -static MCO_FORCE_INLINE void _mco_prepare_jumpout(mco_coro* co) { - /* Switch back to the previous running coroutine. */ - /* MCO_ASSERT(mco_running() == co); */ - mco_coro* prev_co = co->prev_co; - co->prev_co = NULL; - if(prev_co) { - /* MCO_ASSERT(prev_co->state == MCO_NORMAL); */ - prev_co->state = MCO_RUNNING; - } - mco_current_co = prev_co; -#ifdef _MCO_USE_ASAN - void* bottom_old = NULL; - size_t size_old = 0; - __sanitizer_finish_switch_fiber(co->asan_prev_stack, (const void**)&bottom_old, &size_old); - co->asan_prev_stack = NULL; - if(prev_co) { - __sanitizer_start_switch_fiber(&prev_co->asan_prev_stack, bottom_old, size_old); - } -#endif -#ifdef _MCO_USE_TSAN - void* tsan_prev_fiber = co->tsan_prev_fiber; - co->tsan_prev_fiber = NULL; - __tsan_switch_to_fiber(tsan_prev_fiber, 0); -#endif -} - -static void _mco_jumpin(mco_coro* co); -static void _mco_jumpout(mco_coro* co); - -static MCO_NO_INLINE void _mco_main(mco_coro* co) { - co->func(co); /* Run the coroutine function. */ - co->state = MCO_DEAD; /* Coroutine finished successfully, set state to dead. */ - _mco_jumpout(co); /* Jump back to the old context .*/ -} - -/* ---------------------------------------------------------------------------------------------- */ - -#if defined(MCO_USE_UCONTEXT) || defined(MCO_USE_ASM) - -/* -Some of the following assembly code is taken from LuaCoco by Mike Pall. -See https://coco.luajit.org/index.html - -MIT license - -Copyright (C) 2004-2016 Mike Pall. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifdef MCO_USE_ASM - -#if defined(__x86_64__) || defined(_M_X64) - -#ifdef _WIN32 - -typedef struct _mco_ctxbuf { - void *rip, *rsp, *rbp, *rbx, *r12, *r13, *r14, *r15, *rdi, *rsi; - void* xmm[20]; /* xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 */ - void* fiber_storage; - void* dealloc_stack; - void* stack_limit; - void* stack_base; -} _mco_ctxbuf; - -#if defined(__GNUC__) -#define _MCO_ASM_BLOB __attribute__((section(".text"))) -#elif defined(_MSC_VER) -#define _MCO_ASM_BLOB __declspec(allocate(".text")) -#pragma section(".text") -#endif - -_MCO_ASM_BLOB static unsigned char _mco_wrap_main_code[] = { - 0x4c, 0x89, 0xe9, /* mov %r13,%rcx */ - 0x41, 0xff, 0xe4, /* jmpq *%r12 */ - 0xc3, /* retq */ - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 /* nop */ -}; - -_MCO_ASM_BLOB static unsigned char _mco_switch_code[] = { - 0x48, 0x8d, 0x05, 0x3e, 0x01, 0x00, 0x00, /* lea 0x13e(%rip),%rax */ - 0x48, 0x89, 0x01, /* mov %rax,(%rcx) */ - 0x48, 0x89, 0x61, 0x08, /* mov %rsp,0x8(%rcx) */ - 0x48, 0x89, 0x69, 0x10, /* mov %rbp,0x10(%rcx) */ - 0x48, 0x89, 0x59, 0x18, /* mov %rbx,0x18(%rcx) */ - 0x4c, 0x89, 0x61, 0x20, /* mov %r12,0x20(%rcx) */ - 0x4c, 0x89, 0x69, 0x28, /* mov %r13,0x28(%rcx) */ - 0x4c, 0x89, 0x71, 0x30, /* mov %r14,0x30(%rcx) */ - 0x4c, 0x89, 0x79, 0x38, /* mov %r15,0x38(%rcx) */ - 0x48, 0x89, 0x79, 0x40, /* mov %rdi,0x40(%rcx) */ - 0x48, 0x89, 0x71, 0x48, /* mov %rsi,0x48(%rcx) */ - 0x0f, 0x11, 0x71, 0x50, /* movups %xmm6,0x50(%rcx) */ - 0x0f, 0x11, 0x79, 0x60, /* movups %xmm7,0x60(%rcx) */ - 0x44, 0x0f, 0x11, 0x41, 0x70, /* movups %xmm8,0x70(%rcx) */ - 0x44, 0x0f, 0x11, 0x89, 0x80, 0x00, 0x00, 0x00, /* movups %xmm9,0x80(%rcx) */ - 0x44, 0x0f, 0x11, 0x91, 0x90, 0x00, 0x00, 0x00, /* movups %xmm10,0x90(%rcx) */ - 0x44, 0x0f, 0x11, 0x99, 0xa0, 0x00, 0x00, 0x00, /* movups %xmm11,0xa0(%rcx) */ - 0x44, 0x0f, 0x11, 0xa1, 0xb0, 0x00, 0x00, 0x00, /* movups %xmm12,0xb0(%rcx) */ - 0x44, 0x0f, 0x11, 0xa9, 0xc0, 0x00, 0x00, 0x00, /* movups %xmm13,0xc0(%rcx) */ - 0x44, 0x0f, 0x11, 0xb1, 0xd0, 0x00, 0x00, 0x00, /* movups %xmm14,0xd0(%rcx) */ - 0x44, 0x0f, 0x11, 0xb9, 0xe0, 0x00, 0x00, 0x00, /* movups %xmm15,0xe0(%rcx) */ - 0x65, 0x4c, 0x8b, 0x14, 0x25, 0x30, 0x00, 0x00, 0x00, /* mov %gs:0x30,%r10 */ - 0x49, 0x8b, 0x42, 0x20, /* mov 0x20(%r10),%rax */ - 0x48, 0x89, 0x81, 0xf0, 0x00, 0x00, 0x00, /* mov %rax,0xf0(%rcx) */ - 0x49, 0x8b, 0x82, 0x78, 0x14, 0x00, 0x00, /* mov 0x1478(%r10),%rax */ - 0x48, 0x89, 0x81, 0xf8, 0x00, 0x00, 0x00, /* mov %rax,0xf8(%rcx) */ - 0x49, 0x8b, 0x42, 0x10, /* mov 0x10(%r10),%rax */ - 0x48, 0x89, 0x81, 0x00, 0x01, 0x00, 0x00, /* mov %rax,0x100(%rcx) */ - 0x49, 0x8b, 0x42, 0x08, /* mov 0x8(%r10),%rax */ - 0x48, 0x89, 0x81, 0x08, 0x01, 0x00, 0x00, /* mov %rax,0x108(%rcx) */ - 0x48, 0x8b, 0x82, 0x08, 0x01, 0x00, 0x00, /* mov 0x108(%rdx),%rax */ - 0x49, 0x89, 0x42, 0x08, /* mov %rax,0x8(%r10) */ - 0x48, 0x8b, 0x82, 0x00, 0x01, 0x00, 0x00, /* mov 0x100(%rdx),%rax */ - 0x49, 0x89, 0x42, 0x10, /* mov %rax,0x10(%r10) */ - 0x48, 0x8b, 0x82, 0xf8, 0x00, 0x00, 0x00, /* mov 0xf8(%rdx),%rax */ - 0x49, 0x89, 0x82, 0x78, 0x14, 0x00, 0x00, /* mov %rax,0x1478(%r10) */ - 0x48, 0x8b, 0x82, 0xf0, 0x00, 0x00, 0x00, /* mov 0xf0(%rdx),%rax */ - 0x49, 0x89, 0x42, 0x20, /* mov %rax,0x20(%r10) */ - 0x44, 0x0f, 0x10, 0xba, 0xe0, 0x00, 0x00, 0x00, /* movups 0xe0(%rdx),%xmm15 */ - 0x44, 0x0f, 0x10, 0xb2, 0xd0, 0x00, 0x00, 0x00, /* movups 0xd0(%rdx),%xmm14 */ - 0x44, 0x0f, 0x10, 0xaa, 0xc0, 0x00, 0x00, 0x00, /* movups 0xc0(%rdx),%xmm13 */ - 0x44, 0x0f, 0x10, 0xa2, 0xb0, 0x00, 0x00, 0x00, /* movups 0xb0(%rdx),%xmm12 */ - 0x44, 0x0f, 0x10, 0x9a, 0xa0, 0x00, 0x00, 0x00, /* movups 0xa0(%rdx),%xmm11 */ - 0x44, 0x0f, 0x10, 0x92, 0x90, 0x00, 0x00, 0x00, /* movups 0x90(%rdx),%xmm10 */ - 0x44, 0x0f, 0x10, 0x8a, 0x80, 0x00, 0x00, 0x00, /* movups 0x80(%rdx),%xmm9 */ - 0x44, 0x0f, 0x10, 0x42, 0x70, /* movups 0x70(%rdx),%xmm8 */ - 0x0f, 0x10, 0x7a, 0x60, /* movups 0x60(%rdx),%xmm7 */ - 0x0f, 0x10, 0x72, 0x50, /* movups 0x50(%rdx),%xmm6 */ - 0x48, 0x8b, 0x72, 0x48, /* mov 0x48(%rdx),%rsi */ - 0x48, 0x8b, 0x7a, 0x40, /* mov 0x40(%rdx),%rdi */ - 0x4c, 0x8b, 0x7a, 0x38, /* mov 0x38(%rdx),%r15 */ - 0x4c, 0x8b, 0x72, 0x30, /* mov 0x30(%rdx),%r14 */ - 0x4c, 0x8b, 0x6a, 0x28, /* mov 0x28(%rdx),%r13 */ - 0x4c, 0x8b, 0x62, 0x20, /* mov 0x20(%rdx),%r12 */ - 0x48, 0x8b, 0x5a, 0x18, /* mov 0x18(%rdx),%rbx */ - 0x48, 0x8b, 0x6a, 0x10, /* mov 0x10(%rdx),%rbp */ - 0x48, 0x8b, 0x62, 0x08, /* mov 0x8(%rdx),%rsp */ - 0xff, 0x22, /* jmpq *(%rdx) */ - 0xc3, /* retq */ - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, /* nop */ - 0x90, 0x90, /* nop */ -}; - -void (*_mco_wrap_main)(void) = (void(*)(void))(void*)_mco_wrap_main_code; -void (*_mco_switch)(_mco_ctxbuf* from, _mco_ctxbuf* to) = (void(*)(_mco_ctxbuf* from, _mco_ctxbuf* to))(void*)_mco_switch_code; - -static mco_result _mco_makectx(mco_coro* co, _mco_ctxbuf* ctx, void* stack_base, size_t stack_size) { - stack_size = stack_size - 32; /* Reserve 32 bytes for the shadow space. */ - void** stack_high_ptr = (void**)((size_t)stack_base + stack_size - sizeof(size_t)); - stack_high_ptr[0] = (void*)(0xdeaddeaddeaddead); /* Dummy return address. */ - ctx->rip = (void*)(_mco_wrap_main); - ctx->rsp = (void*)(stack_high_ptr); - ctx->r12 = (void*)(_mco_main); - ctx->r13 = (void*)(co); - void* stack_top = (void*)((size_t)stack_base + stack_size); - ctx->stack_base = stack_top; - ctx->stack_limit = stack_base; - ctx->dealloc_stack = stack_base; - return MCO_SUCCESS; -} - -#else /* not _WIN32 */ - -typedef struct _mco_ctxbuf { - void *rip, *rsp, *rbp, *rbx, *r12, *r13, *r14, *r15; -} _mco_ctxbuf; - -void _mco_wrap_main(void); -int _mco_switch(_mco_ctxbuf* from, _mco_ctxbuf* to); - -__asm__( - ".text\n" -#ifdef __MACH__ /* Mac OS X assembler */ - ".globl __mco_wrap_main\n" - "__mco_wrap_main:\n" -#else /* Linux assembler */ - ".globl _mco_wrap_main\n" - ".type _mco_wrap_main @function\n" - ".hidden _mco_wrap_main\n" - "_mco_wrap_main:\n" -#endif - " movq %r13, %rdi\n" - " jmpq *%r12\n" -#ifndef __MACH__ - ".size _mco_wrap_main, .-_mco_wrap_main\n" -#endif -); - -__asm__( - ".text\n" -#ifdef __MACH__ /* Mac OS assembler */ - ".globl __mco_switch\n" - "__mco_switch:\n" -#else /* Linux assembler */ - ".globl _mco_switch\n" - ".type _mco_switch @function\n" - ".hidden _mco_switch\n" - "_mco_switch:\n" -#endif - " leaq 0x3d(%rip), %rax\n" - " movq %rax, (%rdi)\n" - " movq %rsp, 8(%rdi)\n" - " movq %rbp, 16(%rdi)\n" - " movq %rbx, 24(%rdi)\n" - " movq %r12, 32(%rdi)\n" - " movq %r13, 40(%rdi)\n" - " movq %r14, 48(%rdi)\n" - " movq %r15, 56(%rdi)\n" - " movq 56(%rsi), %r15\n" - " movq 48(%rsi), %r14\n" - " movq 40(%rsi), %r13\n" - " movq 32(%rsi), %r12\n" - " movq 24(%rsi), %rbx\n" - " movq 16(%rsi), %rbp\n" - " movq 8(%rsi), %rsp\n" - " jmpq *(%rsi)\n" - " ret\n" -#ifndef __MACH__ - ".size _mco_switch, .-_mco_switch\n" -#endif -); - -static mco_result _mco_makectx(mco_coro* co, _mco_ctxbuf* ctx, void* stack_base, size_t stack_size) { - stack_size = stack_size - 128; /* Reserve 128 bytes for the Red Zone space (System V AMD64 ABI). */ - void** stack_high_ptr = (void**)((size_t)stack_base + stack_size - sizeof(size_t)); - stack_high_ptr[0] = (void*)(0xdeaddeaddeaddead); /* Dummy return address. */ - ctx->rip = (void*)(_mco_wrap_main); - ctx->rsp = (void*)(stack_high_ptr); - ctx->r12 = (void*)(_mco_main); - ctx->r13 = (void*)(co); - return MCO_SUCCESS; -} - -#endif /* not _WIN32 */ - -#elif defined(__riscv) - -typedef struct _mco_ctxbuf { - void* s[12]; /* s0-s11 */ - void* ra; - void* pc; - void* sp; -#ifdef __riscv_flen -#if __riscv_flen == 64 - double fs[12]; /* fs0-fs11 */ -#elif __riscv_flen == 32 - float fs[12]; /* fs0-fs11 */ -#endif -#endif /* __riscv_flen */ -} _mco_ctxbuf; - -void _mco_wrap_main(void); -int _mco_switch(_mco_ctxbuf* from, _mco_ctxbuf* to); - -__asm__( - ".text\n" - ".globl _mco_wrap_main\n" - ".type _mco_wrap_main @function\n" - ".hidden _mco_wrap_main\n" - "_mco_wrap_main:\n" - " mv a0, s0\n" - " jr s1\n" - ".size _mco_wrap_main, .-_mco_wrap_main\n" -); - -__asm__( - ".text\n" - ".globl _mco_switch\n" - ".type _mco_switch @function\n" - ".hidden _mco_switch\n" - "_mco_switch:\n" - #if __riscv_xlen == 64 - " sd s0, 0x00(a0)\n" - " sd s1, 0x08(a0)\n" - " sd s2, 0x10(a0)\n" - " sd s3, 0x18(a0)\n" - " sd s4, 0x20(a0)\n" - " sd s5, 0x28(a0)\n" - " sd s6, 0x30(a0)\n" - " sd s7, 0x38(a0)\n" - " sd s8, 0x40(a0)\n" - " sd s9, 0x48(a0)\n" - " sd s10, 0x50(a0)\n" - " sd s11, 0x58(a0)\n" - " sd ra, 0x60(a0)\n" - " sd ra, 0x68(a0)\n" /* pc */ - " sd sp, 0x70(a0)\n" - #ifdef __riscv_flen - #if __riscv_flen == 64 - " fsd fs0, 0x78(a0)\n" - " fsd fs1, 0x80(a0)\n" - " fsd fs2, 0x88(a0)\n" - " fsd fs3, 0x90(a0)\n" - " fsd fs4, 0x98(a0)\n" - " fsd fs5, 0xa0(a0)\n" - " fsd fs6, 0xa8(a0)\n" - " fsd fs7, 0xb0(a0)\n" - " fsd fs8, 0xb8(a0)\n" - " fsd fs9, 0xc0(a0)\n" - " fsd fs10, 0xc8(a0)\n" - " fsd fs11, 0xd0(a0)\n" - " fld fs0, 0x78(a1)\n" - " fld fs1, 0x80(a1)\n" - " fld fs2, 0x88(a1)\n" - " fld fs3, 0x90(a1)\n" - " fld fs4, 0x98(a1)\n" - " fld fs5, 0xa0(a1)\n" - " fld fs6, 0xa8(a1)\n" - " fld fs7, 0xb0(a1)\n" - " fld fs8, 0xb8(a1)\n" - " fld fs9, 0xc0(a1)\n" - " fld fs10, 0xc8(a1)\n" - " fld fs11, 0xd0(a1)\n" - #else - #error "Unsupported RISC-V FLEN" - #endif - #endif /* __riscv_flen */ - " ld s0, 0x00(a1)\n" - " ld s1, 0x08(a1)\n" - " ld s2, 0x10(a1)\n" - " ld s3, 0x18(a1)\n" - " ld s4, 0x20(a1)\n" - " ld s5, 0x28(a1)\n" - " ld s6, 0x30(a1)\n" - " ld s7, 0x38(a1)\n" - " ld s8, 0x40(a1)\n" - " ld s9, 0x48(a1)\n" - " ld s10, 0x50(a1)\n" - " ld s11, 0x58(a1)\n" - " ld ra, 0x60(a1)\n" - " ld a2, 0x68(a1)\n" /* pc */ - " ld sp, 0x70(a1)\n" - " jr a2\n" - #elif __riscv_xlen == 32 - " sw s0, 0x00(a0)\n" - " sw s1, 0x04(a0)\n" - " sw s2, 0x08(a0)\n" - " sw s3, 0x0c(a0)\n" - " sw s4, 0x10(a0)\n" - " sw s5, 0x14(a0)\n" - " sw s6, 0x18(a0)\n" - " sw s7, 0x1c(a0)\n" - " sw s8, 0x20(a0)\n" - " sw s9, 0x24(a0)\n" - " sw s10, 0x28(a0)\n" - " sw s11, 0x2c(a0)\n" - " sw ra, 0x30(a0)\n" - " sw ra, 0x34(a0)\n" /* pc */ - " sw sp, 0x38(a0)\n" - #ifdef __riscv_flen - #if __riscv_flen == 64 - " fsd fs0, 0x3c(a0)\n" - " fsd fs1, 0x44(a0)\n" - " fsd fs2, 0x4c(a0)\n" - " fsd fs3, 0x54(a0)\n" - " fsd fs4, 0x5c(a0)\n" - " fsd fs5, 0x64(a0)\n" - " fsd fs6, 0x6c(a0)\n" - " fsd fs7, 0x74(a0)\n" - " fsd fs8, 0x7c(a0)\n" - " fsd fs9, 0x84(a0)\n" - " fsd fs10, 0x8c(a0)\n" - " fsd fs11, 0x94(a0)\n" - " fld fs0, 0x3c(a1)\n" - " fld fs1, 0x44(a1)\n" - " fld fs2, 0x4c(a1)\n" - " fld fs3, 0x54(a1)\n" - " fld fs4, 0x5c(a1)\n" - " fld fs5, 0x64(a1)\n" - " fld fs6, 0x6c(a1)\n" - " fld fs7, 0x74(a1)\n" - " fld fs8, 0x7c(a1)\n" - " fld fs9, 0x84(a1)\n" - " fld fs10, 0x8c(a1)\n" - " fld fs11, 0x94(a1)\n" - #elif __riscv_flen == 32 - " fsw fs0, 0x3c(a0)\n" - " fsw fs1, 0x40(a0)\n" - " fsw fs2, 0x44(a0)\n" - " fsw fs3, 0x48(a0)\n" - " fsw fs4, 0x4c(a0)\n" - " fsw fs5, 0x50(a0)\n" - " fsw fs6, 0x54(a0)\n" - " fsw fs7, 0x58(a0)\n" - " fsw fs8, 0x5c(a0)\n" - " fsw fs9, 0x60(a0)\n" - " fsw fs10, 0x64(a0)\n" - " fsw fs11, 0x68(a0)\n" - " flw fs0, 0x3c(a1)\n" - " flw fs1, 0x40(a1)\n" - " flw fs2, 0x44(a1)\n" - " flw fs3, 0x48(a1)\n" - " flw fs4, 0x4c(a1)\n" - " flw fs5, 0x50(a1)\n" - " flw fs6, 0x54(a1)\n" - " flw fs7, 0x58(a1)\n" - " flw fs8, 0x5c(a1)\n" - " flw fs9, 0x60(a1)\n" - " flw fs10, 0x64(a1)\n" - " flw fs11, 0x68(a1)\n" - #else - #error "Unsupported RISC-V FLEN" - #endif - #endif /* __riscv_flen */ - " lw s0, 0x00(a1)\n" - " lw s1, 0x04(a1)\n" - " lw s2, 0x08(a1)\n" - " lw s3, 0x0c(a1)\n" - " lw s4, 0x10(a1)\n" - " lw s5, 0x14(a1)\n" - " lw s6, 0x18(a1)\n" - " lw s7, 0x1c(a1)\n" - " lw s8, 0x20(a1)\n" - " lw s9, 0x24(a1)\n" - " lw s10, 0x28(a1)\n" - " lw s11, 0x2c(a1)\n" - " lw ra, 0x30(a1)\n" - " lw a2, 0x34(a1)\n" /* pc */ - " lw sp, 0x38(a1)\n" - " jr a2\n" - #else - #error "Unsupported RISC-V XLEN" - #endif /* __riscv_xlen */ - ".size _mco_switch, .-_mco_switch\n" -); - -static mco_result _mco_makectx(mco_coro* co, _mco_ctxbuf* ctx, void* stack_base, size_t stack_size) { - ctx->s[0] = (void*)(co); - ctx->s[1] = (void*)(_mco_main); - ctx->pc = (void*)(_mco_wrap_main); -#if __riscv_xlen == 64 - ctx->ra = (void*)(0xdeaddeaddeaddead); -#elif __riscv_xlen == 32 - ctx->ra = (void*)(0xdeaddead); -#endif - ctx->sp = (void*)((size_t)stack_base + stack_size); - return MCO_SUCCESS; -} - -#elif defined(__i386) || defined(__i386__) - -typedef struct _mco_ctxbuf { - void *eip, *esp, *ebp, *ebx, *esi, *edi; -} _mco_ctxbuf; - -void _mco_switch(_mco_ctxbuf* from, _mco_ctxbuf* to); - -__asm__( -#ifdef __DJGPP__ /* DOS compiler */ - "__mco_switch:\n" -#else - ".text\n" - ".globl _mco_switch\n" - ".type _mco_switch @function\n" - ".hidden _mco_switch\n" - "_mco_switch:\n" -#endif - " call 1f\n" - " 1:\n" - " popl %ecx\n" - " addl $(2f-1b), %ecx\n" - " movl 4(%esp), %eax\n" - " movl 8(%esp), %edx\n" - " movl %ecx, (%eax)\n" - " movl %esp, 4(%eax)\n" - " movl %ebp, 8(%eax)\n" - " movl %ebx, 12(%eax)\n" - " movl %esi, 16(%eax)\n" - " movl %edi, 20(%eax)\n" - " movl 20(%edx), %edi\n" - " movl 16(%edx), %esi\n" - " movl 12(%edx), %ebx\n" - " movl 8(%edx), %ebp\n" - " movl 4(%edx), %esp\n" - " jmp *(%edx)\n" - " 2:\n" - " ret\n" -#ifndef __DJGPP__ - ".size _mco_switch, .-_mco_switch\n" -#endif -); - -static mco_result _mco_makectx(mco_coro* co, _mco_ctxbuf* ctx, void* stack_base, size_t stack_size) { - void** stack_high_ptr = (void**)((size_t)stack_base + stack_size - 16 - 1*sizeof(size_t)); - stack_high_ptr[0] = (void*)(0xdeaddead); /* Dummy return address. */ - stack_high_ptr[1] = (void*)(co); - ctx->eip = (void*)(_mco_main); - ctx->esp = (void*)(stack_high_ptr); - return MCO_SUCCESS; -} - -#elif defined(__ARM_EABI__) - -typedef struct _mco_ctxbuf { -#ifndef __SOFTFP__ - void* f[16]; -#endif - void *d[4]; /* d8-d15 */ - void *r[4]; /* r4-r11 */ - void *lr; - void *sp; -} _mco_ctxbuf; - -void _mco_wrap_main(void); -int _mco_switch(_mco_ctxbuf* from, _mco_ctxbuf* to); - -__asm__( - ".text\n" -#ifdef __APPLE__ - ".globl __mco_switch\n" - "__mco_switch:\n" -#else - ".globl _mco_switch\n" - ".type _mco_switch #function\n" - ".hidden _mco_switch\n" - "_mco_switch:\n" -#endif -#ifndef __SOFTFP__ - " vstmia r0!, {d8-d15}\n" -#endif - " stmia r0, {r4-r11, lr}\n" - " str sp, [r0, #9*4]\n" -#ifndef __SOFTFP__ - " vldmia r1!, {d8-d15}\n" -#endif - " ldr sp, [r1, #9*4]\n" - " ldmia r1, {r4-r11, pc}\n" -#ifndef __APPLE__ - ".size _mco_switch, .-_mco_switch\n" -#endif -); - -__asm__( - ".text\n" -#ifdef __APPLE__ - ".globl __mco_wrap_main\n" - "__mco_wrap_main:\n" -#else - ".globl _mco_wrap_main\n" - ".type _mco_wrap_main #function\n" - ".hidden _mco_wrap_main\n" - "_mco_wrap_main:\n" -#endif - " mov r0, r4\n" - " mov ip, r5\n" - " mov lr, r6\n" - " bx ip\n" -#ifndef __APPLE__ - ".size _mco_wrap_main, .-_mco_wrap_main\n" -#endif -); - -static mco_result _mco_makectx(mco_coro* co, _mco_ctxbuf* ctx, void* stack_base, size_t stack_size) { - ctx->d[0] = (void*)(co); - ctx->d[1] = (void*)(_mco_main); - ctx->d[2] = (void*)(0xdeaddead); /* Dummy return address. */ - ctx->lr = (void*)(_mco_wrap_main); - ctx->sp = (void*)((size_t)stack_base + stack_size); - return MCO_SUCCESS; -} - -#elif defined(__aarch64__) - -typedef struct _mco_ctxbuf { - void *x[12]; /* x19-x30 */ - void *sp; - void *lr; - void *d[8]; /* d8-d15 */ -} _mco_ctxbuf; - -void _mco_wrap_main(void); -int _mco_switch(_mco_ctxbuf* from, _mco_ctxbuf* to); - -__asm__( - ".text\n" -#ifdef __APPLE__ - ".globl __mco_switch\n" - "__mco_switch:\n" -#else - ".globl _mco_switch\n" - ".type _mco_switch #function\n" - ".hidden _mco_switch\n" - "_mco_switch:\n" -#endif - - " mov x10, sp\n" - " mov x11, x30\n" - " stp x19, x20, [x0, #(0*16)]\n" - " stp x21, x22, [x0, #(1*16)]\n" - " stp d8, d9, [x0, #(7*16)]\n" - " stp x23, x24, [x0, #(2*16)]\n" - " stp d10, d11, [x0, #(8*16)]\n" - " stp x25, x26, [x0, #(3*16)]\n" - " stp d12, d13, [x0, #(9*16)]\n" - " stp x27, x28, [x0, #(4*16)]\n" - " stp d14, d15, [x0, #(10*16)]\n" - " stp x29, x30, [x0, #(5*16)]\n" - " stp x10, x11, [x0, #(6*16)]\n" - " ldp x19, x20, [x1, #(0*16)]\n" - " ldp x21, x22, [x1, #(1*16)]\n" - " ldp d8, d9, [x1, #(7*16)]\n" - " ldp x23, x24, [x1, #(2*16)]\n" - " ldp d10, d11, [x1, #(8*16)]\n" - " ldp x25, x26, [x1, #(3*16)]\n" - " ldp d12, d13, [x1, #(9*16)]\n" - " ldp x27, x28, [x1, #(4*16)]\n" - " ldp d14, d15, [x1, #(10*16)]\n" - " ldp x29, x30, [x1, #(5*16)]\n" - " ldp x10, x11, [x1, #(6*16)]\n" - " mov sp, x10\n" - " br x11\n" -#ifndef __APPLE__ - ".size _mco_switch, .-_mco_switch\n" -#endif -); - -__asm__( - ".text\n" -#ifdef __APPLE__ - ".globl __mco_wrap_main\n" - "__mco_wrap_main:\n" -#else - ".globl _mco_wrap_main\n" - ".type _mco_wrap_main #function\n" - ".hidden _mco_wrap_main\n" - "_mco_wrap_main:\n" -#endif - " mov x0, x19\n" - " mov x30, x21\n" - " br x20\n" -#ifndef __APPLE__ - ".size _mco_wrap_main, .-_mco_wrap_main\n" -#endif -); - -static mco_result _mco_makectx(mco_coro* co, _mco_ctxbuf* ctx, void* stack_base, size_t stack_size) { - ctx->x[0] = (void*)(co); - ctx->x[1] = (void*)(_mco_main); - ctx->x[2] = (void*)(0xdeaddeaddeaddead); /* Dummy return address. */ - ctx->sp = (void*)((size_t)stack_base + stack_size); - ctx->lr = (void*)(_mco_wrap_main); - return MCO_SUCCESS; -} - -#else - -#error "Unsupported architecture for assembly method." - -#endif /* ARCH */ - -#elif defined(MCO_USE_UCONTEXT) - -#include - -typedef ucontext_t _mco_ctxbuf; - -#if defined(_LP64) || defined(__LP64__) -static void _mco_wrap_main(unsigned int lo, unsigned int hi) { - mco_coro* co = (mco_coro*)(((size_t)lo) | (((size_t)hi) << 32)); /* Extract coroutine pointer. */ - _mco_main(co); -} -#else -static void _mco_wrap_main(unsigned int lo) { - mco_coro* co = (mco_coro*)((size_t)lo); /* Extract coroutine pointer. */ - _mco_main(co); -} -#endif - -static MCO_FORCE_INLINE void _mco_switch(_mco_ctxbuf* from, _mco_ctxbuf* to) { - int res = swapcontext(from, to); - _MCO_UNUSED(res); - MCO_ASSERT(res == 0); -} - -static mco_result _mco_makectx(mco_coro* co, _mco_ctxbuf* ctx, void* stack_base, size_t stack_size) { - /* Initialize ucontext. */ - if(getcontext(ctx) != 0) { - MCO_LOG("failed to get ucontext"); - return MCO_MAKE_CONTEXT_ERROR; - } - ctx->uc_link = NULL; /* We never exit from _mco_wrap_main. */ - ctx->uc_stack.ss_sp = stack_base; - ctx->uc_stack.ss_size = stack_size; - unsigned int lo = (unsigned int)((size_t)co); -#if defined(_LP64) || defined(__LP64__) - unsigned int hi = (unsigned int)(((size_t)co)>>32); - makecontext(ctx, (void (*)(void))_mco_wrap_main, 2, lo, hi); -#else - makecontext(ctx, (void (*)(void))_mco_wrap_main, 1, lo); -#endif - return MCO_SUCCESS; -} - -#endif /* defined(MCO_USE_UCONTEXT) */ - -#ifdef MCO_USE_VALGRIND -#include -#endif - -typedef struct _mco_context { -#ifdef MCO_USE_VALGRIND - unsigned int valgrind_stack_id; -#endif - _mco_ctxbuf ctx; - _mco_ctxbuf back_ctx; -} _mco_context; - -static void _mco_jumpin(mco_coro* co) { - _mco_context* context = (_mco_context*)co->context; - _mco_prepare_jumpin(co); - _mco_switch(&context->back_ctx, &context->ctx); /* Do the context switch. */ -} - -static void _mco_jumpout(mco_coro* co) { - _mco_context* context = (_mco_context*)co->context; - _mco_prepare_jumpout(co); - _mco_switch(&context->ctx, &context->back_ctx); /* Do the context switch. */ -} - -static mco_result _mco_create_context(mco_coro* co, mco_desc* desc) { - /* Determine the context and stack address. */ - size_t co_addr = (size_t)co; - size_t context_addr = _mco_align_forward(co_addr + sizeof(mco_coro), 16); - size_t storage_addr = _mco_align_forward(context_addr + sizeof(_mco_context), 16); - size_t stack_addr = _mco_align_forward(storage_addr + desc->storage_size, 16); - /* Initialize context. */ - _mco_context* context = (_mco_context*)context_addr; - memset(context, 0, sizeof(_mco_context)); - /* Initialize storage. */ - unsigned char* storage = (unsigned char*)storage_addr; - memset(storage, 0, desc->storage_size); - /* Initialize stack. */ - void *stack_base = (void*)stack_addr; - size_t stack_size = desc->stack_size; -#ifdef MCO_ZERO_MEMORY - memset(stack_base, 0, stack_size); -#endif - /* Make the context. */ - mco_result res = _mco_makectx(co, &context->ctx, stack_base, stack_size); - if(res != MCO_SUCCESS) { - return res; - } -#ifdef MCO_USE_VALGRIND - context->valgrind_stack_id = VALGRIND_STACK_REGISTER(stack_addr, stack_addr + stack_size); -#endif - co->context = context; - co->stack_base = stack_base; - co->stack_size = stack_size; - co->storage = storage; - co->storage_size = desc->storage_size; - return MCO_SUCCESS; -} - -static void _mco_destroy_context(mco_coro* co) { -#ifdef MCO_USE_VALGRIND - _mco_context* context = (_mco_context*)co->context; - if(context && context->valgrind_stack_id != 0) { - VALGRIND_STACK_DEREGISTER(context->valgrind_stack_id); - context->valgrind_stack_id = 0; - } -#else - _MCO_UNUSED(co); -#endif -} - -static MCO_FORCE_INLINE void _mco_init_desc_sizes(mco_desc* desc, size_t stack_size) { - desc->coro_size = _mco_align_forward(sizeof(mco_coro), 16) + - _mco_align_forward(sizeof(_mco_context), 16) + - _mco_align_forward(desc->storage_size, 16) + - stack_size + 16; - desc->stack_size = stack_size; /* This is just a hint, it won't be the real one. */ -} - -#endif /* defined(MCO_USE_UCONTEXT) || defined(MCO_USE_ASM) */ - -/* ---------------------------------------------------------------------------------------------- */ - -#ifdef MCO_USE_FIBERS - -#ifdef _WIN32 - -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0400 -#endif -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include - -typedef struct _mco_context { - void* fib; - void* back_fib; -} _mco_context; - -static void _mco_jumpin(mco_coro* co) { - void *cur_fib = GetCurrentFiber(); - if(!cur_fib || cur_fib == (void*)0x1e00) { /* See http://blogs.msdn.com/oldnewthing/archive/2004/12/31/344799.aspx */ - cur_fib = ConvertThreadToFiber(NULL); - } - MCO_ASSERT(cur_fib != NULL); - _mco_context* context = (_mco_context*)co->context; - context->back_fib = cur_fib; - _mco_prepare_jumpin(co); - SwitchToFiber(context->fib); -} - -static void CALLBACK _mco_wrap_main(void* co) { - _mco_main((mco_coro*)co); -} - -static void _mco_jumpout(mco_coro* co) { - _mco_context* context = (_mco_context*)co->context; - void* back_fib = context->back_fib; - MCO_ASSERT(back_fib != NULL); - context->back_fib = NULL; - _mco_prepare_jumpout(co); - SwitchToFiber(back_fib); -} - -/* Reverse engineered Fiber struct, used to get stack base. */ -typedef struct _mco_fiber { - LPVOID param; /* fiber param */ - void* except; /* saved exception handlers list */ - void* stack_base; /* top of fiber stack */ - void* stack_limit; /* fiber stack low-water mark */ - void* stack_allocation; /* base of the fiber stack allocation */ - CONTEXT context; /* fiber context */ - DWORD flags; /* fiber flags */ - LPFIBER_START_ROUTINE start; /* start routine */ - void **fls_slots; /* fiber storage slots */ -} _mco_fiber; - -static mco_result _mco_create_context(mco_coro* co, mco_desc* desc) { - /* Determine the context address. */ - size_t co_addr = (size_t)co; - size_t context_addr = _mco_align_forward(co_addr + sizeof(mco_coro), 16); - size_t storage_addr = _mco_align_forward(context_addr + sizeof(_mco_context), 16); - /* Initialize context. */ - _mco_context* context = (_mco_context*)context_addr; - memset(context, 0, sizeof(_mco_context)); - /* Initialize storage. */ - unsigned char* storage = (unsigned char*)storage_addr; - memset(storage, 0, desc->storage_size); - /* Create the fiber. */ - _mco_fiber* fib = (_mco_fiber*)CreateFiberEx(desc->stack_size, desc->stack_size, FIBER_FLAG_FLOAT_SWITCH, _mco_wrap_main, co); - if(!fib) { - MCO_LOG("failed to create fiber"); - return MCO_MAKE_CONTEXT_ERROR; - } - context->fib = fib; - co->context = context; - co->stack_base = (void*)((size_t)fib->stack_base - desc->stack_size); - co->stack_size = desc->stack_size; - co->storage = storage; - co->storage_size = desc->storage_size; - return MCO_SUCCESS; -} - -static void _mco_destroy_context(mco_coro* co) { - _mco_context* context = (_mco_context*)co->context; - if(context && context->fib) { - DeleteFiber(context->fib); - context->fib = NULL; - } -} - -static MCO_FORCE_INLINE void _mco_init_desc_sizes(mco_desc* desc, size_t stack_size) { - desc->coro_size = _mco_align_forward(sizeof(mco_coro), 16) + - _mco_align_forward(sizeof(_mco_context), 16) + - _mco_align_forward(desc->storage_size, 16) + - 16; - desc->stack_size = stack_size; -} - -#elif defined(__EMSCRIPTEN__) - -#include - -#ifndef MCO_ASYNCFY_STACK_SIZE -#define MCO_ASYNCFY_STACK_SIZE 16384 -#endif - -typedef struct _mco_context { - emscripten_fiber_t fib; - emscripten_fiber_t* back_fib; -} _mco_context; - -static emscripten_fiber_t* running_fib = NULL; -static unsigned char main_asyncify_stack[MCO_ASYNCFY_STACK_SIZE]; -static emscripten_fiber_t main_fib; - -static void _mco_wrap_main(void* co) { - _mco_main((mco_coro*)co); -} - -static void _mco_jumpin(mco_coro* co) { - _mco_context* context = (_mco_context*)co->context; - emscripten_fiber_t* back_fib = running_fib; - if(!back_fib) { - back_fib = &main_fib; - emscripten_fiber_init_from_current_context(back_fib, main_asyncify_stack, MCO_ASYNCFY_STACK_SIZE); - } - running_fib = &context->fib; - context->back_fib = back_fib; - _mco_prepare_jumpin(co); - emscripten_fiber_swap(back_fib, &context->fib); /* Do the context switch. */ -} - -static void _mco_jumpout(mco_coro* co) { - _mco_context* context = (_mco_context*)co->context; - running_fib = context->back_fib; - _mco_prepare_jumpout(co); - emscripten_fiber_swap(&context->fib, context->back_fib); /* Do the context switch. */ -} - -static mco_result _mco_create_context(mco_coro* co, mco_desc* desc) { - if(emscripten_has_asyncify() != 1) { - MCO_LOG("failed to create fiber because ASYNCIFY is not enabled"); - return MCO_MAKE_CONTEXT_ERROR; - } - /* Determine the context address. */ - size_t co_addr = (size_t)co; - size_t context_addr = _mco_align_forward(co_addr + sizeof(mco_coro), 16); - size_t storage_addr = _mco_align_forward(context_addr + sizeof(_mco_context), 16); - size_t stack_addr = _mco_align_forward(storage_addr + desc->storage_size, 16); - size_t asyncify_stack_addr = _mco_align_forward(stack_addr + desc->stack_size, 16); - /* Initialize context. */ - _mco_context* context = (_mco_context*)context_addr; - memset(context, 0, sizeof(_mco_context)); - /* Initialize storage. */ - unsigned char* storage = (unsigned char*)storage_addr; - memset(storage, 0, desc->storage_size); - /* Initialize stack. */ - void *stack_base = (void*)stack_addr; - size_t stack_size = asyncify_stack_addr - stack_addr; - void *asyncify_stack_base = (void*)asyncify_stack_addr; - size_t asyncify_stack_size = co_addr + desc->coro_size - asyncify_stack_addr; -#ifdef MCO_ZERO_MEMORY - memset(stack_base, 0, stack_size); - memset(asyncify_stack_base, 0, asyncify_stack_size); -#endif - /* Create the fiber. */ - emscripten_fiber_init(&context->fib, _mco_wrap_main, co, stack_base, stack_size, asyncify_stack_base, asyncify_stack_size); - co->context = context; - co->stack_base = stack_base; - co->stack_size = stack_size; - co->storage = storage; - co->storage_size = desc->storage_size; - return MCO_SUCCESS; -} - -static void _mco_destroy_context(mco_coro* co) { - /* Nothing to do. */ - _MCO_UNUSED(co); -} - -static MCO_FORCE_INLINE void _mco_init_desc_sizes(mco_desc* desc, size_t stack_size) { - desc->coro_size = _mco_align_forward(sizeof(mco_coro), 16) + - _mco_align_forward(sizeof(_mco_context), 16) + - _mco_align_forward(desc->storage_size, 16) + - _mco_align_forward(stack_size, 16) + - _mco_align_forward(MCO_ASYNCFY_STACK_SIZE, 16) + - 16; - desc->stack_size = stack_size; /* This is just a hint, it won't be the real one. */ -} - -#else - -#error "Unsupported architecture for fibers method." - -#endif - -#endif /* MCO_USE_FIBERS */ - -/* ---------------------------------------------------------------------------------------------- */ - -#ifdef MCO_USE_ASYNCIFY - -typedef struct _asyncify_stack_region { - void* start; - void* limit; -} _asyncify_stack_region; - -typedef struct _mco_context { - int rewind_id; - _asyncify_stack_region stack_region; -} _mco_context; - -__attribute__((import_module("asyncify"), import_name("start_unwind"))) void _asyncify_start_unwind(void*); -__attribute__((import_module("asyncify"), import_name("stop_unwind"))) void _asyncify_stop_unwind(); -__attribute__((import_module("asyncify"), import_name("start_rewind"))) void _asyncify_start_rewind(void*); -__attribute__((import_module("asyncify"), import_name("stop_rewind"))) void _asyncify_stop_rewind(); - -MCO_NO_INLINE void _mco_jumpin(mco_coro* co) { - _mco_context* context = (_mco_context*)co->context; - _mco_prepare_jumpin(co); - if(context->rewind_id > 0) { /* Begin rewinding until last yield point. */ - _asyncify_start_rewind(&context->stack_region); - } - _mco_main(co); /* Run the coroutine function. */ - _asyncify_stop_unwind(); /* Stop saving coroutine stack. */ -} - -static MCO_NO_INLINE void _mco_finish_jumpout(mco_coro* co, volatile int rewind_id) { - _mco_context* context = (_mco_context*)co->context; - int next_rewind_id = context->rewind_id + 1; - if(rewind_id == next_rewind_id) { /* Begins unwinding the stack (save locals and call stack to rewind later) */ - _mco_prepare_jumpout(co); - context->rewind_id = next_rewind_id; - _asyncify_start_unwind(&context->stack_region); - } else if(rewind_id == context->rewind_id) { /* Continue from yield point. */ - _asyncify_stop_rewind(); - } - /* Otherwise, we should be rewinding, let it continue... */ -} - -MCO_NO_INLINE void _mco_jumpout(mco_coro* co) { - _mco_context* context = (_mco_context*)co->context; - /* - Save rewind point into a local, that should be restored when rewinding. - That is "rewind_id != co->rewind_id + 1" may be true when rewinding. - Use volatile here just to be safe from compiler optimizing this out. - */ - volatile int rewind_id = context->rewind_id + 1; - _mco_finish_jumpout(co, rewind_id); -} - -static mco_result _mco_create_context(mco_coro* co, mco_desc* desc) { - /* Determine the context address. */ - size_t co_addr = (size_t)co; - size_t context_addr = _mco_align_forward(co_addr + sizeof(mco_coro), 16); - size_t storage_addr = _mco_align_forward(context_addr + sizeof(_mco_context), 16); - size_t stack_addr = _mco_align_forward(storage_addr + desc->storage_size, 16); - /* Initialize context. */ - _mco_context* context = (_mco_context*)context_addr; - memset(context, 0, sizeof(_mco_context)); - /* Initialize storage. */ - unsigned char* storage = (unsigned char*)storage_addr; - memset(storage, 0, desc->storage_size); - /* Initialize stack. */ - void *stack_base = (void*)stack_addr; - size_t stack_size = desc->stack_size; -#ifdef MCO_ZERO_MEMORY - memset(stack_base, 0, stack_size); -#endif - context->stack_region.start = stack_base; - context->stack_region.limit = (void*)((size_t)stack_base + stack_size); - co->context = context; - co->stack_base = stack_base; - co->stack_size = stack_size; - co->storage = storage; - co->storage_size = desc->storage_size; - return MCO_SUCCESS; -} - -static void _mco_destroy_context(mco_coro* co) { - /* Nothing to do. */ - _MCO_UNUSED(co); -} - -static MCO_FORCE_INLINE void _mco_init_desc_sizes(mco_desc* desc, size_t stack_size) { - desc->coro_size = _mco_align_forward(sizeof(mco_coro), 16) + - _mco_align_forward(sizeof(_mco_context), 16) + - _mco_align_forward(desc->storage_size, 16) + - _mco_align_forward(stack_size, 16) + - 16; - desc->stack_size = stack_size; /* This is just a hint, it won't be the real one. */ -} - -#endif /* MCO_USE_ASYNCIFY */ - -/* ---------------------------------------------------------------------------------------------- */ - -mco_desc mco_desc_init(void (*func)(mco_coro* co), size_t stack_size) { - if(stack_size != 0) { - /* Stack size should be at least `MCO_MIN_STACK_SIZE`. */ - if(stack_size < MCO_MIN_STACK_SIZE) { - stack_size = MCO_MIN_STACK_SIZE; - } - } else { - stack_size = MCO_DEFAULT_STACK_SIZE; - } - stack_size = _mco_align_forward(stack_size, 16); /* Stack size should be aligned to 16 bytes. */ - mco_desc desc; - memset(&desc, 0, sizeof(mco_desc)); -#ifndef MCO_NO_DEFAULT_ALLOCATORS - /* Set default allocators. */ - desc.malloc_cb = mco_malloc; - desc.free_cb = mco_free; -#endif - desc.func = func; - desc.storage_size = MCO_DEFAULT_STORAGE_SIZE; - _mco_init_desc_sizes(&desc, stack_size); - return desc; -} - -static mco_result _mco_validate_desc(mco_desc* desc) { - if(!desc) { - MCO_LOG("coroutine description is NULL"); - return MCO_INVALID_ARGUMENTS; - } - if(!desc->func) { - MCO_LOG("coroutine function in invalid"); - return MCO_INVALID_ARGUMENTS; - } - if(desc->stack_size < MCO_MIN_STACK_SIZE) { - MCO_LOG("coroutine stack size is too small"); - return MCO_INVALID_ARGUMENTS; - } - if(desc->coro_size < sizeof(mco_coro)) { - MCO_LOG("coroutine size is invalid"); - return MCO_INVALID_ARGUMENTS; - } - return MCO_SUCCESS; -} - -mco_result mco_init(mco_coro* co, mco_desc* desc) { - if(!co) { - MCO_LOG("attempt to initialize an invalid coroutine"); - return MCO_INVALID_COROUTINE; - } - memset(co, 0, sizeof(mco_coro)); - /* Validate coroutine description. */ - mco_result res = _mco_validate_desc(desc); - if(res != MCO_SUCCESS) - return res; - /* Create the coroutine. */ - res = _mco_create_context(co, desc); - if(res != MCO_SUCCESS) - return res; - co->state = MCO_SUSPENDED; /* We initialize in suspended state. */ - co->free_cb = desc->free_cb; - co->allocator_data = desc->allocator_data; - co->func = desc->func; - co->user_data = desc->user_data; -#ifdef _MCO_USE_TSAN - co->tsan_fiber = __tsan_create_fiber(0); -#endif - co->magic_number = MCO_MAGIC_NUMBER; - return MCO_SUCCESS; -} - -mco_result mco_uninit(mco_coro* co) { - if(!co) { - MCO_LOG("attempt to uninitialize an invalid coroutine"); - return MCO_INVALID_COROUTINE; - } - /* Cannot uninitialize while running. */ - if(!(co->state == MCO_SUSPENDED || co->state == MCO_DEAD)) { - MCO_LOG("attempt to uninitialize a coroutine that is not dead or suspended"); - return MCO_INVALID_OPERATION; - } - /* The coroutine is now dead and cannot be used anymore. */ - co->state = MCO_DEAD; -#ifdef _MCO_USE_TSAN - if(co->tsan_fiber != NULL) { - __tsan_destroy_fiber(co->tsan_fiber); - co->tsan_fiber = NULL; - } -#endif - _mco_destroy_context(co); - return MCO_SUCCESS; -} - -mco_result mco_create(mco_coro** out_co, mco_desc* desc) { - /* Validate input. */ - if(!out_co) { - MCO_LOG("coroutine output pointer is NULL"); - return MCO_INVALID_POINTER; - } - if(!desc || !desc->malloc_cb || !desc->free_cb) { - *out_co = NULL; - MCO_LOG("coroutine allocator description is not set"); - return MCO_INVALID_ARGUMENTS; - } - /* Allocate the coroutine. */ - mco_coro* co = (mco_coro*)desc->malloc_cb(desc->coro_size, desc->allocator_data); - if(!co) { - MCO_LOG("coroutine allocation failed"); - *out_co = NULL; - return MCO_OUT_OF_MEMORY; - } - /* Initialize the coroutine. */ - mco_result res = mco_init(co, desc); - if(res != MCO_SUCCESS) { - desc->free_cb(co, desc->allocator_data); - *out_co = NULL; - return res; - } - *out_co = co; - return MCO_SUCCESS; -} - -mco_result mco_destroy(mco_coro* co) { - if(!co) { - MCO_LOG("attempt to destroy an invalid coroutine"); - return MCO_INVALID_COROUTINE; - } - /* Uninitialize the coroutine first. */ - mco_result res = mco_uninit(co); - if(res != MCO_SUCCESS) - return res; - /* Free the coroutine. */ - if(!co->free_cb) { - MCO_LOG("attempt destroy a coroutine that has no free callback"); - return MCO_INVALID_POINTER; - } - co->free_cb(co, co->allocator_data); - return MCO_SUCCESS; -} - -mco_result mco_resume(mco_coro* co) { - if(!co) { - MCO_LOG("attempt to resume an invalid coroutine"); - return MCO_INVALID_COROUTINE; - } - if(co->state != MCO_SUSPENDED) { /* Can only resume coroutines that are suspended. */ - MCO_LOG("attempt to resume a coroutine that is not suspended"); - return MCO_NOT_SUSPENDED; - } - co->state = MCO_RUNNING; /* The coroutine is now running. */ - _mco_jumpin(co); - return MCO_SUCCESS; -} - -mco_result mco_yield(mco_coro* co) { - if(!co) { - MCO_LOG("attempt to yield an invalid coroutine"); - return MCO_INVALID_COROUTINE; - } -#ifdef MCO_USE_ASYNCIFY - /* Asyncify already checks for stack overflow. */ -#else - /* This check happens when the stack overflow already happened, but better later than never. */ - volatile size_t dummy; - size_t stack_addr = (size_t)&dummy; - size_t stack_min = (size_t)co->stack_base; - size_t stack_max = stack_min + co->stack_size; - if(co->magic_number != MCO_MAGIC_NUMBER || stack_addr < stack_min || stack_addr > stack_max) { /* Stack overflow. */ - MCO_LOG("coroutine stack overflow, try increasing the stack size"); - return MCO_STACK_OVERFLOW; - } -#endif - if(co->state != MCO_RUNNING) { /* Can only yield coroutines that are running. */ - MCO_LOG("attempt to yield a coroutine that is not running"); - return MCO_NOT_RUNNING; - } - co->state = MCO_SUSPENDED; /* The coroutine is now suspended. */ - _mco_jumpout(co); - return MCO_SUCCESS; -} - -mco_state mco_status(mco_coro* co) { - if(co != NULL) { - return co->state; - } - return MCO_DEAD; -} - -void* mco_get_user_data(mco_coro* co) { - if(co != NULL) { - return co->user_data; - } - return NULL; -} - -mco_result mco_push(mco_coro* co, const void* src, size_t len) { - if(!co) { - MCO_LOG("attempt to use an invalid coroutine"); - return MCO_INVALID_COROUTINE; - } else if(len > 0) { - size_t bytes_stored = co->bytes_stored + len; - if(bytes_stored > co->storage_size) { - MCO_LOG("attempt to push too many bytes into coroutine storage"); - return MCO_NOT_ENOUGH_SPACE; - } - if(!src) { - MCO_LOG("attempt push a null pointer into coroutine storage"); - return MCO_INVALID_POINTER; - } - memcpy(&co->storage[co->bytes_stored], src, len); - co->bytes_stored = bytes_stored; - } - return MCO_SUCCESS; -} - -mco_result mco_pop(mco_coro* co, void* dest, size_t len) { - if(!co) { - MCO_LOG("attempt to use an invalid coroutine"); - return MCO_INVALID_COROUTINE; - } else if(len > 0) { - if(len > co->bytes_stored) { - MCO_LOG("attempt to pop too many bytes from coroutine storage"); - return MCO_NOT_ENOUGH_SPACE; - } - size_t bytes_stored = co->bytes_stored - len; - if(dest) { - memcpy(dest, &co->storage[bytes_stored], len); - } - co->bytes_stored = bytes_stored; -#ifdef MCO_ZERO_MEMORY - /* Clear garbage in the discarded storage. */ - memset(&co->storage[bytes_stored], 0, len); -#endif - } - return MCO_SUCCESS; -} - -mco_result mco_peek(mco_coro* co, void* dest, size_t len) { - if(!co) { - MCO_LOG("attempt to use an invalid coroutine"); - return MCO_INVALID_COROUTINE; - } else if(len > 0) { - if(len > co->bytes_stored) { - MCO_LOG("attempt to peek too many bytes from coroutine storage"); - return MCO_NOT_ENOUGH_SPACE; - } - if(!dest) { - MCO_LOG("attempt peek into a null pointer"); - return MCO_INVALID_POINTER; - } - memcpy(dest, &co->storage[co->bytes_stored - len], len); - } - return MCO_SUCCESS; -} - -size_t mco_get_bytes_stored(mco_coro* co) { - if(co == NULL) { - return 0; - } - return co->bytes_stored; -} - -size_t mco_get_storage_size(mco_coro* co) { - if(co == NULL) { - return 0; - } - return co->storage_size; -} - -#ifdef MCO_NO_MULTITHREAD -mco_coro* mco_running(void) { - return mco_current_co; -} -#else -static MCO_NO_INLINE mco_coro* _mco_running(void) { - return mco_current_co; -} -mco_coro* mco_running(void) { - /* - Compilers aggressively optimize the use of TLS by caching loads. - Since fiber code can migrate between threads it’s possible for the load to be stale. - To prevent this from happening we avoid inline functions. - */ - mco_coro* (*volatile func)(void) = _mco_running; - return func(); -} -#endif - -const char* mco_result_description(mco_result res) { - switch(res) { - case MCO_SUCCESS: - return "No error"; - case MCO_GENERIC_ERROR: - return "Generic error"; - case MCO_INVALID_POINTER: - return "Invalid pointer"; - case MCO_INVALID_COROUTINE: - return "Invalid coroutine"; - case MCO_NOT_SUSPENDED: - return "Coroutine not suspended"; - case MCO_NOT_RUNNING: - return "Coroutine not running"; - case MCO_MAKE_CONTEXT_ERROR: - return "Make context error"; - case MCO_SWITCH_CONTEXT_ERROR: - return "Switch context error"; - case MCO_NOT_ENOUGH_SPACE: - return "Not enough space"; - case MCO_OUT_OF_MEMORY: - return "Out of memory"; - case MCO_INVALID_ARGUMENTS: - return "Invalid arguments"; - case MCO_INVALID_OPERATION: - return "Invalid operation"; - case MCO_STACK_OVERFLOW: - return "Stack overflow"; - } - return "Unknown error"; -} - -#ifdef __cplusplus -} -#endif - -#endif /* MINICORO_IMPL */ - -/* -This software is available as a choice of the following licenses. Choose -whichever you prefer. - -=============================================================================== -ALTERNATIVE 1 - Public Domain (www.unlicense.org) -=============================================================================== -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. - -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to - -=============================================================================== -ALTERNATIVE 2 - MIT No Attribution -=============================================================================== -Copyright (c) 2021-2022 Eduardo Bart (https://github.com/edubart/minicoro) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ diff --git a/3rdparty/minitrace/CMakeLists.txt b/3rdparty/minitrace/CMakeLists.txt deleted file mode 100644 index a228df116..000000000 --- a/3rdparty/minitrace/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -add_library(minitrace STATIC - minitrace.cpp -) - -add_library(minitrace::minitrace ALIAS minitrace) - -target_include_directories(minitrace - PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} -) - -target_compile_definitions(minitrace - PRIVATE - MTR_ENABLED=True -) - -set_property(TARGET minitrace - PROPERTY - POSITION_INDEPENDENT_CODE ON -) diff --git a/3rdparty/minitrace/LICENSE b/3rdparty/minitrace/LICENSE deleted file mode 100644 index f7469311e..000000000 --- a/3rdparty/minitrace/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Henrik RydgÃĨrd - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/3rdparty/minitrace/README.md b/3rdparty/minitrace/README.md deleted file mode 100644 index 75cdcbf05..000000000 --- a/3rdparty/minitrace/README.md +++ /dev/null @@ -1,113 +0,0 @@ -minitrace -========= -by Henrik RydgÃĨrd 2014 (hrydgard+minitrace@gmail.com) - -MIT licensed, feel free to use however you want. If you use it for something cool, I'd love to hear about it! - -This is a C library with C++ helpers for producing JSON traces suitable for Chrome's excellent built-in trace viewer (chrome://tracing). - -Extremely simple to build and use. Tested on Mac and Windows, but should compile anywhere you can use ANSI C with few or no changes. - -Sample output (see example code below): - -![minitrace](http://www.ppsspp.org/img/minitrace.png) - -Remember to be careful when interpreting the output. This is not a sampling profiler, so it only records start and stop times for blocks. This means that blocks grow even when the CPU is off running another thread, and that it can look like work is being done on more blocks at a time than you have CPUs. - - -How to use ----------- - - 1. Include `minitrace.c` and `minitrace.h` in your project. `#include minitrace.h` in some common header. - - 2. In your initialization code: - - ```c - mtr_init("trace.json"); - ``` - - 3. In your exit code: - - ```c - mtr_shutdown(); - ``` - - 4. Make sure `MTR_ENABLED` is defined globally when you want to profile, for example `-DMTR_ENABLED` - - 5. In all functions you want to profile: - - ```c - // C - MTR_BEGIN("GFX", "RasterizeTriangle") - ... - MTR_END("GFX", "RasterizeTriangle") - ``` - - ```c++ - // C++ - MTR_SCOPE("GFX", "RasterizeTriangle") - ``` - - 6. In Google Chrome open "about:tracing" - - 7. Click Open, and choose your `trace.json` - - 8. Navigate the trace view using the WASD keys, and Look for bottlenecks and optimize your application. - - 9. In your final release build, don't forget to remove `-DMTR_ENABLED` or however you set the define. - - -By default, it will collect 1 million tracepoints and then stop. You can change this behaviour, see the -top of the header file. - -Note: Please only use string literals in MTR statements. - -Example code ------------- - -```c -int main(int argc, const char *argv[]) { - int i; - mtr_init("trace.json"); - - MTR_META_PROCESS_NAME("minitrace_test"); - MTR_META_THREAD_NAME("main thread"); - - int long_running_thing_1; - int long_running_thing_2; - - MTR_START("background", "long_running", &long_running_thing_1); - MTR_START("background", "long_running", &long_running_thing_2); - - MTR_BEGIN("main", "outer"); - usleep(80000); - for (i = 0; i < 3; i++) { - MTR_BEGIN("main", "inner"); - usleep(40000); - MTR_END("main", "inner"); - usleep(10000); - } - MTR_STEP("background", "long_running", &long_running_thing_1, "middle step"); - usleep(80000); - MTR_END("main", "outer"); - - usleep(50000); - MTR_INSTANT("main", "the end"); - usleep(10000); - MTR_FINISH("background", "long_running", &long_running_thing_1); - MTR_FINISH("background", "long_running", &long_running_thing_2); - - mtr_flush(); - mtr_shutdown(); - return 0; -} -``` - -The output will result in something looking a little like the picture at the top of this readme. - -Future plans: - - * Builtin background flush thread support with better synchronization, no more fixed limit - * Support for more trace arguments, more tracing types - -If you use this, feel free to tell me how, and what issues you may have had. hrydgard+minitrace@gmail.com diff --git a/3rdparty/minitrace/minitrace.cpp b/3rdparty/minitrace/minitrace.cpp deleted file mode 100644 index a3ac5f829..000000000 --- a/3rdparty/minitrace/minitrace.cpp +++ /dev/null @@ -1,490 +0,0 @@ -// minitrace -// Copyright 2014 by Henrik RydgÃĨrd -// http://www.github.com/hrydgard/minitrace -// Released under the MIT license. - -// See minitrace.h for basic documentation. - -#include -#include -#include -#include - -#ifdef _WIN32 -#pragma warning (disable:4996) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#define __thread __declspec(thread) -#define pthread_mutex_t CRITICAL_SECTION -#define pthread_mutex_init(a, b) InitializeCriticalSection(a) -#define pthread_mutex_lock(a) EnterCriticalSection(a) -#define pthread_mutex_unlock(a) LeaveCriticalSection(a) -#define pthread_mutex_destroy(a) DeleteCriticalSection(a) -#else -#include -#include -#include -#include -#endif - -#define __STDC_FORMAT_MACROS -#include - -#include "minitrace.h" - -#ifdef __GNUC__ -#define ATTR_NORETURN __attribute__((noreturn)) -#else -#define ATTR_NORETURN -#endif - -#define ARRAY_SIZE(x) sizeof(x)/sizeof(x[0]) -#define TRUE 1 -#define FALSE 0 - -// Ugh, this struct is already pretty heavy. -// Will probably need to move arguments to a second buffer to support more than one. -typedef struct raw_event { - const char *name; - const char *cat; - void *id; - int64_t ts; - uint32_t pid; - uint32_t tid; - char ph; - mtr_arg_type arg_type; - const char *arg_name; - union { - const char *a_str; - int a_int; - double a_double; - }; -} raw_event_t; - -static raw_event_t *event_buffer; -static raw_event_t *flush_buffer; -static std::atomic_int event_count; -static int is_tracing = FALSE; -static int is_flushing = FALSE; -static int events_in_progress = 0; -static int64_t time_offset; -static int first_line = 1; -static FILE *f; -static __thread int cur_thread_id; // Thread local storage -static int cur_process_id; -static pthread_mutex_t mutex; -static pthread_mutex_t event_mutex; - -#define STRING_POOL_SIZE 100 -static char *str_pool[100]; - -// forward declaration -void mtr_flush_with_state(int); - -// Tiny portability layer. -// Exposes: -// get_cur_thread_id() -// get_cur_process_id() -// mtr_time_s() -// pthread basics -#ifdef _WIN32 -static int get_cur_thread_id() { - return (int)GetCurrentThreadId(); -} -static int get_cur_process_id() { - return (int)GetCurrentProcessId(); -} - -static uint64_t _frequency = 0; -static uint64_t _starttime = 0; -double mtr_time_s() { - if (_frequency == 0) { - QueryPerformanceFrequency((LARGE_INTEGER*)&_frequency); - QueryPerformanceCounter((LARGE_INTEGER*)&_starttime); - } - __int64 time; - QueryPerformanceCounter((LARGE_INTEGER*)&time); - return ((double) (time - _starttime) / (double) _frequency); -} - -// Ctrl+C handling for Windows console apps -static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) { - if (is_tracing && fdwCtrlType == CTRL_C_EVENT) { - printf("Ctrl-C detected! Flushing trace and shutting down.\n\n"); - mtr_flush(); - mtr_shutdown(); - } - ExitProcess(1); -} - -void mtr_register_sigint_handler() { - // For console apps: - SetConsoleCtrlHandler(&CtrlHandler, TRUE); -} - -#else - -static inline int get_cur_thread_id() { - return (int)(intptr_t)pthread_self(); -} -static inline int get_cur_process_id() { - return (int)getpid(); -} - -#if defined(BLACKBERRY) -double mtr_time_s() { - struct timespec time; - clock_gettime(CLOCK_MONOTONIC, &time); // Linux must use CLOCK_MONOTONIC_RAW due to time warps - return time.tv_sec + time.tv_nsec / 1.0e9; -} -#else -double mtr_time_s() { - static time_t start; - struct timeval tv; - gettimeofday(&tv, NULL); - if (start == 0) { - start = tv.tv_sec; - } - tv.tv_sec -= start; - return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; -} -#endif // !BLACKBERRY - -static void termination_handler(int signum) ATTR_NORETURN; -static void termination_handler(int signum) { - (void) signum; - if (is_tracing) { - printf("Ctrl-C detected! Flushing trace and shutting down.\n\n"); - mtr_flush(); - fwrite("\n]}\n", 1, 4, f); - fclose(f); - } - exit(1); -} - -void mtr_register_sigint_handler() { -#ifndef MTR_ENABLED - return; -#endif - // Avoid altering set-to-be-ignored handlers while registering. - if (signal(SIGINT, &termination_handler) == SIG_IGN) - signal(SIGINT, SIG_IGN); -} - -#endif - -void mtr_init_from_stream(void *stream) { -#ifndef MTR_ENABLED - return; -#endif - event_buffer = (raw_event_t *)malloc(INTERNAL_MINITRACE_BUFFER_SIZE * sizeof(raw_event_t)); - flush_buffer = (raw_event_t *)malloc(INTERNAL_MINITRACE_BUFFER_SIZE * sizeof(raw_event_t)); - is_tracing = 1; - event_count = 0; - f = (FILE *)stream; - const char *header = "{\"traceEvents\":[\n"; - fwrite(header, 1, strlen(header), f); - time_offset = (uint64_t)(mtr_time_s() * 1000000); - first_line = 1; - pthread_mutex_init(&mutex, 0); - pthread_mutex_init(&event_mutex, 0); -} - -void mtr_init(const char *json_file) { -#ifndef MTR_ENABLED - return; -#endif - mtr_init_from_stream(fopen(json_file, "wb")); -} - -void mtr_shutdown() { - int i; -#ifndef MTR_ENABLED - return; -#endif - pthread_mutex_lock(&mutex); - is_tracing = FALSE; - pthread_mutex_unlock(&mutex); - mtr_flush_with_state(TRUE); - - fwrite("\n]}\n", 1, 4, f); - fclose(f); - pthread_mutex_destroy(&mutex); - pthread_mutex_destroy(&event_mutex); - f = 0; - free(event_buffer); - event_buffer = 0; - for (i = 0; i < STRING_POOL_SIZE; i++) { - if (str_pool[i]) { - free(str_pool[i]); - str_pool[i] = 0; - } - } -} - -const char *mtr_pool_string(const char *str) { - int i; - for (i = 0; i < STRING_POOL_SIZE; i++) { - if (!str_pool[i]) { - str_pool[i] = (char*)malloc(strlen(str) + 1); - strcpy(str_pool[i], str); - return str_pool[i]; - } else { - if (!strcmp(str, str_pool[i])) - return str_pool[i]; - } - } - return "string pool full"; -} - -void mtr_start() { -#ifndef MTR_ENABLED - return; -#endif - pthread_mutex_lock(&mutex); - is_tracing = TRUE; - pthread_mutex_unlock(&mutex); -} - -void mtr_stop() { -#ifndef MTR_ENABLED - return; -#endif - pthread_mutex_lock(&mutex); - is_tracing = FALSE; - pthread_mutex_unlock(&mutex); -} - -// TODO: fwrite more than one line at a time. -// Flushing is thread safe and process async -// using double-buffering mechanism. -// Aware: only one flushing process may be -// running at any point of time -void mtr_flush_with_state(int is_last) { -#ifndef MTR_ENABLED - return; -#endif - int i = 0; - char linebuf[1024]; - char arg_buf[1024]; - char id_buf[256]; - int event_count_copy = 0; - int events_in_progress_copy = 1; - raw_event_t *event_buffer_tmp = NULL; - - // small critical section to swap buffers - // - no any new events can be spawn while - // swapping since they tied to the same mutex - // - checks for any flushing in process - pthread_mutex_lock(&mutex); - // if not flushing already - if (is_flushing) { - pthread_mutex_unlock(&mutex); - return; - } - is_flushing = TRUE; - event_count_copy = event_count; - event_buffer_tmp = flush_buffer; - flush_buffer = event_buffer; - event_buffer = event_buffer_tmp; - event_count = 0; - // waiting for any unfinished events before swap - while (events_in_progress_copy != 0) { - pthread_mutex_lock(&event_mutex); - events_in_progress_copy = events_in_progress; - pthread_mutex_unlock(&event_mutex); - } - pthread_mutex_unlock(&mutex); - - for (i = 0; i < event_count_copy; i++) { - raw_event_t *raw = &flush_buffer[i]; - int len; - switch (raw->arg_type) { - case MTR_ARG_TYPE_INT: - snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":%i", raw->arg_name, raw->a_int); - break; - case MTR_ARG_TYPE_STRING_CONST: - snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":\"%s\"", raw->arg_name, raw->a_str); - break; - case MTR_ARG_TYPE_STRING_COPY: - if (strlen(raw->a_str) > 700) { - snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":\"%.*s\"", raw->arg_name, 700, raw->a_str); - } else { - snprintf(arg_buf, ARRAY_SIZE(arg_buf), "\"%s\":\"%s\"", raw->arg_name, raw->a_str); - } - break; - case MTR_ARG_TYPE_NONE: - arg_buf[0] = '\0'; - break; - } - if (raw->id) { - switch (raw->ph) { - case 'S': - case 'T': - case 'F': - // TODO: Support full 64-bit pointers - snprintf(id_buf, ARRAY_SIZE(id_buf), ",\"id\":\"0x%08x\"", (uint32_t)(uintptr_t)raw->id); - break; - case 'X': - snprintf(id_buf, ARRAY_SIZE(id_buf), ",\"dur\":%i", (int)raw->a_double); - break; - } - } else { - id_buf[0] = 0; - } - const char *cat = raw->cat; -#ifdef _WIN32 - // On Windows, we often end up with backslashes in category. - char temp[256]; - { - int len = (int)strlen(cat); - int i; - if (len > 255) len = 255; - for (i = 0; i < len; i++) { - temp[i] = cat[i] == '\\' ? '/' : cat[i]; - } - temp[len] = 0; - cat = temp; - } -#endif - - len = snprintf(linebuf, ARRAY_SIZE(linebuf), "%s{\"cat\":\"%s\",\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 ",\"ph\":\"%c\",\"name\":\"%s\",\"args\":{%s}%s}", - first_line ? "" : ",\n", - cat, raw->pid, raw->tid, raw->ts - time_offset, raw->ph, raw->name, arg_buf, id_buf); - fwrite(linebuf, 1, len, f); - first_line = 0; - - if (raw->arg_type == MTR_ARG_TYPE_STRING_COPY) { - free((void*)raw->a_str); - } - #ifdef MTR_COPY_EVENT_CATEGORY_AND_NAME - free(raw->name); - free(raw->cat); - #endif - } - - pthread_mutex_lock(&mutex); - is_flushing = is_last; - pthread_mutex_unlock(&mutex); -} - -void mtr_flush() { - mtr_flush_with_state(FALSE); -} - -void internal_mtr_raw_event(const char *category, const char *name, char ph, void *id) { -#ifndef MTR_ENABLED - return; -#endif - pthread_mutex_lock(&mutex); - if (!is_tracing || event_count >= INTERNAL_MINITRACE_BUFFER_SIZE) { - pthread_mutex_unlock(&mutex); - return; - } - raw_event_t *ev = &event_buffer[event_count]; - ++event_count; - pthread_mutex_lock(&event_mutex); - ++events_in_progress; - pthread_mutex_unlock(&event_mutex); - pthread_mutex_unlock(&mutex); - - double ts = mtr_time_s(); - if (!cur_thread_id) { - cur_thread_id = get_cur_thread_id(); - } - if (!cur_process_id) { - cur_process_id = get_cur_process_id(); - } - -#ifdef MTR_COPY_EVENT_CATEGORY_AND_NAME - const size_t category_len = strlen(category); - ev->cat = malloc(category_len + 1); - strcpy(ev->cat, category); - - const size_t name_len = strlen(name); - ev->name = malloc(name_len + 1); - strcpy(ev->name, name); - -#else - ev->cat = category; - ev->name = name; -#endif - - ev->id = id; - ev->ph = ph; - if (ev->ph == 'X') { - double x; - memcpy(&x, id, sizeof(double)); - ev->ts = (int64_t)(x * 1000000); - ev->a_double = (ts - x) * 1000000; - } else { - ev->ts = (int64_t)(ts * 1000000); - } - ev->tid = cur_thread_id; - ev->pid = cur_process_id; - ev->arg_type = MTR_ARG_TYPE_NONE; - - pthread_mutex_lock(&event_mutex); - --events_in_progress; - pthread_mutex_unlock(&event_mutex); -} - -void internal_mtr_raw_event_arg(const char *category, const char *name, char ph, void *id, mtr_arg_type arg_type, const char *arg_name, void *arg_value) { -#ifndef MTR_ENABLED - return; -#endif - pthread_mutex_lock(&mutex); - if (!is_tracing || event_count >= INTERNAL_MINITRACE_BUFFER_SIZE) { - pthread_mutex_unlock(&mutex); - return; - } - raw_event_t *ev = &event_buffer[event_count]; - ++event_count; - pthread_mutex_lock(&event_mutex); - ++events_in_progress; - pthread_mutex_unlock(&event_mutex); - pthread_mutex_unlock(&mutex); - - if (!cur_thread_id) { - cur_thread_id = get_cur_thread_id(); - } - if (!cur_process_id) { - cur_process_id = get_cur_process_id(); - } - double ts = mtr_time_s(); - -#ifdef MTR_COPY_EVENT_CATEGORY_AND_NAME - const size_t category_len = strlen(category); - ev->cat = malloc(category_len + 1); - strcpy(ev->cat, category); - - const size_t name_len = strlen(name); - ev->name = malloc(name_len + 1); - strcpy(ev->name, name); - -#else - ev->cat = category; - ev->name = name; -#endif - - ev->id = id; - ev->ts = (int64_t)(ts * 1000000); - ev->ph = ph; - ev->tid = cur_thread_id; - ev->pid = cur_process_id; - ev->arg_type = arg_type; - ev->arg_name = arg_name; - switch (arg_type) { - case MTR_ARG_TYPE_INT: ev->a_int = (int)(uintptr_t)arg_value; break; - case MTR_ARG_TYPE_STRING_CONST: ev->a_str = (const char*)arg_value; break; - case MTR_ARG_TYPE_STRING_COPY: ev->a_str = strdup((const char*)arg_value); break; - case MTR_ARG_TYPE_NONE: break; - } - - pthread_mutex_lock(&event_mutex); - --events_in_progress; - pthread_mutex_unlock(&event_mutex); -} - diff --git a/3rdparty/minitrace/minitrace.h b/3rdparty/minitrace/minitrace.h deleted file mode 100644 index 465c1aff5..000000000 --- a/3rdparty/minitrace/minitrace.h +++ /dev/null @@ -1,276 +0,0 @@ -// Minitrace -// -// Copyright 2014 by Henrik RydgÃĨrd -// http://www.github.com/hrydgard/minitrace -// Released under the MIT license. -// -// Ultra-light dependency free library for performance tracing C/C++ applications. -// Produces traces compatible with Google Chrome's trace viewer. -// Simply open "about:tracing" in Chrome and load the produced JSON. -// -// This contains far less template magic than the original libraries from Chrome -// because this is meant to be usable from C. -// -// See README.md for a tutorial. -// -// The trace format is documented here: -// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit -// More: -// http://www.altdevblogaday.com/2012/08/21/using-chrometracing-to-view-your-inline-profiling-data/ - -#ifndef MINITRACE_H -#define MINITRACE_H - -#include - -#ifdef MTR_BUILDING_WITH_CMAKE -#include "minitrace_export.h" -#else -#define MINITRACE_EXPORT -#endif - -// If MTR_ENABLED is not defined, Minitrace does nothing and has near zero overhead. -// Preferably, set this flag in your build system. If you can't just uncomment this line. -// #define MTR_ENABLED - -// By default, will collect up to 1000000 events, then you must flush. -// It's recommended that you simply call mtr_flush on a background thread -// occasionally. It's safe...ish. -#define INTERNAL_MINITRACE_BUFFER_SIZE 1000000 - -#ifdef __cplusplus -extern "C" { -#endif - -// Initializes Minitrace. Must be called very early during startup of your executable, -// before any MTR_ statements. -MINITRACE_EXPORT void mtr_init(const char *json_file); -// Same as above, but allows passing in a custom stream (FILE *), as returned by -// fopen(). It should be opened for writing, preferably in binary mode to avoid -// processing of line endings (i.e. the "wb" mode). -MINITRACE_EXPORT void mtr_init_from_stream(void *stream); - -// Shuts down minitrace cleanly, flushing the trace buffer. -MINITRACE_EXPORT void mtr_shutdown(void); - -// Lets you enable and disable Minitrace at runtime. -// May cause strange discontinuities in the output. -// Minitrace is enabled on startup by default. -MINITRACE_EXPORT void mtr_start(void); -MINITRACE_EXPORT void mtr_stop(void); - -// Flushes the collected data to disk, clearing the buffer for new data. -MINITRACE_EXPORT void mtr_flush(void); - -// Returns the current time in seconds. Used internally by Minitrace. No caching. -MINITRACE_EXPORT double mtr_time_s(void); - -// Registers a handler that will flush the trace on Ctrl+C. -// Works on Linux and MacOSX, and in Win32 console applications. -MINITRACE_EXPORT void mtr_register_sigint_handler(void); - -// Utility function that should rarely be used. -// If str is semi dynamic, store it permanently in a small pool so we don't need to malloc it. -// The pool fills up fast though and performance isn't great. -// Returns a fixed string if the pool is full. -MINITRACE_EXPORT const char *mtr_pool_string(const char *str); - -// Commented-out types will be supported in the future. -typedef enum { - MTR_ARG_TYPE_NONE = 0, - MTR_ARG_TYPE_INT = 1, // I - // MTR_ARG_TYPE_FLOAT = 2, // TODO - // MTR_ARG_TYPE_DOUBLE = 3, // TODO - MTR_ARG_TYPE_STRING_CONST = 8, // C - MTR_ARG_TYPE_STRING_COPY = 9, - // MTR_ARG_TYPE_JSON_COPY = 10, -} mtr_arg_type; - -// TODO: Add support for more than one argument (metadata) per event -// Having more costs speed and memory. -#define MTR_MAX_ARGS 1 - -// Only use the macros to call these. -MINITRACE_EXPORT void internal_mtr_raw_event(const char *category, const char *name, char ph, void *id); -MINITRACE_EXPORT void internal_mtr_raw_event_arg(const char *category, const char *name, char ph, void *id, mtr_arg_type arg_type, const char *arg_name, void *arg_value); - -#ifdef MTR_ENABLED - -// c - category. Can be filtered by in trace viewer (or at least that's the intention). -// A good use is to pass __FILE__, there are macros further below that will do it for you. -// n - name. Pass __FUNCTION__ in most cases, unless you are marking up parts of one. - -// Scopes. In C++, use MTR_SCOPE. In C, always match them within the same scope. -#define MTR_BEGIN(c, n) internal_mtr_raw_event(c, n, 'B', nullptr) -#define MTR_END(c, n) internal_mtr_raw_event(c, n, 'E', nullptr) -#define MTR_SCOPE(c, n) MTRScopedTrace ____mtr_scope(c, n) -#define MTR_SCOPE_LIMIT(c, n, l) MTRScopedTraceLimit ____mtr_scope(c, n, l) - -// Async events. Can span threads. ID identifies which events to connect in the view. -#define MTR_START(c, n, id) internal_mtr_raw_event(c, n, 'S', (void *)(id)) -#define MTR_STEP(c, n, id, step) internal_mtr_raw_event_arg(c, n, 'T', (void *)(id), MTR_ARG_TYPE_STRING_CONST, "step", (void *)(step)) -#define MTR_FINISH(c, n, id) internal_mtr_raw_event(c, n, 'F', (void *)(id)) - -// Flow events. Like async events, but displayed in a more fancy way in the viewer. -#define MTR_FLOW_START(c, n, id) internal_mtr_raw_event(c, n, 's', (void *)(id)) -#define MTR_FLOW_STEP(c, n, id, step) internal_mtr_raw_event_arg(c, n, 't', (void *)(id), MTR_ARG_TYPE_STRING_CONST, "step", (void *)(step)) -#define MTR_FLOW_FINISH(c, n, id) internal_mtr_raw_event(c, n, 'f', (void *)(id)) - -// The same macros, but with a single named argument which shows up as metadata in the viewer. -// _I for int. -// _C is for a const string arg. -// _S will copy the string, freeing on flush (expensive but sometimes necessary). -// but required if the string was generated dynamically. - -// Note that it's fine to match BEGIN_S with END and BEGIN with END_S, etc. -#define MTR_BEGIN_C(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'B', 0, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval)) -#define MTR_END_C(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'E', 0, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval)) -#define MTR_SCOPE_C(c, n, aname, astrval) MTRScopedTraceArg ____mtr_scope(c, n, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval)) - -#define MTR_BEGIN_S(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'B', 0, MTR_ARG_TYPE_STRING_COPY, aname, (void *)(astrval)) -#define MTR_END_S(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'E', 0, MTR_ARG_TYPE_STRING_COPY, aname, (void *)(astrval)) -#define MTR_SCOPE_S(c, n, aname, astrval) MTRScopedTraceArg ____mtr_scope(c, n, MTR_ARG_TYPE_STRING_COPY, aname, (void *)(astrval)) - -#define MTR_BEGIN_I(c, n, aname, aintval) internal_mtr_raw_event_arg(c, n, 'B', 0, MTR_ARG_TYPE_INT, aname, (void*)(intptr_t)(aintval)) -#define MTR_END_I(c, n, aname, aintval) internal_mtr_raw_event_arg(c, n, 'E', 0, MTR_ARG_TYPE_INT, aname, (void*)(intptr_t)(aintval)) -#define MTR_SCOPE_I(c, n, aname, aintval) MTRScopedTraceArg ____mtr_scope(c, n, MTR_ARG_TYPE_INT, aname, (void*)(intptr_t)(aintval)) - -// Instant events. For things with no duration. -#define MTR_INSTANT(c, n) internal_mtr_raw_event(c, n, 'I', nullptr) -#define MTR_INSTANT_C(c, n, aname, astrval) internal_mtr_raw_event_arg(c, n, 'I', 0, MTR_ARG_TYPE_STRING_CONST, aname, (void *)(astrval)) -#define MTR_INSTANT_I(c, n, aname, aintval) internal_mtr_raw_event_arg(c, n, 'I', 0, MTR_ARG_TYPE_INT, aname, (void *)(aintval)) - -// Counters (can't do multi-value counters yet) -#define MTR_COUNTER(c, n, val) internal_mtr_raw_event_arg(c, n, 'C', 0, MTR_ARG_TYPE_INT, n, (void *)(intptr_t)(val)) - -// Metadata. Call at the start preferably. Must be const strings. - -#define MTR_META_PROCESS_NAME(n) internal_mtr_raw_event_arg("", "process_name", 'M', 0, MTR_ARG_TYPE_STRING_COPY, "name", (void *)(n)) -#define MTR_META_THREAD_NAME(n) internal_mtr_raw_event_arg("", "thread_name", 'M', 0, MTR_ARG_TYPE_STRING_COPY, "name", (void *)(n)) -#define MTR_META_THREAD_SORT_INDEX(i) internal_mtr_raw_event_arg("", "thread_sort_index", 'M', 0, MTR_ARG_TYPE_INT, "sort_index", (void *)(i)) - -#else - -#define MTR_BEGIN(c, n) -#define MTR_END(c, n) -#define MTR_SCOPE(c, n) -#define MTR_START(c, n, id) -#define MTR_STEP(c, n, id, step) -#define MTR_FINISH(c, n, id) -#define MTR_FLOW_START(c, n, id) -#define MTR_FLOW_STEP(c, n, id, step) -#define MTR_FLOW_FINISH(c, n, id) -#define MTR_INSTANT(c, n) - -#define MTR_BEGIN_C(c, n, aname, astrval) -#define MTR_END_C(c, n, aname, astrval) -#define MTR_SCOPE_C(c, n, aname, astrval) - -#define MTR_BEGIN_S(c, n, aname, astrval) -#define MTR_END_S(c, n, aname, astrval) -#define MTR_SCOPE_S(c, n, aname, astrval) - -#define MTR_BEGIN_I(c, n, aname, aintval) -#define MTR_END_I(c, n, aname, aintval) -#define MTR_SCOPE_I(c, n, aname, aintval) - -#define MTR_INSTANT(c, n) -#define MTR_INSTANT_C(c, n, aname, astrval) -#define MTR_INSTANT_I(c, n, aname, aintval) - -// Counters (can't do multi-value counters yet) -#define MTR_COUNTER(c, n, val) - -// Metadata. Call at the start preferably. Must be const strings. - -#define MTR_META_PROCESS_NAME(n) - -#define MTR_META_THREAD_NAME(n) -#define MTR_META_THREAD_SORT_INDEX(i) - -#endif - -// Shortcuts for simple function timing with automatic categories and names. - -#define MTR_BEGIN_FUNC() MTR_BEGIN(__FILE__, __FUNCTION__) -#define MTR_END_FUNC() MTR_END(__FILE__, __FUNCTION__) -#define MTR_SCOPE_FUNC() MTR_SCOPE(__FILE__, __FUNCTION__) -#define MTR_INSTANT_FUNC() MTR_INSTANT(__FILE__, __FUNCTION__) -#define MTR_SCOPE_FUNC_LIMIT_S(l) MTRScopedTraceLimit ____mtr_scope(__FILE__, __FUNCTION__, l) -#define MTR_SCOPE_FUNC_LIMIT_MS(l) MTRScopedTraceLimit ____mtr_scope(__FILE__, __FUNCTION__, (double)l * 0.000001) - -// Same, but with a single argument of the usual types. -#define MTR_BEGIN_FUNC_S(aname, arg) MTR_BEGIN_S(__FILE__, __FUNCTION__, aname, arg) -#define MTR_END_FUNC_S(aname, arg) MTR_END_S(__FILE__, __FUNCTION__, aname, arg) -#define MTR_SCOPE_FUNC_S(aname, arg) MTR_SCOPE_S(__FILE__, __FUNCTION__, aname, arg) - -#define MTR_BEGIN_FUNC_C(aname, arg) MTR_BEGIN_C(__FILE__, __FUNCTION__, aname, arg) -#define MTR_END_FUNC_C(aname, arg) MTR_END_C(__FILE__, __FUNCTION__, aname, arg) -#define MTR_SCOPE_FUNC_C(aname, arg) MTR_SCOPE_C(__FILE__, __FUNCTION__, aname, arg) - -#define MTR_BEGIN_FUNC_I(aname, arg) MTR_BEGIN_I(__FILE__, __FUNCTION__, aname, arg) -#define MTR_END_FUNC_I(aname, arg) MTR_END_I(__FILE__, __FUNCTION__, aname, arg) -#define MTR_SCOPE_FUNC_I(aname, arg) MTR_SCOPE_I(__FILE__, __FUNCTION__, aname, arg) - -#ifdef __cplusplus -} - -#ifdef MTR_ENABLED -// These are optimized to use X events (combined B and E). Much easier to do in C++ than in C. -class MTRScopedTrace { -public: - MTRScopedTrace(const char *category, const char *name) - : category_(category), name_(name) { - start_time_ = mtr_time_s(); - } - ~MTRScopedTrace() { - internal_mtr_raw_event(category_, name_, 'X', &start_time_); - } - -private: - const char *category_; - const char *name_; - double start_time_; -}; - -// Only outputs a block if execution time exceeded the limit. -// TODO: This will effectively call mtr_time_s twice at the end, which is bad. -class MTRScopedTraceLimit { -public: - MTRScopedTraceLimit(const char *category, const char *name, double limit_s) - : category_(category), name_(name), limit_(limit_s) { - start_time_ = mtr_time_s(); - } - ~MTRScopedTraceLimit() { - double end_time = mtr_time_s(); - if (end_time - start_time_ >= limit_) { - internal_mtr_raw_event(category_, name_, 'X', &start_time_); - } - } - -private: - const char *category_; - const char *name_; - double start_time_; - double limit_; -}; - -class MTRScopedTraceArg { -public: - MTRScopedTraceArg(const char *category, const char *name, mtr_arg_type arg_type, const char *arg_name, void *arg_value) - : category_(category), name_(name) { - internal_mtr_raw_event_arg(category, name, 'B', 0, arg_type, arg_name, arg_value); - } - ~MTRScopedTraceArg() { - internal_mtr_raw_event(category_, name_, 'E', 0); - } - -private: - const char *category_; - const char *name_; -}; -#endif - -#endif - -#endif diff --git a/3rdparty/tinyxml2/CMakeLists.txt b/3rdparty/tinyxml2/CMakeLists.txt deleted file mode 100644 index 9d5dc9fb9..000000000 --- a/3rdparty/tinyxml2/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -add_library(tinyxml2 STATIC - tinyxml2.cpp -) - -add_library(tinyxml2::tinyxml2 ALIAS tinyxml2) - -target_include_directories(tinyxml2 - PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} -) - -set_property(TARGET tinyxml2 - PROPERTY - POSITION_INDEPENDENT_CODE ON -) diff --git a/3rdparty/tinyxml2/LICENSE.txt b/3rdparty/tinyxml2/LICENSE.txt deleted file mode 100644 index 85a6a36f0..000000000 --- a/3rdparty/tinyxml2/LICENSE.txt +++ /dev/null @@ -1,18 +0,0 @@ -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. diff --git a/3rdparty/tinyxml2/tinyxml2.cpp b/3rdparty/tinyxml2/tinyxml2.cpp deleted file mode 100644 index 66ef0c962..000000000 --- a/3rdparty/tinyxml2/tinyxml2.cpp +++ /dev/null @@ -1,3019 +0,0 @@ -/* -Original code by Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#include "tinyxml2.h" - -#include // yes, this one new style header, is in the Android SDK. -#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) || defined(__CC_ARM) -# include -# include -#else -# include -# include -#endif - -#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) - // Microsoft Visual Studio, version 2005 and higher. Not WinCE. - /*int _snprintf_s( - char *buffer, - size_t sizeOfBuffer, - size_t count, - const char *format [, - argument] ... - );*/ - static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) - { - va_list va; - va_start( va, format ); - const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); - va_end( va ); - return result; - } - - static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va ) - { - const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); - return result; - } - - #define TIXML_VSCPRINTF _vscprintf - #define TIXML_SSCANF sscanf_s -#elif defined _MSC_VER - // Microsoft Visual Studio 2003 and earlier or WinCE - #define TIXML_SNPRINTF _snprintf - #define TIXML_VSNPRINTF _vsnprintf - #define TIXML_SSCANF sscanf - #if (_MSC_VER < 1400 ) && (!defined WINCE) - // Microsoft Visual Studio 2003 and not WinCE. - #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have. - #else - // Microsoft Visual Studio 2003 and earlier or WinCE. - static inline int TIXML_VSCPRINTF( const char* format, va_list va ) - { - int len = 512; - for (;;) { - len = len*2; - char* str = new char[len](); - const int required = _vsnprintf(str, len, format, va); - delete[] str; - if ( required != -1 ) { - TIXMLASSERT( required >= 0 ); - len = required; - break; - } - } - TIXMLASSERT( len >= 0 ); - return len; - } - #endif -#else - // GCC version 3 and higher - //#warning( "Using sn* functions." ) - #define TIXML_SNPRINTF snprintf - #define TIXML_VSNPRINTF vsnprintf - static inline int TIXML_VSCPRINTF( const char* format, va_list va ) - { - int len = vsnprintf( 0, 0, format, va ); - TIXMLASSERT( len >= 0 ); - return len; - } - #define TIXML_SSCANF sscanf -#endif - -#if defined(_WIN64) - #define TIXML_FSEEK _fseeki64 - #define TIXML_FTELL _ftelli64 -#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__CYGWIN__) - #define TIXML_FSEEK fseeko - #define TIXML_FTELL ftello -#elif defined(__ANDROID__) && __ANDROID_API__ > 24 - #define TIXML_FSEEK fseeko64 - #define TIXML_FTELL ftello64 -#else - #define TIXML_FSEEK fseek - #define TIXML_FTELL ftell -#endif - - -static const char LINE_FEED = static_cast(0x0a); // all line endings are normalized to LF -static const char LF = LINE_FEED; -static const char CARRIAGE_RETURN = static_cast(0x0d); // CR gets filtered out -static const char CR = CARRIAGE_RETURN; -static const char SINGLE_QUOTE = '\''; -static const char DOUBLE_QUOTE = '\"'; - -// Bunch of unicode info at: -// http://www.unicode.org/faq/utf_bom.html -// ef bb bf (Microsoft "lead bytes") - designates UTF-8 - -static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; -static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; -static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; - -namespace tinyxml2 -{ - -struct Entity { - const char* pattern; - int length; - char value; -}; - -static const int NUM_ENTITIES = 5; -static const Entity entities[NUM_ENTITIES] = { - { "quot", 4, DOUBLE_QUOTE }, - { "amp", 3, '&' }, - { "apos", 4, SINGLE_QUOTE }, - { "lt", 2, '<' }, - { "gt", 2, '>' } -}; - - -StrPair::~StrPair() -{ - Reset(); -} - - -void StrPair::TransferTo( StrPair* other ) -{ - if ( this == other ) { - return; - } - // This in effect implements the assignment operator by "moving" - // ownership (as in auto_ptr). - - TIXMLASSERT( other != 0 ); - TIXMLASSERT( other->_flags == 0 ); - TIXMLASSERT( other->_start == 0 ); - TIXMLASSERT( other->_end == 0 ); - - other->Reset(); - - other->_flags = _flags; - other->_start = _start; - other->_end = _end; - - _flags = 0; - _start = 0; - _end = 0; -} - - -void StrPair::Reset() -{ - if ( _flags & NEEDS_DELETE ) { - delete [] _start; - } - _flags = 0; - _start = 0; - _end = 0; -} - - -void StrPair::SetStr( const char* str, int flags ) -{ - TIXMLASSERT( str ); - Reset(); - size_t len = strlen( str ); - TIXMLASSERT( _start == 0 ); - _start = new char[ len+1 ]; - memcpy( _start, str, len+1 ); - _end = _start + len; - _flags = flags | NEEDS_DELETE; -} - - -char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr ) -{ - TIXMLASSERT( p ); - TIXMLASSERT( endTag && *endTag ); - TIXMLASSERT(curLineNumPtr); - - char* start = p; - const char endChar = *endTag; - size_t length = strlen( endTag ); - - // Inner loop of text parsing. - while ( *p ) { - if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { - Set( start, p, strFlags ); - return p + length; - } else if (*p == '\n') { - ++(*curLineNumPtr); - } - ++p; - TIXMLASSERT( p ); - } - return 0; -} - - -char* StrPair::ParseName( char* p ) -{ - if ( !p || !(*p) ) { - return 0; - } - if ( !XMLUtil::IsNameStartChar( static_cast(*p) ) ) { - return 0; - } - - char* const start = p; - ++p; - while ( *p && XMLUtil::IsNameChar( static_cast(*p) ) ) { - ++p; - } - - Set( start, p, 0 ); - return p; -} - - -void StrPair::CollapseWhitespace() -{ - // Adjusting _start would cause undefined behavior on delete[] - TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 ); - // Trim leading space. - _start = XMLUtil::SkipWhiteSpace( _start, 0 ); - - if ( *_start ) { - const char* p = _start; // the read pointer - char* q = _start; // the write pointer - - while( *p ) { - if ( XMLUtil::IsWhiteSpace( *p )) { - p = XMLUtil::SkipWhiteSpace( p, 0 ); - if ( *p == 0 ) { - break; // don't write to q; this trims the trailing space. - } - *q = ' '; - ++q; - } - *q = *p; - ++q; - ++p; - } - *q = 0; - } -} - - -const char* StrPair::GetStr() -{ - TIXMLASSERT( _start ); - TIXMLASSERT( _end ); - if ( _flags & NEEDS_FLUSH ) { - *_end = 0; - _flags ^= NEEDS_FLUSH; - - if ( _flags ) { - const char* p = _start; // the read pointer - char* q = _start; // the write pointer - - while( p < _end ) { - if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) { - // CR-LF pair becomes LF - // CR alone becomes LF - // LF-CR becomes LF - if ( *(p+1) == LF ) { - p += 2; - } - else { - ++p; - } - *q = LF; - ++q; - } - else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { - if ( *(p+1) == CR ) { - p += 2; - } - else { - ++p; - } - *q = LF; - ++q; - } - else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { - // Entities handled by tinyXML2: - // - special entities in the entity table [in/out] - // - numeric character reference [in] - // 中 or 中 - - if ( *(p+1) == '#' ) { - const int buflen = 10; - char buf[buflen] = { 0 }; - int len = 0; - const char* adjusted = const_cast( XMLUtil::GetCharacterRef( p, buf, &len ) ); - if ( adjusted == 0 ) { - *q = *p; - ++p; - ++q; - } - else { - TIXMLASSERT( 0 <= len && len <= buflen ); - TIXMLASSERT( q + len <= adjusted ); - p = adjusted; - memcpy( q, buf, len ); - q += len; - } - } - else { - bool entityFound = false; - for( int i = 0; i < NUM_ENTITIES; ++i ) { - const Entity& entity = entities[i]; - if ( strncmp( p + 1, entity.pattern, entity.length ) == 0 - && *( p + entity.length + 1 ) == ';' ) { - // Found an entity - convert. - *q = entity.value; - ++q; - p += entity.length + 2; - entityFound = true; - break; - } - } - if ( !entityFound ) { - // fixme: treat as error? - ++p; - ++q; - } - } - } - else { - *q = *p; - ++p; - ++q; - } - } - *q = 0; - } - // The loop below has plenty going on, and this - // is a less useful mode. Break it out. - if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) { - CollapseWhitespace(); - } - _flags = (_flags & NEEDS_DELETE); - } - TIXMLASSERT( _start ); - return _start; -} - - - - -// --------- XMLUtil ----------- // - -const char* XMLUtil::writeBoolTrue = "true"; -const char* XMLUtil::writeBoolFalse = "false"; - -void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse) -{ - static const char* defTrue = "true"; - static const char* defFalse = "false"; - - writeBoolTrue = (writeTrue) ? writeTrue : defTrue; - writeBoolFalse = (writeFalse) ? writeFalse : defFalse; -} - - -const char* XMLUtil::ReadBOM( const char* p, bool* bom ) -{ - TIXMLASSERT( p ); - TIXMLASSERT( bom ); - *bom = false; - const unsigned char* pu = reinterpret_cast(p); - // Check for BOM: - if ( *(pu+0) == TIXML_UTF_LEAD_0 - && *(pu+1) == TIXML_UTF_LEAD_1 - && *(pu+2) == TIXML_UTF_LEAD_2 ) { - *bom = true; - p += 3; - } - TIXMLASSERT( p ); - return p; -} - - -void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) -{ - const unsigned long BYTE_MASK = 0xBF; - const unsigned long BYTE_MARK = 0x80; - const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - - if (input < 0x80) { - *length = 1; - } - else if ( input < 0x800 ) { - *length = 2; - } - else if ( input < 0x10000 ) { - *length = 3; - } - else if ( input < 0x200000 ) { - *length = 4; - } - else { - *length = 0; // This code won't convert this correctly anyway. - return; - } - - output += *length; - - // Scary scary fall throughs are annotated with carefully designed comments - // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc - switch (*length) { - case 4: - --output; - *output = static_cast((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - //fall through - case 3: - --output; - *output = static_cast((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - //fall through - case 2: - --output; - *output = static_cast((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - //fall through - case 1: - --output; - *output = static_cast(input | FIRST_BYTE_MARK[*length]); - break; - default: - TIXMLASSERT( false ); - } -} - - -const char* XMLUtil::GetCharacterRef(const char* p, char* value, int* length) -{ - // Assume an entity, and pull it out. - *length = 0; - - static const uint32_t MAX_CODE_POINT = 0x10FFFF; - - if (*(p + 1) == '#' && *(p + 2)) { - uint32_t ucs = 0; - ptrdiff_t delta = 0; - uint32_t mult = 1; - static const char SEMICOLON = ';'; - - bool hex = false; - uint32_t radix = 10; - const char* q = 0; - char terminator = '#'; - - if (*(p + 2) == 'x') { - // Hexadecimal. - hex = true; - radix = 16; - terminator = 'x'; - - q = p + 3; - } - else { - // Decimal. - q = p + 2; - } - if (!(*q)) { - return 0; - } - - q = strchr(q, SEMICOLON); - if (!q) { - return 0; - } - TIXMLASSERT(*q == SEMICOLON); - - delta = q - p; - --q; - - while (*q != terminator) { - uint32_t digit = 0; - - if (*q >= '0' && *q <= '9') { - digit = *q - '0'; - } - else if (hex && (*q >= 'a' && *q <= 'f')) { - digit = *q - 'a' + 10; - } - else if (hex && (*q >= 'A' && *q <= 'F')) { - digit = *q - 'A' + 10; - } - else { - return 0; - } - TIXMLASSERT(digit < radix); - - const unsigned int digitScaled = mult * digit; - ucs += digitScaled; - mult *= radix; - - // Security check: could a value exist that is out of range? - // Easily; limit to the MAX_CODE_POINT, which also allows for a - // bunch of leading zeroes. - if (mult > MAX_CODE_POINT) { - mult = MAX_CODE_POINT; - } - --q; - } - // Out of range: - if (ucs > MAX_CODE_POINT) { - return 0; - } - // convert the UCS to UTF-8 - ConvertUTF32ToUTF8(ucs, value, length); - if (length == 0) { - // If length is 0, there was an error. (Security? Bad input?) - // Fail safely. - return 0; - } - return p + delta + 1; - } - return p + 1; -} - -void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) -{ - TIXML_SNPRINTF( buffer, bufferSize, "%d", v ); -} - - -void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize ) -{ - TIXML_SNPRINTF( buffer, bufferSize, "%u", v ); -} - - -void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) -{ - TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse); -} - -/* - ToStr() of a number is a very tricky topic. - https://github.com/leethomason/tinyxml2/issues/106 -*/ -void XMLUtil::ToStr( float v, char* buffer, int bufferSize ) -{ - TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v ); -} - - -void XMLUtil::ToStr( double v, char* buffer, int bufferSize ) -{ - TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v ); -} - - -void XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize ) -{ - // horrible syntax trick to make the compiler happy about %lld - TIXML_SNPRINTF(buffer, bufferSize, "%lld", static_cast(v)); -} - -void XMLUtil::ToStr( uint64_t v, char* buffer, int bufferSize ) -{ - // horrible syntax trick to make the compiler happy about %llu - TIXML_SNPRINTF(buffer, bufferSize, "%llu", static_cast(v)); -} - -bool XMLUtil::ToInt(const char* str, int* value) -{ - if (IsPrefixHex(str)) { - unsigned v; - if (TIXML_SSCANF(str, "%x", &v) == 1) { - *value = static_cast(v); - return true; - } - } - else { - if (TIXML_SSCANF(str, "%d", value) == 1) { - return true; - } - } - return false; -} - -bool XMLUtil::ToUnsigned(const char* str, unsigned* value) -{ - if (TIXML_SSCANF(str, IsPrefixHex(str) ? "%x" : "%u", value) == 1) { - return true; - } - return false; -} - -bool XMLUtil::ToBool( const char* str, bool* value ) -{ - int ival = 0; - if ( ToInt( str, &ival )) { - *value = (ival==0) ? false : true; - return true; - } - static const char* TRUE_VALS[] = { "true", "True", "TRUE", 0 }; - static const char* FALSE_VALS[] = { "false", "False", "FALSE", 0 }; - - for (int i = 0; TRUE_VALS[i]; ++i) { - if (StringEqual(str, TRUE_VALS[i])) { - *value = true; - return true; - } - } - for (int i = 0; FALSE_VALS[i]; ++i) { - if (StringEqual(str, FALSE_VALS[i])) { - *value = false; - return true; - } - } - return false; -} - - -bool XMLUtil::ToFloat( const char* str, float* value ) -{ - if ( TIXML_SSCANF( str, "%f", value ) == 1 ) { - return true; - } - return false; -} - - -bool XMLUtil::ToDouble( const char* str, double* value ) -{ - if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) { - return true; - } - return false; -} - - -bool XMLUtil::ToInt64(const char* str, int64_t* value) -{ - if (IsPrefixHex(str)) { - unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llx - if (TIXML_SSCANF(str, "%llx", &v) == 1) { - *value = static_cast(v); - return true; - } - } - else { - long long v = 0; // horrible syntax trick to make the compiler happy about %lld - if (TIXML_SSCANF(str, "%lld", &v) == 1) { - *value = static_cast(v); - return true; - } - } - return false; -} - - -bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) { - unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu - if(TIXML_SSCANF(str, IsPrefixHex(str) ? "%llx" : "%llu", &v) == 1) { - *value = static_cast(v); - return true; - } - return false; -} - - -char* XMLDocument::Identify( char* p, XMLNode** node, bool first ) -{ - TIXMLASSERT( node ); - TIXMLASSERT( p ); - char* const start = p; - int const startLine = _parseCurLineNum; - p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); - if( !*p ) { - *node = 0; - TIXMLASSERT( p ); - return p; - } - - // These strings define the matching patterns: - static const char* xmlHeader = { "( _commentPool ); - returnNode->_parseLineNum = _parseCurLineNum; - p += xmlHeaderLen; - } - else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { - returnNode = CreateUnlinkedNode( _commentPool ); - returnNode->_parseLineNum = _parseCurLineNum; - p += commentHeaderLen; - } - else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { - XMLText* text = CreateUnlinkedNode( _textPool ); - returnNode = text; - returnNode->_parseLineNum = _parseCurLineNum; - p += cdataHeaderLen; - text->SetCData( true ); - } - else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { - returnNode = CreateUnlinkedNode( _commentPool ); - returnNode->_parseLineNum = _parseCurLineNum; - p += dtdHeaderLen; - } - else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { - - // Preserve whitespace pedantically before closing tag, when it's immediately after opening tag - if (WhitespaceMode() == PEDANTIC_WHITESPACE && first && p != start && *(p + elementHeaderLen) == '/') { - returnNode = CreateUnlinkedNode(_textPool); - returnNode->_parseLineNum = startLine; - p = start; // Back it up, all the text counts. - _parseCurLineNum = startLine; - } - else { - returnNode = CreateUnlinkedNode(_elementPool); - returnNode->_parseLineNum = _parseCurLineNum; - p += elementHeaderLen; - } - } - else { - returnNode = CreateUnlinkedNode( _textPool ); - returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character - p = start; // Back it up, all the text counts. - _parseCurLineNum = startLine; - } - - TIXMLASSERT( returnNode ); - TIXMLASSERT( p ); - *node = returnNode; - return p; -} - - -bool XMLDocument::Accept( XMLVisitor* visitor ) const -{ - TIXMLASSERT( visitor ); - if ( visitor->VisitEnter( *this ) ) { - for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { - if ( !node->Accept( visitor ) ) { - break; - } - } - } - return visitor->VisitExit( *this ); -} - - -// --------- XMLNode ----------- // - -XMLNode::XMLNode( XMLDocument* doc ) : - _document( doc ), - _parent( 0 ), - _value(), - _parseLineNum( 0 ), - _firstChild( 0 ), _lastChild( 0 ), - _prev( 0 ), _next( 0 ), - _userData( 0 ), - _memPool( 0 ) -{ -} - - -XMLNode::~XMLNode() -{ - DeleteChildren(); - if ( _parent ) { - _parent->Unlink( this ); - } -} - -// ChildElementCount was originally suggested by msteiger on the sourceforge page for TinyXML and modified by KB1SPH for TinyXML-2. - -int XMLNode::ChildElementCount(const char *value) const { - int count = 0; - - const XMLElement *e = FirstChildElement(value); - - while (e) { - e = e->NextSiblingElement(value); - count++; - } - - return count; -} - -int XMLNode::ChildElementCount() const { - int count = 0; - - const XMLElement *e = FirstChildElement(); - - while (e) { - e = e->NextSiblingElement(); - count++; - } - - return count; -} - -const char* XMLNode::Value() const -{ - // Edge case: XMLDocuments don't have a Value. Return null. - if ( this->ToDocument() ) - return 0; - return _value.GetStr(); -} - -void XMLNode::SetValue( const char* str, bool staticMem ) -{ - if ( staticMem ) { - _value.SetInternedStr( str ); - } - else { - _value.SetStr( str ); - } -} - -XMLNode* XMLNode::DeepClone(XMLDocument* target) const -{ - XMLNode* clone = this->ShallowClone(target); - if (!clone) return 0; - - for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) { - XMLNode* childClone = child->DeepClone(target); - TIXMLASSERT(childClone); - clone->InsertEndChild(childClone); - } - return clone; -} - -void XMLNode::DeleteChildren() -{ - while( _firstChild ) { - TIXMLASSERT( _lastChild ); - DeleteChild( _firstChild ); - } - _firstChild = _lastChild = 0; -} - - -void XMLNode::Unlink( XMLNode* child ) -{ - TIXMLASSERT( child ); - TIXMLASSERT( child->_document == _document ); - TIXMLASSERT( child->_parent == this ); - if ( child == _firstChild ) { - _firstChild = _firstChild->_next; - } - if ( child == _lastChild ) { - _lastChild = _lastChild->_prev; - } - - if ( child->_prev ) { - child->_prev->_next = child->_next; - } - if ( child->_next ) { - child->_next->_prev = child->_prev; - } - child->_next = 0; - child->_prev = 0; - child->_parent = 0; -} - - -void XMLNode::DeleteChild( XMLNode* node ) -{ - TIXMLASSERT( node ); - TIXMLASSERT( node->_document == _document ); - TIXMLASSERT( node->_parent == this ); - Unlink( node ); - TIXMLASSERT(node->_prev == 0); - TIXMLASSERT(node->_next == 0); - TIXMLASSERT(node->_parent == 0); - DeleteNode( node ); -} - - -XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) -{ - TIXMLASSERT( addThis ); - if ( addThis->_document != _document ) { - TIXMLASSERT( false ); - return 0; - } - InsertChildPreamble( addThis ); - - if ( _lastChild ) { - TIXMLASSERT( _firstChild ); - TIXMLASSERT( _lastChild->_next == 0 ); - _lastChild->_next = addThis; - addThis->_prev = _lastChild; - _lastChild = addThis; - - addThis->_next = 0; - } - else { - TIXMLASSERT( _firstChild == 0 ); - _firstChild = _lastChild = addThis; - - addThis->_prev = 0; - addThis->_next = 0; - } - addThis->_parent = this; - return addThis; -} - - -XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) -{ - TIXMLASSERT( addThis ); - if ( addThis->_document != _document ) { - TIXMLASSERT( false ); - return 0; - } - InsertChildPreamble( addThis ); - - if ( _firstChild ) { - TIXMLASSERT( _lastChild ); - TIXMLASSERT( _firstChild->_prev == 0 ); - - _firstChild->_prev = addThis; - addThis->_next = _firstChild; - _firstChild = addThis; - - addThis->_prev = 0; - } - else { - TIXMLASSERT( _lastChild == 0 ); - _firstChild = _lastChild = addThis; - - addThis->_prev = 0; - addThis->_next = 0; - } - addThis->_parent = this; - return addThis; -} - - -XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) -{ - TIXMLASSERT( addThis ); - if ( addThis->_document != _document ) { - TIXMLASSERT( false ); - return 0; - } - - TIXMLASSERT( afterThis ); - - if ( afterThis->_parent != this ) { - TIXMLASSERT( false ); - return 0; - } - if ( afterThis == addThis ) { - // Current state: BeforeThis -> AddThis -> OneAfterAddThis - // Now AddThis must disappear from it's location and then - // reappear between BeforeThis and OneAfterAddThis. - // So just leave it where it is. - return addThis; - } - - if ( afterThis->_next == 0 ) { - // The last node or the only node. - return InsertEndChild( addThis ); - } - InsertChildPreamble( addThis ); - addThis->_prev = afterThis; - addThis->_next = afterThis->_next; - afterThis->_next->_prev = addThis; - afterThis->_next = addThis; - addThis->_parent = this; - return addThis; -} - - - - -const XMLElement* XMLNode::FirstChildElement( const char* name ) const -{ - for( const XMLNode* node = _firstChild; node; node = node->_next ) { - const XMLElement* element = node->ToElementWithName( name ); - if ( element ) { - return element; - } - } - return 0; -} - - -const XMLElement* XMLNode::LastChildElement( const char* name ) const -{ - for( const XMLNode* node = _lastChild; node; node = node->_prev ) { - const XMLElement* element = node->ToElementWithName( name ); - if ( element ) { - return element; - } - } - return 0; -} - - -const XMLElement* XMLNode::NextSiblingElement( const char* name ) const -{ - for( const XMLNode* node = _next; node; node = node->_next ) { - const XMLElement* element = node->ToElementWithName( name ); - if ( element ) { - return element; - } - } - return 0; -} - - -const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const -{ - for( const XMLNode* node = _prev; node; node = node->_prev ) { - const XMLElement* element = node->ToElementWithName( name ); - if ( element ) { - return element; - } - } - return 0; -} - - -char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) -{ - // This is a recursive method, but thinking about it "at the current level" - // it is a pretty simple flat list: - // - // - // - // With a special case: - // - // - // - // - // Where the closing element (/foo) *must* be the next thing after the opening - // element, and the names must match. BUT the tricky bit is that the closing - // element will be read by the child. - // - // 'endTag' is the end tag for this node, it is returned by a call to a child. - // 'parentEnd' is the end tag for the parent, which is filled in and returned. - - XMLDocument::DepthTracker tracker(_document); - if (_document->Error()) - return 0; - - bool first = true; - while( p && *p ) { - XMLNode* node = 0; - - p = _document->Identify( p, &node, first ); - TIXMLASSERT( p ); - if ( node == 0 ) { - break; - } - first = false; - - const int initialLineNum = node->_parseLineNum; - - StrPair endTag; - p = node->ParseDeep( p, &endTag, curLineNumPtr ); - if ( !p ) { - _document->DeleteNode( node ); - if ( !_document->Error() ) { - _document->SetError( XML_ERROR_PARSING, initialLineNum, 0); - } - break; - } - - const XMLDeclaration* const decl = node->ToDeclaration(); - if ( decl ) { - // Declarations are only allowed at document level - // - // Multiple declarations are allowed but all declarations - // must occur before anything else. - // - // Optimized due to a security test case. If the first node is - // a declaration, and the last node is a declaration, then only - // declarations have so far been added. - bool wellLocated = false; - - if (ToDocument()) { - if (FirstChild()) { - wellLocated = - FirstChild() && - FirstChild()->ToDeclaration() && - LastChild() && - LastChild()->ToDeclaration(); - } - else { - wellLocated = true; - } - } - if ( !wellLocated ) { - _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value()); - _document->DeleteNode( node ); - break; - } - } - - XMLElement* ele = node->ToElement(); - if ( ele ) { - // We read the end tag. Return it to the parent. - if ( ele->ClosingType() == XMLElement::CLOSING ) { - if ( parentEndTag ) { - ele->_value.TransferTo( parentEndTag ); - } - node->_memPool->SetTracked(); // created and then immediately deleted. - DeleteNode( node ); - return p; - } - - // Handle an end tag returned to this level. - // And handle a bunch of annoying errors. - bool mismatch = false; - if ( endTag.Empty() ) { - if ( ele->ClosingType() == XMLElement::OPEN ) { - mismatch = true; - } - } - else { - if ( ele->ClosingType() != XMLElement::OPEN ) { - mismatch = true; - } - else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) { - mismatch = true; - } - } - if ( mismatch ) { - _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name()); - _document->DeleteNode( node ); - break; - } - } - InsertEndChild( node ); - } - return 0; -} - -/*static*/ void XMLNode::DeleteNode( XMLNode* node ) -{ - if ( node == 0 ) { - return; - } - TIXMLASSERT(node->_document); - if (!node->ToDocument()) { - node->_document->MarkInUse(node); - } - - MemPool* pool = node->_memPool; - node->~XMLNode(); - pool->Free( node ); -} - -void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const -{ - TIXMLASSERT( insertThis ); - TIXMLASSERT( insertThis->_document == _document ); - - if (insertThis->_parent) { - insertThis->_parent->Unlink( insertThis ); - } - else { - insertThis->_document->MarkInUse(insertThis); - insertThis->_memPool->SetTracked(); - } -} - -const XMLElement* XMLNode::ToElementWithName( const char* name ) const -{ - const XMLElement* element = this->ToElement(); - if ( element == 0 ) { - return 0; - } - if ( name == 0 ) { - return element; - } - if ( XMLUtil::StringEqual( element->Name(), name ) ) { - return element; - } - return 0; -} - -// --------- XMLText ---------- // -char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) -{ - if ( this->CData() ) { - p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); - if ( !p ) { - _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 ); - } - return p; - } - else { - int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; - if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { - flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING; - } - - p = _value.ParseText( p, "<", flags, curLineNumPtr ); - if ( p && *p ) { - return p-1; - } - if ( !p ) { - _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 ); - } - } - return 0; -} - - -XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const -{ - if ( !doc ) { - doc = _document; - } - XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern? - text->SetCData( this->CData() ); - return text; -} - - -bool XMLText::ShallowEqual( const XMLNode* compare ) const -{ - TIXMLASSERT( compare ); - const XMLText* text = compare->ToText(); - return ( text && XMLUtil::StringEqual( text->Value(), Value() ) ); -} - - -bool XMLText::Accept( XMLVisitor* visitor ) const -{ - TIXMLASSERT( visitor ); - return visitor->Visit( *this ); -} - - -// --------- XMLComment ---------- // - -XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc ) -{ -} - - -XMLComment::~XMLComment() -{ -} - - -char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) -{ - // Comment parses as text. - p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr ); - if ( p == 0 ) { - _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 ); - } - return p; -} - - -XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const -{ - if ( !doc ) { - doc = _document; - } - XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern? - return comment; -} - - -bool XMLComment::ShallowEqual( const XMLNode* compare ) const -{ - TIXMLASSERT( compare ); - const XMLComment* comment = compare->ToComment(); - return ( comment && XMLUtil::StringEqual( comment->Value(), Value() )); -} - - -bool XMLComment::Accept( XMLVisitor* visitor ) const -{ - TIXMLASSERT( visitor ); - return visitor->Visit( *this ); -} - - -// --------- XMLDeclaration ---------- // - -XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc ) -{ -} - - -XMLDeclaration::~XMLDeclaration() -{ - //printf( "~XMLDeclaration\n" ); -} - - -char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) -{ - // Declaration parses as text. - p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); - if ( p == 0 ) { - _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 ); - } - return p; -} - - -XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const -{ - if ( !doc ) { - doc = _document; - } - XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern? - return dec; -} - - -bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const -{ - TIXMLASSERT( compare ); - const XMLDeclaration* declaration = compare->ToDeclaration(); - return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() )); -} - - - -bool XMLDeclaration::Accept( XMLVisitor* visitor ) const -{ - TIXMLASSERT( visitor ); - return visitor->Visit( *this ); -} - -// --------- XMLUnknown ---------- // - -XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc ) -{ -} - - -XMLUnknown::~XMLUnknown() -{ -} - - -char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) -{ - // Unknown parses as text. - p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); - if ( !p ) { - _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 ); - } - return p; -} - - -XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const -{ - if ( !doc ) { - doc = _document; - } - XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern? - return text; -} - - -bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const -{ - TIXMLASSERT( compare ); - const XMLUnknown* unknown = compare->ToUnknown(); - return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() )); -} - - -bool XMLUnknown::Accept( XMLVisitor* visitor ) const -{ - TIXMLASSERT( visitor ); - return visitor->Visit( *this ); -} - -// --------- XMLAttribute ---------- // - -const char* XMLAttribute::Name() const -{ - return _name.GetStr(); -} - -const char* XMLAttribute::Value() const -{ - return _value.GetStr(); -} - -char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr ) -{ - // Parse using the name rules: bug fix, was using ParseText before - p = _name.ParseName( p ); - if ( !p || !*p ) { - return 0; - } - - // Skip white space before = - p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); - if ( *p != '=' ) { - return 0; - } - - ++p; // move up to opening quote - p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); - if ( *p != '\"' && *p != '\'' ) { - return 0; - } - - const char endTag[2] = { *p, 0 }; - ++p; // move past opening quote - - p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr ); - return p; -} - - -void XMLAttribute::SetName( const char* n ) -{ - _name.SetStr( n ); -} - - -XMLError XMLAttribute::QueryIntValue( int* value ) const -{ - if ( XMLUtil::ToInt( Value(), value )) { - return XML_SUCCESS; - } - return XML_WRONG_ATTRIBUTE_TYPE; -} - - -XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const -{ - if ( XMLUtil::ToUnsigned( Value(), value )) { - return XML_SUCCESS; - } - return XML_WRONG_ATTRIBUTE_TYPE; -} - - -XMLError XMLAttribute::QueryInt64Value(int64_t* value) const -{ - if (XMLUtil::ToInt64(Value(), value)) { - return XML_SUCCESS; - } - return XML_WRONG_ATTRIBUTE_TYPE; -} - - -XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const -{ - if(XMLUtil::ToUnsigned64(Value(), value)) { - return XML_SUCCESS; - } - return XML_WRONG_ATTRIBUTE_TYPE; -} - - -XMLError XMLAttribute::QueryBoolValue( bool* value ) const -{ - if ( XMLUtil::ToBool( Value(), value )) { - return XML_SUCCESS; - } - return XML_WRONG_ATTRIBUTE_TYPE; -} - - -XMLError XMLAttribute::QueryFloatValue( float* value ) const -{ - if ( XMLUtil::ToFloat( Value(), value )) { - return XML_SUCCESS; - } - return XML_WRONG_ATTRIBUTE_TYPE; -} - - -XMLError XMLAttribute::QueryDoubleValue( double* value ) const -{ - if ( XMLUtil::ToDouble( Value(), value )) { - return XML_SUCCESS; - } - return XML_WRONG_ATTRIBUTE_TYPE; -} - - -void XMLAttribute::SetAttribute( const char* v ) -{ - _value.SetStr( v ); -} - - -void XMLAttribute::SetAttribute( int v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - _value.SetStr( buf ); -} - - -void XMLAttribute::SetAttribute( unsigned v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - _value.SetStr( buf ); -} - - -void XMLAttribute::SetAttribute(int64_t v) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr(v, buf, BUF_SIZE); - _value.SetStr(buf); -} - -void XMLAttribute::SetAttribute(uint64_t v) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr(v, buf, BUF_SIZE); - _value.SetStr(buf); -} - - -void XMLAttribute::SetAttribute( bool v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - _value.SetStr( buf ); -} - -void XMLAttribute::SetAttribute( double v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - _value.SetStr( buf ); -} - -void XMLAttribute::SetAttribute( float v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - _value.SetStr( buf ); -} - - -// --------- XMLElement ---------- // -XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), - _closingType( OPEN ), - _rootAttribute( 0 ) -{ -} - - -XMLElement::~XMLElement() -{ - while( _rootAttribute ) { - XMLAttribute* next = _rootAttribute->_next; - DeleteAttribute( _rootAttribute ); - _rootAttribute = next; - } -} - - -const XMLAttribute* XMLElement::FindAttribute( const char* name ) const -{ - for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) { - if ( XMLUtil::StringEqual( a->Name(), name ) ) { - return a; - } - } - return 0; -} - - -const char* XMLElement::Attribute( const char* name, const char* value ) const -{ - const XMLAttribute* a = FindAttribute( name ); - if ( !a ) { - return 0; - } - if ( !value || XMLUtil::StringEqual( a->Value(), value )) { - return a->Value(); - } - return 0; -} - -int XMLElement::IntAttribute(const char* name, int defaultValue) const -{ - int i = defaultValue; - QueryIntAttribute(name, &i); - return i; -} - -unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const -{ - unsigned i = defaultValue; - QueryUnsignedAttribute(name, &i); - return i; -} - -int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const -{ - int64_t i = defaultValue; - QueryInt64Attribute(name, &i); - return i; -} - -uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const -{ - uint64_t i = defaultValue; - QueryUnsigned64Attribute(name, &i); - return i; -} - -bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const -{ - bool b = defaultValue; - QueryBoolAttribute(name, &b); - return b; -} - -double XMLElement::DoubleAttribute(const char* name, double defaultValue) const -{ - double d = defaultValue; - QueryDoubleAttribute(name, &d); - return d; -} - -float XMLElement::FloatAttribute(const char* name, float defaultValue) const -{ - float f = defaultValue; - QueryFloatAttribute(name, &f); - return f; -} - -const char* XMLElement::GetText() const -{ - /* skip comment node */ - const XMLNode* node = FirstChild(); - while (node) { - if (node->ToComment()) { - node = node->NextSibling(); - continue; - } - break; - } - - if ( node && node->ToText() ) { - return node->Value(); - } - return 0; -} - - -void XMLElement::SetText( const char* inText ) -{ - if ( FirstChild() && FirstChild()->ToText() ) - FirstChild()->SetValue( inText ); - else { - XMLText* theText = GetDocument()->NewText( inText ); - InsertFirstChild( theText ); - } -} - - -void XMLElement::SetText( int v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - SetText( buf ); -} - - -void XMLElement::SetText( unsigned v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - SetText( buf ); -} - - -void XMLElement::SetText(int64_t v) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr(v, buf, BUF_SIZE); - SetText(buf); -} - -void XMLElement::SetText(uint64_t v) { - char buf[BUF_SIZE]; - XMLUtil::ToStr(v, buf, BUF_SIZE); - SetText(buf); -} - - -void XMLElement::SetText( bool v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - SetText( buf ); -} - - -void XMLElement::SetText( float v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - SetText( buf ); -} - - -void XMLElement::SetText( double v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - SetText( buf ); -} - - -XMLError XMLElement::QueryIntText( int* ival ) const -{ - if ( FirstChild() && FirstChild()->ToText() ) { - const char* t = FirstChild()->Value(); - if ( XMLUtil::ToInt( t, ival ) ) { - return XML_SUCCESS; - } - return XML_CAN_NOT_CONVERT_TEXT; - } - return XML_NO_TEXT_NODE; -} - - -XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const -{ - if ( FirstChild() && FirstChild()->ToText() ) { - const char* t = FirstChild()->Value(); - if ( XMLUtil::ToUnsigned( t, uval ) ) { - return XML_SUCCESS; - } - return XML_CAN_NOT_CONVERT_TEXT; - } - return XML_NO_TEXT_NODE; -} - - -XMLError XMLElement::QueryInt64Text(int64_t* ival) const -{ - if (FirstChild() && FirstChild()->ToText()) { - const char* t = FirstChild()->Value(); - if (XMLUtil::ToInt64(t, ival)) { - return XML_SUCCESS; - } - return XML_CAN_NOT_CONVERT_TEXT; - } - return XML_NO_TEXT_NODE; -} - - -XMLError XMLElement::QueryUnsigned64Text(uint64_t* uval) const -{ - if(FirstChild() && FirstChild()->ToText()) { - const char* t = FirstChild()->Value(); - if(XMLUtil::ToUnsigned64(t, uval)) { - return XML_SUCCESS; - } - return XML_CAN_NOT_CONVERT_TEXT; - } - return XML_NO_TEXT_NODE; -} - - -XMLError XMLElement::QueryBoolText( bool* bval ) const -{ - if ( FirstChild() && FirstChild()->ToText() ) { - const char* t = FirstChild()->Value(); - if ( XMLUtil::ToBool( t, bval ) ) { - return XML_SUCCESS; - } - return XML_CAN_NOT_CONVERT_TEXT; - } - return XML_NO_TEXT_NODE; -} - - -XMLError XMLElement::QueryDoubleText( double* dval ) const -{ - if ( FirstChild() && FirstChild()->ToText() ) { - const char* t = FirstChild()->Value(); - if ( XMLUtil::ToDouble( t, dval ) ) { - return XML_SUCCESS; - } - return XML_CAN_NOT_CONVERT_TEXT; - } - return XML_NO_TEXT_NODE; -} - - -XMLError XMLElement::QueryFloatText( float* fval ) const -{ - if ( FirstChild() && FirstChild()->ToText() ) { - const char* t = FirstChild()->Value(); - if ( XMLUtil::ToFloat( t, fval ) ) { - return XML_SUCCESS; - } - return XML_CAN_NOT_CONVERT_TEXT; - } - return XML_NO_TEXT_NODE; -} - -int XMLElement::IntText(int defaultValue) const -{ - int i = defaultValue; - QueryIntText(&i); - return i; -} - -unsigned XMLElement::UnsignedText(unsigned defaultValue) const -{ - unsigned i = defaultValue; - QueryUnsignedText(&i); - return i; -} - -int64_t XMLElement::Int64Text(int64_t defaultValue) const -{ - int64_t i = defaultValue; - QueryInt64Text(&i); - return i; -} - -uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const -{ - uint64_t i = defaultValue; - QueryUnsigned64Text(&i); - return i; -} - -bool XMLElement::BoolText(bool defaultValue) const -{ - bool b = defaultValue; - QueryBoolText(&b); - return b; -} - -double XMLElement::DoubleText(double defaultValue) const -{ - double d = defaultValue; - QueryDoubleText(&d); - return d; -} - -float XMLElement::FloatText(float defaultValue) const -{ - float f = defaultValue; - QueryFloatText(&f); - return f; -} - - -XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) -{ - XMLAttribute* last = 0; - XMLAttribute* attrib = 0; - for( attrib = _rootAttribute; - attrib; - last = attrib, attrib = attrib->_next ) { - if ( XMLUtil::StringEqual( attrib->Name(), name ) ) { - break; - } - } - if ( !attrib ) { - attrib = CreateAttribute(); - TIXMLASSERT( attrib ); - if ( last ) { - TIXMLASSERT( last->_next == 0 ); - last->_next = attrib; - } - else { - TIXMLASSERT( _rootAttribute == 0 ); - _rootAttribute = attrib; - } - attrib->SetName( name ); - } - return attrib; -} - - -void XMLElement::DeleteAttribute( const char* name ) -{ - XMLAttribute* prev = 0; - for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) { - if ( XMLUtil::StringEqual( name, a->Name() ) ) { - if ( prev ) { - prev->_next = a->_next; - } - else { - _rootAttribute = a->_next; - } - DeleteAttribute( a ); - break; - } - prev = a; - } -} - - -char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr ) -{ - XMLAttribute* prevAttribute = 0; - - // Read the attributes. - while( p ) { - p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); - if ( !(*p) ) { - _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() ); - return 0; - } - - // attribute. - if (XMLUtil::IsNameStartChar( static_cast(*p) ) ) { - XMLAttribute* attrib = CreateAttribute(); - TIXMLASSERT( attrib ); - attrib->_parseLineNum = _document->_parseCurLineNum; - - const int attrLineNum = attrib->_parseLineNum; - - p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr ); - if ( !p || Attribute( attrib->Name() ) ) { - DeleteAttribute( attrib ); - _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() ); - return 0; - } - // There is a minor bug here: if the attribute in the source xml - // document is duplicated, it will not be detected and the - // attribute will be doubly added. However, tracking the 'prevAttribute' - // avoids re-scanning the attribute list. Preferring performance for - // now, may reconsider in the future. - if ( prevAttribute ) { - TIXMLASSERT( prevAttribute->_next == 0 ); - prevAttribute->_next = attrib; - } - else { - TIXMLASSERT( _rootAttribute == 0 ); - _rootAttribute = attrib; - } - prevAttribute = attrib; - } - // end of the tag - else if ( *p == '>' ) { - ++p; - break; - } - // end of the tag - else if ( *p == '/' && *(p+1) == '>' ) { - _closingType = CLOSED; - return p+2; // done; sealed element. - } - else { - _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 ); - return 0; - } - } - return p; -} - -void XMLElement::DeleteAttribute( XMLAttribute* attribute ) -{ - if ( attribute == 0 ) { - return; - } - MemPool* pool = attribute->_memPool; - attribute->~XMLAttribute(); - pool->Free( attribute ); -} - -XMLAttribute* XMLElement::CreateAttribute() -{ - TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); - XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); - TIXMLASSERT( attrib ); - attrib->_memPool = &_document->_attributePool; - attrib->_memPool->SetTracked(); - return attrib; -} - - -XMLElement* XMLElement::InsertNewChildElement(const char* name) -{ - XMLElement* node = _document->NewElement(name); - return InsertEndChild(node) ? node : 0; -} - -XMLComment* XMLElement::InsertNewComment(const char* comment) -{ - XMLComment* node = _document->NewComment(comment); - return InsertEndChild(node) ? node : 0; -} - -XMLText* XMLElement::InsertNewText(const char* text) -{ - XMLText* node = _document->NewText(text); - return InsertEndChild(node) ? node : 0; -} - -XMLDeclaration* XMLElement::InsertNewDeclaration(const char* text) -{ - XMLDeclaration* node = _document->NewDeclaration(text); - return InsertEndChild(node) ? node : 0; -} - -XMLUnknown* XMLElement::InsertNewUnknown(const char* text) -{ - XMLUnknown* node = _document->NewUnknown(text); - return InsertEndChild(node) ? node : 0; -} - - - -// -// -// foobar -// -char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) -{ - // Read the element name. - p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); - - // The closing element is the form. It is - // parsed just like a regular element then deleted from - // the DOM. - if ( *p == '/' ) { - _closingType = CLOSING; - ++p; - } - - p = _value.ParseName( p ); - if ( _value.Empty() ) { - return 0; - } - - p = ParseAttributes( p, curLineNumPtr ); - if ( !p || !*p || _closingType != OPEN ) { - return p; - } - - p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr ); - return p; -} - - - -XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const -{ - if ( !doc ) { - doc = _document; - } - XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern? - for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) { - element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern? - } - return element; -} - - -bool XMLElement::ShallowEqual( const XMLNode* compare ) const -{ - TIXMLASSERT( compare ); - const XMLElement* other = compare->ToElement(); - if ( other && XMLUtil::StringEqual( other->Name(), Name() )) { - - const XMLAttribute* a=FirstAttribute(); - const XMLAttribute* b=other->FirstAttribute(); - - while ( a && b ) { - if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) { - return false; - } - a = a->Next(); - b = b->Next(); - } - if ( a || b ) { - // different count - return false; - } - return true; - } - return false; -} - - -bool XMLElement::Accept( XMLVisitor* visitor ) const -{ - TIXMLASSERT( visitor ); - if ( visitor->VisitEnter( *this, _rootAttribute ) ) { - for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { - if ( !node->Accept( visitor ) ) { - break; - } - } - } - return visitor->VisitExit( *this ); -} - - -// --------- XMLDocument ----------- // - -// Warning: List must match 'enum XMLError' -const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = { - "XML_SUCCESS", - "XML_NO_ATTRIBUTE", - "XML_WRONG_ATTRIBUTE_TYPE", - "XML_ERROR_FILE_NOT_FOUND", - "XML_ERROR_FILE_COULD_NOT_BE_OPENED", - "XML_ERROR_FILE_READ_ERROR", - "XML_ERROR_PARSING_ELEMENT", - "XML_ERROR_PARSING_ATTRIBUTE", - "XML_ERROR_PARSING_TEXT", - "XML_ERROR_PARSING_CDATA", - "XML_ERROR_PARSING_COMMENT", - "XML_ERROR_PARSING_DECLARATION", - "XML_ERROR_PARSING_UNKNOWN", - "XML_ERROR_EMPTY_DOCUMENT", - "XML_ERROR_MISMATCHED_ELEMENT", - "XML_ERROR_PARSING", - "XML_CAN_NOT_CONVERT_TEXT", - "XML_NO_TEXT_NODE", - "XML_ELEMENT_DEPTH_EXCEEDED" -}; - - -XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) : - XMLNode( 0 ), - _writeBOM( false ), - _processEntities( processEntities ), - _errorID(XML_SUCCESS), - _whitespaceMode( whitespaceMode ), - _errorStr(), - _errorLineNum( 0 ), - _charBuffer( 0 ), - _parseCurLineNum( 0 ), - _parsingDepth(0), - _unlinked(), - _elementPool(), - _attributePool(), - _textPool(), - _commentPool() -{ - // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+) - _document = this; -} - - -XMLDocument::~XMLDocument() -{ - Clear(); -} - - -void XMLDocument::MarkInUse(const XMLNode* const node) -{ - TIXMLASSERT(node); - TIXMLASSERT(node->_parent == 0); - - for (size_t i = 0; i < _unlinked.Size(); ++i) { - if (node == _unlinked[i]) { - _unlinked.SwapRemove(i); - break; - } - } -} - -void XMLDocument::Clear() -{ - DeleteChildren(); - while( _unlinked.Size()) { - DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete. - } - -#ifdef TINYXML2_DEBUG - const bool hadError = Error(); -#endif - ClearError(); - - delete [] _charBuffer; - _charBuffer = 0; - _parsingDepth = 0; - -#if 0 - _textPool.Trace( "text" ); - _elementPool.Trace( "element" ); - _commentPool.Trace( "comment" ); - _attributePool.Trace( "attribute" ); -#endif - -#ifdef TINYXML2_DEBUG - if ( !hadError ) { - TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() ); - TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() ); - TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() ); - TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() ); - } -#endif -} - - -void XMLDocument::DeepCopy(XMLDocument* target) const -{ - TIXMLASSERT(target); - if (target == this) { - return; // technically success - a no-op. - } - - target->Clear(); - for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) { - target->InsertEndChild(node->DeepClone(target)); - } -} - -XMLElement* XMLDocument::NewElement( const char* name ) -{ - XMLElement* ele = CreateUnlinkedNode( _elementPool ); - ele->SetName( name ); - return ele; -} - - -XMLComment* XMLDocument::NewComment( const char* str ) -{ - XMLComment* comment = CreateUnlinkedNode( _commentPool ); - comment->SetValue( str ); - return comment; -} - - -XMLText* XMLDocument::NewText( const char* str ) -{ - XMLText* text = CreateUnlinkedNode( _textPool ); - text->SetValue( str ); - return text; -} - - -XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) -{ - XMLDeclaration* dec = CreateUnlinkedNode( _commentPool ); - dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); - return dec; -} - - -XMLUnknown* XMLDocument::NewUnknown( const char* str ) -{ - XMLUnknown* unk = CreateUnlinkedNode( _commentPool ); - unk->SetValue( str ); - return unk; -} - -static FILE* callfopen( const char* filepath, const char* mode ) -{ - TIXMLASSERT( filepath ); - TIXMLASSERT( mode ); -#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) - FILE* fp = 0; - const errno_t err = fopen_s( &fp, filepath, mode ); - if ( err ) { - return 0; - } -#else - FILE* fp = fopen( filepath, mode ); -#endif - return fp; -} - -void XMLDocument::DeleteNode( XMLNode* node ) { - TIXMLASSERT( node ); - TIXMLASSERT(node->_document == this ); - if (node->_parent) { - node->_parent->DeleteChild( node ); - } - else { - // Isn't in the tree. - // Use the parent delete. - // Also, we need to mark it tracked: we 'know' - // it was never used. - node->_memPool->SetTracked(); - // Call the static XMLNode version: - XMLNode::DeleteNode(node); - } -} - - -XMLError XMLDocument::LoadFile( const char* filename ) -{ - if ( !filename ) { - TIXMLASSERT( false ); - SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=" ); - return _errorID; - } - - Clear(); - FILE* fp = callfopen( filename, "rb" ); - if ( !fp ) { - SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ); - return _errorID; - } - LoadFile( fp ); - fclose( fp ); - return _errorID; -} - -XMLError XMLDocument::LoadFile( FILE* fp ) -{ - Clear(); - - TIXML_FSEEK( fp, 0, SEEK_SET ); - if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) { - SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); - return _errorID; - } - - TIXML_FSEEK( fp, 0, SEEK_END ); - - unsigned long long filelength; - { - const long long fileLengthSigned = TIXML_FTELL( fp ); - TIXML_FSEEK( fp, 0, SEEK_SET ); - if ( fileLengthSigned == -1L ) { - SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); - return _errorID; - } - TIXMLASSERT( fileLengthSigned >= 0 ); - filelength = static_cast(fileLengthSigned); - } - - const size_t maxSizeT = static_cast(-1); - // We'll do the comparison as an unsigned long long, because that's guaranteed to be at - // least 8 bytes, even on a 32-bit platform. - if ( filelength >= static_cast(maxSizeT) ) { - // Cannot handle files which won't fit in buffer together with null terminator - SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); - return _errorID; - } - - if ( filelength == 0 ) { - SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); - return _errorID; - } - - const size_t size = static_cast(filelength); - TIXMLASSERT( _charBuffer == 0 ); - _charBuffer = new char[size+1]; - const size_t read = fread( _charBuffer, 1, size, fp ); - if ( read != size ) { - SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); - return _errorID; - } - - _charBuffer[size] = 0; - - Parse(); - return _errorID; -} - - -XMLError XMLDocument::SaveFile( const char* filename, bool compact ) -{ - if ( !filename ) { - TIXMLASSERT( false ); - SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=" ); - return _errorID; - } - - FILE* fp = callfopen( filename, "w" ); - if ( !fp ) { - SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ); - return _errorID; - } - SaveFile(fp, compact); - fclose( fp ); - return _errorID; -} - - -XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) -{ - // Clear any error from the last save, otherwise it will get reported - // for *this* call. - ClearError(); - XMLPrinter stream( fp, compact ); - Print( &stream ); - return _errorID; -} - - -XMLError XMLDocument::Parse( const char* xml, size_t nBytes ) -{ - Clear(); - - if ( nBytes == 0 || !xml || !*xml ) { - SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); - return _errorID; - } - if ( nBytes == static_cast(-1) ) { - nBytes = strlen( xml ); - } - TIXMLASSERT( _charBuffer == 0 ); - _charBuffer = new char[ nBytes+1 ]; - memcpy( _charBuffer, xml, nBytes ); - _charBuffer[nBytes] = 0; - - Parse(); - if ( Error() ) { - // clean up now essentially dangling memory. - // and the parse fail can put objects in the - // pools that are dead and inaccessible. - DeleteChildren(); - _elementPool.Clear(); - _attributePool.Clear(); - _textPool.Clear(); - _commentPool.Clear(); - } - return _errorID; -} - - -void XMLDocument::Print( XMLPrinter* streamer ) const -{ - if ( streamer ) { - Accept( streamer ); - } - else { - XMLPrinter stdoutStreamer( stdout ); - Accept( &stdoutStreamer ); - } -} - - -void XMLDocument::ClearError() { - _errorID = XML_SUCCESS; - _errorLineNum = 0; - _errorStr.Reset(); -} - - -void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... ) -{ - TIXMLASSERT(error >= 0 && error < XML_ERROR_COUNT); - _errorID = error; - _errorLineNum = lineNum; - _errorStr.Reset(); - - const size_t BUFFER_SIZE = 1000; - char* buffer = new char[BUFFER_SIZE]; - - TIXMLASSERT(sizeof(error) <= sizeof(int)); - TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", - ErrorIDToName(error), static_cast(error), static_cast(error), lineNum); - - if (format) { - size_t len = strlen(buffer); - TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": "); - len = strlen(buffer); - - va_list va; - va_start(va, format); - TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va); - va_end(va); - } - _errorStr.SetStr(buffer); - delete[] buffer; -} - - -/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID) -{ - TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT ); - const char* errorName = _errorNames[errorID]; - TIXMLASSERT( errorName && errorName[0] ); - return errorName; -} - -const char* XMLDocument::ErrorStr() const -{ - return _errorStr.Empty() ? "" : _errorStr.GetStr(); -} - - -void XMLDocument::PrintError() const -{ - printf("%s\n", ErrorStr()); -} - -const char* XMLDocument::ErrorName() const -{ - return ErrorIDToName(_errorID); -} - -void XMLDocument::Parse() -{ - TIXMLASSERT( NoChildren() ); // Clear() must have been called previously - TIXMLASSERT( _charBuffer ); - _parseCurLineNum = 1; - _parseLineNum = 1; - char* p = _charBuffer; - p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); - p = const_cast( XMLUtil::ReadBOM( p, &_writeBOM ) ); - if ( !*p ) { - SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); - return; - } - ParseDeep(p, 0, &_parseCurLineNum ); -} - -void XMLDocument::PushDepth() -{ - _parsingDepth++; - if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) { - SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." ); - } -} - -void XMLDocument::PopDepth() -{ - TIXMLASSERT(_parsingDepth > 0); - --_parsingDepth; -} - -XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : - _elementJustOpened( false ), - _stack(), - _firstElement( true ), - _fp( file ), - _depth( depth ), - _textDepth( -1 ), - _processEntities( true ), - _compactMode( compact ), - _buffer() -{ - for( int i=0; i(entityValue); - TIXMLASSERT( flagIndex < ENTITY_RANGE ); - _entityFlag[flagIndex] = true; - } - _restrictedEntityFlag[static_cast('&')] = true; - _restrictedEntityFlag[static_cast('<')] = true; - _restrictedEntityFlag[static_cast('>')] = true; // not required, but consistency is nice - _buffer.Push( 0 ); -} - - -void XMLPrinter::Print( const char* format, ... ) -{ - va_list va; - va_start( va, format ); - - if ( _fp ) { - vfprintf( _fp, format, va ); - } - else { - const int len = TIXML_VSCPRINTF( format, va ); - // Close out and re-start the va-args - va_end( va ); - TIXMLASSERT( len >= 0 ); - va_start( va, format ); - TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 ); - char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator. - TIXML_VSNPRINTF( p, len+1, format, va ); - } - va_end( va ); -} - - -void XMLPrinter::Write( const char* data, size_t size ) -{ - if ( _fp ) { - fwrite ( data , sizeof(char), size, _fp); - } - else { - char* p = _buffer.PushArr( static_cast(size) ) - 1; // back up over the null terminator. - memcpy( p, data, size ); - p[size] = 0; - } -} - - -void XMLPrinter::Putc( char ch ) -{ - if ( _fp ) { - fputc ( ch, _fp); - } - else { - char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator. - p[0] = ch; - p[1] = 0; - } -} - - -void XMLPrinter::PrintSpace( int depth ) -{ - for( int i=0; i 0 && *q < ENTITY_RANGE ) { - // Check for entities. If one is found, flush - // the stream up until the entity, write the - // entity, and keep looking. - if ( flag[static_cast(*q)] ) { - while ( p < q ) { - const size_t delta = q - p; - const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast(delta); - Write( p, toPrint ); - p += toPrint; - } - bool entityPatternPrinted = false; - for( int i=0; i(delta); - Write( p, toPrint ); - } - } - else { - Write( p ); - } -} - - -void XMLPrinter::PushHeader( bool writeBOM, bool writeDec ) -{ - if ( writeBOM ) { - static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 }; - Write( reinterpret_cast< const char* >( bom ) ); - } - if ( writeDec ) { - PushDeclaration( "xml version=\"1.0\"" ); - } -} - -void XMLPrinter::PrepareForNewNode( bool compactMode ) -{ - SealElementIfJustOpened(); - - if ( compactMode ) { - return; - } - - if ( _firstElement ) { - PrintSpace (_depth); - } else if ( _textDepth < 0) { - Putc( '\n' ); - PrintSpace( _depth ); - } - - _firstElement = false; -} - -void XMLPrinter::OpenElement( const char* name, bool compactMode ) -{ - PrepareForNewNode( compactMode ); - _stack.Push( name ); - - Write ( "<" ); - Write ( name ); - - _elementJustOpened = true; - ++_depth; -} - - -void XMLPrinter::PushAttribute( const char* name, const char* value ) -{ - TIXMLASSERT( _elementJustOpened ); - Putc ( ' ' ); - Write( name ); - Write( "=\"" ); - PrintString( value, false ); - Putc ( '\"' ); -} - - -void XMLPrinter::PushAttribute( const char* name, int v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - PushAttribute( name, buf ); -} - - -void XMLPrinter::PushAttribute( const char* name, unsigned v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - PushAttribute( name, buf ); -} - - -void XMLPrinter::PushAttribute(const char* name, int64_t v) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr(v, buf, BUF_SIZE); - PushAttribute(name, buf); -} - - -void XMLPrinter::PushAttribute(const char* name, uint64_t v) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr(v, buf, BUF_SIZE); - PushAttribute(name, buf); -} - - -void XMLPrinter::PushAttribute( const char* name, bool v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - PushAttribute( name, buf ); -} - - -void XMLPrinter::PushAttribute( const char* name, double v ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( v, buf, BUF_SIZE ); - PushAttribute( name, buf ); -} - - -void XMLPrinter::CloseElement( bool compactMode ) -{ - --_depth; - const char* name = _stack.Pop(); - - if ( _elementJustOpened ) { - Write( "/>" ); - } - else { - if ( _textDepth < 0 && !compactMode) { - Putc( '\n' ); - PrintSpace( _depth ); - } - Write ( "" ); - } - - if ( _textDepth == _depth ) { - _textDepth = -1; - } - if ( _depth == 0 && !compactMode) { - Putc( '\n' ); - } - _elementJustOpened = false; -} - - -void XMLPrinter::SealElementIfJustOpened() -{ - if ( !_elementJustOpened ) { - return; - } - _elementJustOpened = false; - Putc( '>' ); -} - - -void XMLPrinter::PushText( const char* text, bool cdata ) -{ - _textDepth = _depth-1; - - SealElementIfJustOpened(); - if ( cdata ) { - Write( "" ); - } - else { - PrintString( text, true ); - } -} - - -void XMLPrinter::PushText( int64_t value ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( value, buf, BUF_SIZE ); - PushText( buf, false ); -} - - -void XMLPrinter::PushText( uint64_t value ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr(value, buf, BUF_SIZE); - PushText(buf, false); -} - - -void XMLPrinter::PushText( int value ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( value, buf, BUF_SIZE ); - PushText( buf, false ); -} - - -void XMLPrinter::PushText( unsigned value ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( value, buf, BUF_SIZE ); - PushText( buf, false ); -} - - -void XMLPrinter::PushText( bool value ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( value, buf, BUF_SIZE ); - PushText( buf, false ); -} - - -void XMLPrinter::PushText( float value ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( value, buf, BUF_SIZE ); - PushText( buf, false ); -} - - -void XMLPrinter::PushText( double value ) -{ - char buf[BUF_SIZE]; - XMLUtil::ToStr( value, buf, BUF_SIZE ); - PushText( buf, false ); -} - - -void XMLPrinter::PushComment( const char* comment ) -{ - PrepareForNewNode( _compactMode ); - - Write( "" ); -} - - -void XMLPrinter::PushDeclaration( const char* value ) -{ - PrepareForNewNode( _compactMode ); - - Write( "" ); -} - - -void XMLPrinter::PushUnknown( const char* value ) -{ - PrepareForNewNode( _compactMode ); - - Write( "' ); -} - - -bool XMLPrinter::VisitEnter( const XMLDocument& doc ) -{ - _processEntities = doc.ProcessEntities(); - if ( doc.HasBOM() ) { - PushHeader( true, false ); - } - return true; -} - - -bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) -{ - const XMLElement* parentElem = 0; - if ( element.Parent() ) { - parentElem = element.Parent()->ToElement(); - } - const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode; - OpenElement( element.Name(), compactMode ); - while ( attribute ) { - PushAttribute( attribute->Name(), attribute->Value() ); - attribute = attribute->Next(); - } - return true; -} - - -bool XMLPrinter::VisitExit( const XMLElement& element ) -{ - CloseElement( CompactMode(element) ); - return true; -} - - -bool XMLPrinter::Visit( const XMLText& text ) -{ - PushText( text.Value(), text.CData() ); - return true; -} - - -bool XMLPrinter::Visit( const XMLComment& comment ) -{ - PushComment( comment.Value() ); - return true; -} - -bool XMLPrinter::Visit( const XMLDeclaration& declaration ) -{ - PushDeclaration( declaration.Value() ); - return true; -} - - -bool XMLPrinter::Visit( const XMLUnknown& unknown ) -{ - PushUnknown( unknown.Value() ); - return true; -} - -} // namespace tinyxml2 diff --git a/3rdparty/tinyxml2/tinyxml2.h b/3rdparty/tinyxml2/tinyxml2.h deleted file mode 100644 index 8179f57b4..000000000 --- a/3rdparty/tinyxml2/tinyxml2.h +++ /dev/null @@ -1,2383 +0,0 @@ -/* -Original code by Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#ifndef TINYXML2_INCLUDED -#define TINYXML2_INCLUDED - -#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) -# include -# include -# include -# include -# include -# if defined(__PS3__) -# include -# endif -#else -# include -# include -# include -# include -# include -#endif -#include - -/* - gcc: - g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe - - Formatting, Artistic Style: - AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h -*/ - -#if defined( _DEBUG ) || defined (__DEBUG__) -# ifndef TINYXML2_DEBUG -# define TINYXML2_DEBUG -# endif -#endif - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4251) -#endif - -#ifdef _MSC_VER -# ifdef TINYXML2_EXPORT -# define TINYXML2_LIB __declspec(dllexport) -# elif defined(TINYXML2_IMPORT) -# define TINYXML2_LIB __declspec(dllimport) -# else -# define TINYXML2_LIB -# endif -#elif __GNUC__ >= 4 -# define TINYXML2_LIB __attribute__((visibility("default"))) -#else -# define TINYXML2_LIB -#endif - - -#if !defined(TIXMLASSERT) -#if defined(TINYXML2_DEBUG) -# if defined(_MSC_VER) -# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like -# define TIXMLASSERT( x ) do { if ( !((void)0,(x))) { __debugbreak(); } } while(false) -# elif defined (ANDROID_NDK) -# include -# define TIXMLASSERT( x ) do { if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } } while(false) -# else -# include -# define TIXMLASSERT assert -# endif -#else -# define TIXMLASSERT( x ) do {} while(false) -#endif -#endif - -/* Versioning, past 1.0.14: - http://semver.org/ -*/ -static const int TIXML2_MAJOR_VERSION = 11; -static const int TIXML2_MINOR_VERSION = 0; -static const int TIXML2_PATCH_VERSION = 0; - -#define TINYXML2_MAJOR_VERSION 11 -#define TINYXML2_MINOR_VERSION 0 -#define TINYXML2_PATCH_VERSION 0 - -// A fixed element depth limit is problematic. There needs to be a -// limit to avoid a stack overflow. However, that limit varies per -// system, and the capacity of the stack. On the other hand, it's a trivial -// attack that can result from ill, malicious, or even correctly formed XML, -// so there needs to be a limit in place. -static const int TINYXML2_MAX_ELEMENT_DEPTH = 500; - -namespace tinyxml2 -{ -class XMLDocument; -class XMLElement; -class XMLAttribute; -class XMLComment; -class XMLText; -class XMLDeclaration; -class XMLUnknown; -class XMLPrinter; - -/* - A class that wraps strings. Normally stores the start and end - pointers into the XML file itself, and will apply normalization - and entity translation if actually read. Can also store (and memory - manage) a traditional char[] - - Isn't clear why TINYXML2_LIB is needed; but seems to fix #719 -*/ -class TINYXML2_LIB StrPair -{ -public: - enum Mode { - NEEDS_ENTITY_PROCESSING = 0x01, - NEEDS_NEWLINE_NORMALIZATION = 0x02, - NEEDS_WHITESPACE_COLLAPSING = 0x04, - - TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, - TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, - ATTRIBUTE_NAME = 0, - ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, - ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, - COMMENT = NEEDS_NEWLINE_NORMALIZATION - }; - - StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} - ~StrPair(); - - void Set( char* start, char* end, int flags ) { - TIXMLASSERT( start ); - TIXMLASSERT( end ); - Reset(); - _start = start; - _end = end; - _flags = flags | NEEDS_FLUSH; - } - - const char* GetStr(); - - bool Empty() const { - return _start == _end; - } - - void SetInternedStr( const char* str ) { - Reset(); - _start = const_cast(str); - } - - void SetStr( const char* str, int flags=0 ); - - char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr ); - char* ParseName( char* in ); - - void TransferTo( StrPair* other ); - void Reset(); - -private: - void CollapseWhitespace(); - - enum { - NEEDS_FLUSH = 0x100, - NEEDS_DELETE = 0x200 - }; - - int _flags; - char* _start; - char* _end; - - StrPair( const StrPair& other ); // not supported - void operator=( const StrPair& other ); // not supported, use TransferTo() -}; - - -/* - A dynamic array of Plain Old Data. Doesn't support constructors, etc. - Has a small initial memory pool, so that low or no usage will not - cause a call to new/delete -*/ -template -class DynArray -{ -public: - DynArray() : - _mem( _pool ), - _allocated( INITIAL_SIZE ), - _size( 0 ) - { - } - - ~DynArray() { - if ( _mem != _pool ) { - delete [] _mem; - } - } - - void Clear() { - _size = 0; - } - - void Push( T t ) { - TIXMLASSERT( _size < INT_MAX ); - EnsureCapacity( _size+1 ); - _mem[_size] = t; - ++_size; - } - - T* PushArr( size_t count ) { - TIXMLASSERT( _size <= SIZE_MAX - count ); - EnsureCapacity( _size+count ); - T* ret = &_mem[_size]; - _size += count; - return ret; - } - - T Pop() { - TIXMLASSERT( _size > 0 ); - --_size; - return _mem[_size]; - } - - void PopArr( size_t count ) { - TIXMLASSERT( _size >= count ); - _size -= count; - } - - bool Empty() const { - return _size == 0; - } - - T& operator[](size_t i) { - TIXMLASSERT( i < _size ); - return _mem[i]; - } - - const T& operator[](size_t i) const { - TIXMLASSERT( i < _size ); - return _mem[i]; - } - - const T& PeekTop() const { - TIXMLASSERT( _size > 0 ); - return _mem[ _size - 1]; - } - - size_t Size() const { - TIXMLASSERT( _size >= 0 ); - return _size; - } - - size_t Capacity() const { - TIXMLASSERT( _allocated >= INITIAL_SIZE ); - return _allocated; - } - - void SwapRemove(size_t i) { - TIXMLASSERT(i < _size); - TIXMLASSERT(_size > 0); - _mem[i] = _mem[_size - 1]; - --_size; - } - - const T* Mem() const { - TIXMLASSERT( _mem ); - return _mem; - } - - T* Mem() { - TIXMLASSERT( _mem ); - return _mem; - } - -private: - DynArray( const DynArray& ); // not supported - void operator=( const DynArray& ); // not supported - - void EnsureCapacity( size_t cap ) { - TIXMLASSERT( cap > 0 ); - if ( cap > _allocated ) { - TIXMLASSERT( cap <= SIZE_MAX / 2 / sizeof(T)); - const size_t newAllocated = cap * 2; - T* newMem = new T[newAllocated]; - TIXMLASSERT( newAllocated >= _size ); - memcpy( newMem, _mem, sizeof(T) * _size ); // warning: not using constructors, only works for PODs - if ( _mem != _pool ) { - delete [] _mem; - } - _mem = newMem; - _allocated = newAllocated; - } - } - - T* _mem; - T _pool[INITIAL_SIZE]; - size_t _allocated; // objects allocated - size_t _size; // number objects in use -}; - - -/* - Parent virtual class of a pool for fast allocation - and deallocation of objects. -*/ -class MemPool -{ -public: - MemPool() {} - virtual ~MemPool() {} - - virtual size_t ItemSize() const = 0; - virtual void* Alloc() = 0; - virtual void Free( void* ) = 0; - virtual void SetTracked() = 0; -}; - - -/* - Template child class to create pools of the correct type. -*/ -template< size_t ITEM_SIZE > -class MemPoolT : public MemPool -{ -public: - MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} - ~MemPoolT() { - MemPoolT< ITEM_SIZE >::Clear(); - } - - void Clear() { - // Delete the blocks. - while( !_blockPtrs.Empty()) { - Block* lastBlock = _blockPtrs.Pop(); - delete lastBlock; - } - _root = 0; - _currentAllocs = 0; - _nAllocs = 0; - _maxAllocs = 0; - _nUntracked = 0; - } - - virtual size_t ItemSize() const override { - return ITEM_SIZE; - } - size_t CurrentAllocs() const { - return _currentAllocs; - } - - virtual void* Alloc() override{ - if ( !_root ) { - // Need a new block. - Block* block = new Block; - _blockPtrs.Push( block ); - - Item* blockItems = block->items; - for( size_t i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) { - blockItems[i].next = &(blockItems[i + 1]); - } - blockItems[ITEMS_PER_BLOCK - 1].next = 0; - _root = blockItems; - } - Item* const result = _root; - TIXMLASSERT( result != 0 ); - _root = _root->next; - - ++_currentAllocs; - if ( _currentAllocs > _maxAllocs ) { - _maxAllocs = _currentAllocs; - } - ++_nAllocs; - ++_nUntracked; - return result; - } - - virtual void Free( void* mem ) override { - if ( !mem ) { - return; - } - --_currentAllocs; - Item* item = static_cast( mem ); -#ifdef TINYXML2_DEBUG - memset( item, 0xfe, sizeof( *item ) ); -#endif - item->next = _root; - _root = item; - } - void Trace( const char* name ) { - printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", - name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs, - ITEM_SIZE, _nAllocs, _blockPtrs.Size() ); - } - - void SetTracked() override { - --_nUntracked; - } - - size_t Untracked() const { - return _nUntracked; - } - - // This number is perf sensitive. 4k seems like a good tradeoff on my machine. - // The test file is large, 170k. - // Release: VS2010 gcc(no opt) - // 1k: 4000 - // 2k: 4000 - // 4k: 3900 21000 - // 16k: 5200 - // 32k: 4300 - // 64k: 4000 21000 - // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK - // in private part if ITEMS_PER_BLOCK is private - enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE }; - -private: - MemPoolT( const MemPoolT& ); // not supported - void operator=( const MemPoolT& ); // not supported - - union Item { - Item* next; - char itemData[static_cast(ITEM_SIZE)]; - }; - struct Block { - Item items[ITEMS_PER_BLOCK]; - }; - DynArray< Block*, 10 > _blockPtrs; - Item* _root; - - size_t _currentAllocs; - size_t _nAllocs; - size_t _maxAllocs; - size_t _nUntracked; -}; - - - -/** - Implements the interface to the "Visitor pattern" (see the Accept() method.) - If you call the Accept() method, it requires being passed a XMLVisitor - class to handle callbacks. For nodes that contain other nodes (Document, Element) - you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs - are simply called with Visit(). - - If you return 'true' from a Visit method, recursive parsing will continue. If you return - false, no children of this node or its siblings will be visited. - - All flavors of Visit methods have a default implementation that returns 'true' (continue - visiting). You need to only override methods that are interesting to you. - - Generally Accept() is called on the XMLDocument, although all nodes support visiting. - - You should never change the document from a callback. - - @sa XMLNode::Accept() -*/ -class TINYXML2_LIB XMLVisitor -{ -public: - virtual ~XMLVisitor() {} - - /// Visit a document. - virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { - return true; - } - /// Visit a document. - virtual bool VisitExit( const XMLDocument& /*doc*/ ) { - return true; - } - - /// Visit an element. - virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { - return true; - } - /// Visit an element. - virtual bool VisitExit( const XMLElement& /*element*/ ) { - return true; - } - - /// Visit a declaration. - virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { - return true; - } - /// Visit a text node. - virtual bool Visit( const XMLText& /*text*/ ) { - return true; - } - /// Visit a comment node. - virtual bool Visit( const XMLComment& /*comment*/ ) { - return true; - } - /// Visit an unknown node. - virtual bool Visit( const XMLUnknown& /*unknown*/ ) { - return true; - } -}; - -// WARNING: must match XMLDocument::_errorNames[] -enum XMLError { - XML_SUCCESS = 0, - XML_NO_ATTRIBUTE, - XML_WRONG_ATTRIBUTE_TYPE, - XML_ERROR_FILE_NOT_FOUND, - XML_ERROR_FILE_COULD_NOT_BE_OPENED, - XML_ERROR_FILE_READ_ERROR, - XML_ERROR_PARSING_ELEMENT, - XML_ERROR_PARSING_ATTRIBUTE, - XML_ERROR_PARSING_TEXT, - XML_ERROR_PARSING_CDATA, - XML_ERROR_PARSING_COMMENT, - XML_ERROR_PARSING_DECLARATION, - XML_ERROR_PARSING_UNKNOWN, - XML_ERROR_EMPTY_DOCUMENT, - XML_ERROR_MISMATCHED_ELEMENT, - XML_ERROR_PARSING, - XML_CAN_NOT_CONVERT_TEXT, - XML_NO_TEXT_NODE, - XML_ELEMENT_DEPTH_EXCEEDED, - - XML_ERROR_COUNT -}; - - -/* - Utility functionality. -*/ -class TINYXML2_LIB XMLUtil -{ -public: - static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) { - TIXMLASSERT( p ); - - while( IsWhiteSpace(*p) ) { - if (curLineNumPtr && *p == '\n') { - ++(*curLineNumPtr); - } - ++p; - } - TIXMLASSERT( p ); - return p; - } - static char* SkipWhiteSpace( char* const p, int* curLineNumPtr ) { - return const_cast( SkipWhiteSpace( const_cast(p), curLineNumPtr ) ); - } - - // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't - // correct, but simple, and usually works. - static bool IsWhiteSpace( char p ) { - return !IsUTF8Continuation(p) && isspace( static_cast(p) ); - } - - inline static bool IsNameStartChar( unsigned char ch ) { - if ( ch >= 128 ) { - // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() - return true; - } - if ( isalpha( ch ) ) { - return true; - } - return ch == ':' || ch == '_'; - } - - inline static bool IsNameChar( unsigned char ch ) { - return IsNameStartChar( ch ) - || isdigit( ch ) - || ch == '.' - || ch == '-'; - } - - inline static bool IsPrefixHex( const char* p) { - p = SkipWhiteSpace(p, 0); - return p && *p == '0' && ( *(p + 1) == 'x' || *(p + 1) == 'X'); - } - - inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { - if ( p == q ) { - return true; - } - TIXMLASSERT( p ); - TIXMLASSERT( q ); - TIXMLASSERT( nChar >= 0 ); - return strncmp( p, q, static_cast(nChar) ) == 0; - } - - inline static bool IsUTF8Continuation( const char p ) { - return ( p & 0x80 ) != 0; - } - - static const char* ReadBOM( const char* p, bool* hasBOM ); - // p is the starting location, - // the UTF-8 value of the entity will be placed in value, and length filled in. - static const char* GetCharacterRef( const char* p, char* value, int* length ); - static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); - - // converts primitive types to strings - static void ToStr( int v, char* buffer, int bufferSize ); - static void ToStr( unsigned v, char* buffer, int bufferSize ); - static void ToStr( bool v, char* buffer, int bufferSize ); - static void ToStr( float v, char* buffer, int bufferSize ); - static void ToStr( double v, char* buffer, int bufferSize ); - static void ToStr(int64_t v, char* buffer, int bufferSize); - static void ToStr(uint64_t v, char* buffer, int bufferSize); - - // converts strings to primitive types - static bool ToInt( const char* str, int* value ); - static bool ToUnsigned( const char* str, unsigned* value ); - static bool ToBool( const char* str, bool* value ); - static bool ToFloat( const char* str, float* value ); - static bool ToDouble( const char* str, double* value ); - static bool ToInt64(const char* str, int64_t* value); - static bool ToUnsigned64(const char* str, uint64_t* value); - // Changes what is serialized for a boolean value. - // Default to "true" and "false". Shouldn't be changed - // unless you have a special testing or compatibility need. - // Be careful: static, global, & not thread safe. - // Be sure to set static const memory as parameters. - static void SetBoolSerialization(const char* writeTrue, const char* writeFalse); - -private: - static const char* writeBoolTrue; - static const char* writeBoolFalse; -}; - - -/** XMLNode is a base class for every object that is in the - XML Document Object Model (DOM), except XMLAttributes. - Nodes have siblings, a parent, and children which can - be navigated. A node is always in a XMLDocument. - The type of a XMLNode can be queried, and it can - be cast to its more defined type. - - A XMLDocument allocates memory for all its Nodes. - When the XMLDocument gets deleted, all its Nodes - will also be deleted. - - @verbatim - A Document can contain: Element (container or leaf) - Comment (leaf) - Unknown (leaf) - Declaration( leaf ) - - An Element can contain: Element (container or leaf) - Text (leaf) - Attributes (not on tree) - Comment (leaf) - Unknown (leaf) - - @endverbatim -*/ -class TINYXML2_LIB XMLNode -{ - friend class XMLDocument; - friend class XMLElement; -public: - - /// Get the XMLDocument that owns this XMLNode. - const XMLDocument* GetDocument() const { - TIXMLASSERT( _document ); - return _document; - } - /// Get the XMLDocument that owns this XMLNode. - XMLDocument* GetDocument() { - TIXMLASSERT( _document ); - return _document; - } - - /// Safely cast to an Element, or null. - virtual XMLElement* ToElement() { - return 0; - } - /// Safely cast to Text, or null. - virtual XMLText* ToText() { - return 0; - } - /// Safely cast to a Comment, or null. - virtual XMLComment* ToComment() { - return 0; - } - /// Safely cast to a Document, or null. - virtual XMLDocument* ToDocument() { - return 0; - } - /// Safely cast to a Declaration, or null. - virtual XMLDeclaration* ToDeclaration() { - return 0; - } - /// Safely cast to an Unknown, or null. - virtual XMLUnknown* ToUnknown() { - return 0; - } - - virtual const XMLElement* ToElement() const { - return 0; - } - virtual const XMLText* ToText() const { - return 0; - } - virtual const XMLComment* ToComment() const { - return 0; - } - virtual const XMLDocument* ToDocument() const { - return 0; - } - virtual const XMLDeclaration* ToDeclaration() const { - return 0; - } - virtual const XMLUnknown* ToUnknown() const { - return 0; - } - - // ChildElementCount was originally suggested by msteiger on the sourceforge page for TinyXML and modified by KB1SPH for TinyXML-2. - - int ChildElementCount(const char *value) const; - - int ChildElementCount() const; - - /** The meaning of 'value' changes for the specific type. - @verbatim - Document: empty (NULL is returned, not an empty string) - Element: name of the element - Comment: the comment text - Unknown: the tag contents - Text: the text string - @endverbatim - */ - const char* Value() const; - - /** Set the Value of an XML node. - @sa Value() - */ - void SetValue( const char* val, bool staticMem=false ); - - /// Gets the line number the node is in, if the document was parsed from a file. - int GetLineNum() const { return _parseLineNum; } - - /// Get the parent of this node on the DOM. - const XMLNode* Parent() const { - return _parent; - } - - XMLNode* Parent() { - return _parent; - } - - /// Returns true if this node has no children. - bool NoChildren() const { - return !_firstChild; - } - - /// Get the first child node, or null if none exists. - const XMLNode* FirstChild() const { - return _firstChild; - } - - XMLNode* FirstChild() { - return _firstChild; - } - - /** Get the first child element, or optionally the first child - element with the specified name. - */ - const XMLElement* FirstChildElement( const char* name = 0 ) const; - - XMLElement* FirstChildElement( const char* name = 0 ) { - return const_cast(const_cast(this)->FirstChildElement( name )); - } - - /// Get the last child node, or null if none exists. - const XMLNode* LastChild() const { - return _lastChild; - } - - XMLNode* LastChild() { - return _lastChild; - } - - /** Get the last child element or optionally the last child - element with the specified name. - */ - const XMLElement* LastChildElement( const char* name = 0 ) const; - - XMLElement* LastChildElement( const char* name = 0 ) { - return const_cast(const_cast(this)->LastChildElement(name) ); - } - - /// Get the previous (left) sibling node of this node. - const XMLNode* PreviousSibling() const { - return _prev; - } - - XMLNode* PreviousSibling() { - return _prev; - } - - /// Get the previous (left) sibling element of this node, with an optionally supplied name. - const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ; - - XMLElement* PreviousSiblingElement( const char* name = 0 ) { - return const_cast(const_cast(this)->PreviousSiblingElement( name ) ); - } - - /// Get the next (right) sibling node of this node. - const XMLNode* NextSibling() const { - return _next; - } - - XMLNode* NextSibling() { - return _next; - } - - /// Get the next (right) sibling element of this node, with an optionally supplied name. - const XMLElement* NextSiblingElement( const char* name = 0 ) const; - - XMLElement* NextSiblingElement( const char* name = 0 ) { - return const_cast(const_cast(this)->NextSiblingElement( name ) ); - } - - /** - Add a child node as the last (right) child. - If the child node is already part of the document, - it is moved from its old location to the new location. - Returns the addThis argument or 0 if the node does not - belong to the same document. - */ - XMLNode* InsertEndChild( XMLNode* addThis ); - - XMLNode* LinkEndChild( XMLNode* addThis ) { - return InsertEndChild( addThis ); - } - /** - Add a child node as the first (left) child. - If the child node is already part of the document, - it is moved from its old location to the new location. - Returns the addThis argument or 0 if the node does not - belong to the same document. - */ - XMLNode* InsertFirstChild( XMLNode* addThis ); - /** - Add a node after the specified child node. - If the child node is already part of the document, - it is moved from its old location to the new location. - Returns the addThis argument or 0 if the afterThis node - is not a child of this node, or if the node does not - belong to the same document. - */ - XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); - - /** - Delete all the children of this node. - */ - void DeleteChildren(); - - /** - Delete a child of this node. - */ - void DeleteChild( XMLNode* node ); - - /** - Make a copy of this node, but not its children. - You may pass in a Document pointer that will be - the owner of the new Node. If the 'document' is - null, then the node returned will be allocated - from the current Document. (this->GetDocument()) - - Note: if called on a XMLDocument, this will return null. - */ - virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; - - /** - Make a copy of this node and all its children. - - If the 'target' is null, then the nodes will - be allocated in the current document. If 'target' - is specified, the memory will be allocated in the - specified XMLDocument. - - NOTE: This is probably not the correct tool to - copy a document, since XMLDocuments can have multiple - top level XMLNodes. You probably want to use - XMLDocument::DeepCopy() - */ - XMLNode* DeepClone( XMLDocument* target ) const; - - /** - Test if 2 nodes are the same, but don't test children. - The 2 nodes do not need to be in the same Document. - - Note: if called on a XMLDocument, this will return false. - */ - virtual bool ShallowEqual( const XMLNode* compare ) const = 0; - - /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the - XML tree will be conditionally visited and the host will be called back - via the XMLVisitor interface. - - This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse - the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this - interface versus any other.) - - The interface has been based on ideas from: - - - http://www.saxproject.org/ - - http://c2.com/cgi/wiki?HierarchicalVisitorPattern - - Which are both good references for "visiting". - - An example of using Accept(): - @verbatim - XMLPrinter printer; - tinyxmlDoc.Accept( &printer ); - const char* xmlcstr = printer.CStr(); - @endverbatim - */ - virtual bool Accept( XMLVisitor* visitor ) const = 0; - - /** - Set user data into the XMLNode. TinyXML-2 in - no way processes or interprets user data. - It is initially 0. - */ - void SetUserData(void* userData) { _userData = userData; } - - /** - Get user data set into the XMLNode. TinyXML-2 in - no way processes or interprets user data. - It is initially 0. - */ - void* GetUserData() const { return _userData; } - -protected: - explicit XMLNode( XMLDocument* ); - virtual ~XMLNode(); - - virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); - - XMLDocument* _document; - XMLNode* _parent; - mutable StrPair _value; - int _parseLineNum; - - XMLNode* _firstChild; - XMLNode* _lastChild; - - XMLNode* _prev; - XMLNode* _next; - - void* _userData; - -private: - MemPool* _memPool; - void Unlink( XMLNode* child ); - static void DeleteNode( XMLNode* node ); - void InsertChildPreamble( XMLNode* insertThis ) const; - const XMLElement* ToElementWithName( const char* name ) const; - - XMLNode( const XMLNode& ); // not supported - XMLNode& operator=( const XMLNode& ); // not supported -}; - - -/** XML text. - - Note that a text node can have child element nodes, for example: - @verbatim - This is bold - @endverbatim - - A text node can have 2 ways to output the next. "normal" output - and CDATA. It will default to the mode it was parsed from the XML file and - you generally want to leave it alone, but you can change the output mode with - SetCData() and query it with CData(). -*/ -class TINYXML2_LIB XMLText : public XMLNode -{ - friend class XMLDocument; -public: - virtual bool Accept( XMLVisitor* visitor ) const override; - - virtual XMLText* ToText() override { - return this; - } - virtual const XMLText* ToText() const override { - return this; - } - - /// Declare whether this should be CDATA or standard text. - void SetCData( bool isCData ) { - _isCData = isCData; - } - /// Returns true if this is a CDATA text element. - bool CData() const { - return _isCData; - } - - virtual XMLNode* ShallowClone( XMLDocument* document ) const override; - virtual bool ShallowEqual( const XMLNode* compare ) const override; - -protected: - explicit XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} - virtual ~XMLText() {} - - char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; - -private: - bool _isCData; - - XMLText( const XMLText& ); // not supported - XMLText& operator=( const XMLText& ); // not supported -}; - - -/** An XML Comment. */ -class TINYXML2_LIB XMLComment : public XMLNode -{ - friend class XMLDocument; -public: - virtual XMLComment* ToComment() override { - return this; - } - virtual const XMLComment* ToComment() const override { - return this; - } - - virtual bool Accept( XMLVisitor* visitor ) const override; - - virtual XMLNode* ShallowClone( XMLDocument* document ) const override; - virtual bool ShallowEqual( const XMLNode* compare ) const override; - -protected: - explicit XMLComment( XMLDocument* doc ); - virtual ~XMLComment(); - - char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr) override; - -private: - XMLComment( const XMLComment& ); // not supported - XMLComment& operator=( const XMLComment& ); // not supported -}; - - -/** In correct XML the declaration is the first entry in the file. - @verbatim - - @endverbatim - - TinyXML-2 will happily read or write files without a declaration, - however. - - The text of the declaration isn't interpreted. It is parsed - and written as a string. -*/ -class TINYXML2_LIB XMLDeclaration : public XMLNode -{ - friend class XMLDocument; -public: - virtual XMLDeclaration* ToDeclaration() override { - return this; - } - virtual const XMLDeclaration* ToDeclaration() const override { - return this; - } - - virtual bool Accept( XMLVisitor* visitor ) const override; - - virtual XMLNode* ShallowClone( XMLDocument* document ) const override; - virtual bool ShallowEqual( const XMLNode* compare ) const override; - -protected: - explicit XMLDeclaration( XMLDocument* doc ); - virtual ~XMLDeclaration(); - - char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; - -private: - XMLDeclaration( const XMLDeclaration& ); // not supported - XMLDeclaration& operator=( const XMLDeclaration& ); // not supported -}; - - -/** Any tag that TinyXML-2 doesn't recognize is saved as an - unknown. It is a tag of text, but should not be modified. - It will be written back to the XML, unchanged, when the file - is saved. - - DTD tags get thrown into XMLUnknowns. -*/ -class TINYXML2_LIB XMLUnknown : public XMLNode -{ - friend class XMLDocument; -public: - virtual XMLUnknown* ToUnknown() override { - return this; - } - virtual const XMLUnknown* ToUnknown() const override { - return this; - } - - virtual bool Accept( XMLVisitor* visitor ) const override; - - virtual XMLNode* ShallowClone( XMLDocument* document ) const override; - virtual bool ShallowEqual( const XMLNode* compare ) const override; - -protected: - explicit XMLUnknown( XMLDocument* doc ); - virtual ~XMLUnknown(); - - char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; - -private: - XMLUnknown( const XMLUnknown& ); // not supported - XMLUnknown& operator=( const XMLUnknown& ); // not supported -}; - - - -/** An attribute is a name-value pair. Elements have an arbitrary - number of attributes, each with a unique name. - - @note The attributes are not XMLNodes. You may only query the - Next() attribute in a list. -*/ -class TINYXML2_LIB XMLAttribute -{ - friend class XMLElement; -public: - /// The name of the attribute. - const char* Name() const; - - /// The value of the attribute. - const char* Value() const; - - /// Gets the line number the attribute is in, if the document was parsed from a file. - int GetLineNum() const { return _parseLineNum; } - - /// The next attribute in the list. - const XMLAttribute* Next() const { - return _next; - } - - /** IntValue interprets the attribute as an integer, and returns the value. - If the value isn't an integer, 0 will be returned. There is no error checking; - use QueryIntValue() if you need error checking. - */ - int IntValue() const { - int i = 0; - QueryIntValue(&i); - return i; - } - - int64_t Int64Value() const { - int64_t i = 0; - QueryInt64Value(&i); - return i; - } - - uint64_t Unsigned64Value() const { - uint64_t i = 0; - QueryUnsigned64Value(&i); - return i; - } - - /// Query as an unsigned integer. See IntValue() - unsigned UnsignedValue() const { - unsigned i=0; - QueryUnsignedValue( &i ); - return i; - } - /// Query as a boolean. See IntValue() - bool BoolValue() const { - bool b=false; - QueryBoolValue( &b ); - return b; - } - /// Query as a double. See IntValue() - double DoubleValue() const { - double d=0; - QueryDoubleValue( &d ); - return d; - } - /// Query as a float. See IntValue() - float FloatValue() const { - float f=0; - QueryFloatValue( &f ); - return f; - } - - /** QueryIntValue interprets the attribute as an integer, and returns the value - in the provided parameter. The function will return XML_SUCCESS on success, - and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. - */ - XMLError QueryIntValue( int* value ) const; - /// See QueryIntValue - XMLError QueryUnsignedValue( unsigned int* value ) const; - /// See QueryIntValue - XMLError QueryInt64Value(int64_t* value) const; - /// See QueryIntValue - XMLError QueryUnsigned64Value(uint64_t* value) const; - /// See QueryIntValue - XMLError QueryBoolValue( bool* value ) const; - /// See QueryIntValue - XMLError QueryDoubleValue( double* value ) const; - /// See QueryIntValue - XMLError QueryFloatValue( float* value ) const; - - /// Set the attribute to a string value. - void SetAttribute( const char* value ); - /// Set the attribute to value. - void SetAttribute( int value ); - /// Set the attribute to value. - void SetAttribute( unsigned value ); - /// Set the attribute to value. - void SetAttribute(int64_t value); - /// Set the attribute to value. - void SetAttribute(uint64_t value); - /// Set the attribute to value. - void SetAttribute( bool value ); - /// Set the attribute to value. - void SetAttribute( double value ); - /// Set the attribute to value. - void SetAttribute( float value ); - -private: - enum { BUF_SIZE = 200 }; - - XMLAttribute() : _name(), _value(),_parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {} - virtual ~XMLAttribute() {} - - XMLAttribute( const XMLAttribute& ); // not supported - void operator=( const XMLAttribute& ); // not supported - void SetName( const char* name ); - - char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr ); - - mutable StrPair _name; - mutable StrPair _value; - int _parseLineNum; - XMLAttribute* _next; - MemPool* _memPool; -}; - - -/** The element is a container class. It has a value, the element name, - and can contain other elements, text, comments, and unknowns. - Elements also contain an arbitrary number of attributes. -*/ -class TINYXML2_LIB XMLElement : public XMLNode -{ - friend class XMLDocument; -public: - /// Get the name of an element (which is the Value() of the node.) - const char* Name() const { - return Value(); - } - /// Set the name of the element. - void SetName( const char* str, bool staticMem=false ) { - SetValue( str, staticMem ); - } - - virtual XMLElement* ToElement() override { - return this; - } - virtual const XMLElement* ToElement() const override { - return this; - } - virtual bool Accept( XMLVisitor* visitor ) const override; - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none - exists. For example: - - @verbatim - const char* value = ele->Attribute( "foo" ); - @endverbatim - - The 'value' parameter is normally null. However, if specified, - the attribute will only be returned if the 'name' and 'value' - match. This allow you to write code: - - @verbatim - if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); - @endverbatim - - rather than: - @verbatim - if ( ele->Attribute( "foo" ) ) { - if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); - } - @endverbatim - */ - const char* Attribute( const char* name, const char* value=0 ) const; - - /** Given an attribute name, IntAttribute() returns the value - of the attribute interpreted as an integer. The default - value will be returned if the attribute isn't present, - or if there is an error. (For a method with error - checking, see QueryIntAttribute()). - */ - int IntAttribute(const char* name, int defaultValue = 0) const; - /// See IntAttribute() - unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const; - /// See IntAttribute() - int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const; - /// See IntAttribute() - uint64_t Unsigned64Attribute(const char* name, uint64_t defaultValue = 0) const; - /// See IntAttribute() - bool BoolAttribute(const char* name, bool defaultValue = false) const; - /// See IntAttribute() - double DoubleAttribute(const char* name, double defaultValue = 0) const; - /// See IntAttribute() - float FloatAttribute(const char* name, float defaultValue = 0) const; - - /** Given an attribute name, QueryIntAttribute() returns - XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion - can't be performed, or XML_NO_ATTRIBUTE if the attribute - doesn't exist. If successful, the result of the conversion - will be written to 'value'. If not successful, nothing will - be written to 'value'. This allows you to provide default - value: - - @verbatim - int value = 10; - QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 - @endverbatim - */ - XMLError QueryIntAttribute( const char* name, int* value ) const { - const XMLAttribute* a = FindAttribute( name ); - if ( !a ) { - return XML_NO_ATTRIBUTE; - } - return a->QueryIntValue( value ); - } - - /// See QueryIntAttribute() - XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { - const XMLAttribute* a = FindAttribute( name ); - if ( !a ) { - return XML_NO_ATTRIBUTE; - } - return a->QueryUnsignedValue( value ); - } - - /// See QueryIntAttribute() - XMLError QueryInt64Attribute(const char* name, int64_t* value) const { - const XMLAttribute* a = FindAttribute(name); - if (!a) { - return XML_NO_ATTRIBUTE; - } - return a->QueryInt64Value(value); - } - - /// See QueryIntAttribute() - XMLError QueryUnsigned64Attribute(const char* name, uint64_t* value) const { - const XMLAttribute* a = FindAttribute(name); - if(!a) { - return XML_NO_ATTRIBUTE; - } - return a->QueryUnsigned64Value(value); - } - - /// See QueryIntAttribute() - XMLError QueryBoolAttribute( const char* name, bool* value ) const { - const XMLAttribute* a = FindAttribute( name ); - if ( !a ) { - return XML_NO_ATTRIBUTE; - } - return a->QueryBoolValue( value ); - } - /// See QueryIntAttribute() - XMLError QueryDoubleAttribute( const char* name, double* value ) const { - const XMLAttribute* a = FindAttribute( name ); - if ( !a ) { - return XML_NO_ATTRIBUTE; - } - return a->QueryDoubleValue( value ); - } - /// See QueryIntAttribute() - XMLError QueryFloatAttribute( const char* name, float* value ) const { - const XMLAttribute* a = FindAttribute( name ); - if ( !a ) { - return XML_NO_ATTRIBUTE; - } - return a->QueryFloatValue( value ); - } - - /// See QueryIntAttribute() - XMLError QueryStringAttribute(const char* name, const char** value) const { - const XMLAttribute* a = FindAttribute(name); - if (!a) { - return XML_NO_ATTRIBUTE; - } - *value = a->Value(); - return XML_SUCCESS; - } - - - - /** Given an attribute name, QueryAttribute() returns - XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion - can't be performed, or XML_NO_ATTRIBUTE if the attribute - doesn't exist. It is overloaded for the primitive types, - and is a generally more convenient replacement of - QueryIntAttribute() and related functions. - - If successful, the result of the conversion - will be written to 'value'. If not successful, nothing will - be written to 'value'. This allows you to provide default - value: - - @verbatim - int value = 10; - QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 - @endverbatim - */ - XMLError QueryAttribute( const char* name, int* value ) const { - return QueryIntAttribute( name, value ); - } - - XMLError QueryAttribute( const char* name, unsigned int* value ) const { - return QueryUnsignedAttribute( name, value ); - } - - XMLError QueryAttribute(const char* name, int64_t* value) const { - return QueryInt64Attribute(name, value); - } - - XMLError QueryAttribute(const char* name, uint64_t* value) const { - return QueryUnsigned64Attribute(name, value); - } - - XMLError QueryAttribute( const char* name, bool* value ) const { - return QueryBoolAttribute( name, value ); - } - - XMLError QueryAttribute( const char* name, double* value ) const { - return QueryDoubleAttribute( name, value ); - } - - XMLError QueryAttribute( const char* name, float* value ) const { - return QueryFloatAttribute( name, value ); - } - - XMLError QueryAttribute(const char* name, const char** value) const { - return QueryStringAttribute(name, value); - } - - /// Sets the named attribute to value. - void SetAttribute( const char* name, const char* value ) { - XMLAttribute* a = FindOrCreateAttribute( name ); - a->SetAttribute( value ); - } - /// Sets the named attribute to value. - void SetAttribute( const char* name, int value ) { - XMLAttribute* a = FindOrCreateAttribute( name ); - a->SetAttribute( value ); - } - /// Sets the named attribute to value. - void SetAttribute( const char* name, unsigned value ) { - XMLAttribute* a = FindOrCreateAttribute( name ); - a->SetAttribute( value ); - } - - /// Sets the named attribute to value. - void SetAttribute(const char* name, int64_t value) { - XMLAttribute* a = FindOrCreateAttribute(name); - a->SetAttribute(value); - } - - /// Sets the named attribute to value. - void SetAttribute(const char* name, uint64_t value) { - XMLAttribute* a = FindOrCreateAttribute(name); - a->SetAttribute(value); - } - - /// Sets the named attribute to value. - void SetAttribute( const char* name, bool value ) { - XMLAttribute* a = FindOrCreateAttribute( name ); - a->SetAttribute( value ); - } - /// Sets the named attribute to value. - void SetAttribute( const char* name, double value ) { - XMLAttribute* a = FindOrCreateAttribute( name ); - a->SetAttribute( value ); - } - /// Sets the named attribute to value. - void SetAttribute( const char* name, float value ) { - XMLAttribute* a = FindOrCreateAttribute( name ); - a->SetAttribute( value ); - } - - /** - Delete an attribute. - */ - void DeleteAttribute( const char* name ); - - /// Return the first attribute in the list. - const XMLAttribute* FirstAttribute() const { - return _rootAttribute; - } - /// Query a specific attribute in the list. - const XMLAttribute* FindAttribute( const char* name ) const; - - /** Convenience function for easy access to the text inside an element. Although easy - and concise, GetText() is limited compared to getting the XMLText child - and accessing it directly. - - If the first child of 'this' is a XMLText, the GetText() - returns the character string of the Text node, else null is returned. - - This is a convenient method for getting the text of simple contained text: - @verbatim - This is text - const char* str = fooElement->GetText(); - @endverbatim - - 'str' will be a pointer to "This is text". - - Note that this function can be misleading. If the element foo was created from - this XML: - @verbatim - This is text - @endverbatim - - then the value of str would be null. The first child node isn't a text node, it is - another element. From this XML: - @verbatim - This is text - @endverbatim - GetText() will return "This is ". - */ - const char* GetText() const; - - /** Convenience function for easy access to the text inside an element. Although easy - and concise, SetText() is limited compared to creating an XMLText child - and mutating it directly. - - If the first child of 'this' is a XMLText, SetText() sets its value to - the given string, otherwise it will create a first child that is an XMLText. - - This is a convenient method for setting the text of simple contained text: - @verbatim - This is text - fooElement->SetText( "Hullaballoo!" ); - Hullaballoo! - @endverbatim - - Note that this function can be misleading. If the element foo was created from - this XML: - @verbatim - This is text - @endverbatim - - then it will not change "This is text", but rather prefix it with a text element: - @verbatim - Hullaballoo!This is text - @endverbatim - - For this XML: - @verbatim - - @endverbatim - SetText() will generate - @verbatim - Hullaballoo! - @endverbatim - */ - void SetText( const char* inText ); - /// Convenience method for setting text inside an element. See SetText() for important limitations. - void SetText( int value ); - /// Convenience method for setting text inside an element. See SetText() for important limitations. - void SetText( unsigned value ); - /// Convenience method for setting text inside an element. See SetText() for important limitations. - void SetText(int64_t value); - /// Convenience method for setting text inside an element. See SetText() for important limitations. - void SetText(uint64_t value); - /// Convenience method for setting text inside an element. See SetText() for important limitations. - void SetText( bool value ); - /// Convenience method for setting text inside an element. See SetText() for important limitations. - void SetText( double value ); - /// Convenience method for setting text inside an element. See SetText() for important limitations. - void SetText( float value ); - - /** - Convenience method to query the value of a child text node. This is probably best - shown by example. Given you have a document is this form: - @verbatim - - 1 - 1.4 - - @endverbatim - - The QueryIntText() and similar functions provide a safe and easier way to get to the - "value" of x and y. - - @verbatim - int x = 0; - float y = 0; // types of x and y are contrived for example - const XMLElement* xElement = pointElement->FirstChildElement( "x" ); - const XMLElement* yElement = pointElement->FirstChildElement( "y" ); - xElement->QueryIntText( &x ); - yElement->QueryFloatText( &y ); - @endverbatim - - @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted - to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. - - */ - XMLError QueryIntText( int* ival ) const; - /// See QueryIntText() - XMLError QueryUnsignedText( unsigned* uval ) const; - /// See QueryIntText() - XMLError QueryInt64Text(int64_t* uval) const; - /// See QueryIntText() - XMLError QueryUnsigned64Text(uint64_t* uval) const; - /// See QueryIntText() - XMLError QueryBoolText( bool* bval ) const; - /// See QueryIntText() - XMLError QueryDoubleText( double* dval ) const; - /// See QueryIntText() - XMLError QueryFloatText( float* fval ) const; - - int IntText(int defaultValue = 0) const; - - /// See QueryIntText() - unsigned UnsignedText(unsigned defaultValue = 0) const; - /// See QueryIntText() - int64_t Int64Text(int64_t defaultValue = 0) const; - /// See QueryIntText() - uint64_t Unsigned64Text(uint64_t defaultValue = 0) const; - /// See QueryIntText() - bool BoolText(bool defaultValue = false) const; - /// See QueryIntText() - double DoubleText(double defaultValue = 0) const; - /// See QueryIntText() - float FloatText(float defaultValue = 0) const; - - /** - Convenience method to create a new XMLElement and add it as last (right) - child of this node. Returns the created and inserted element. - */ - XMLElement* InsertNewChildElement(const char* name); - /// See InsertNewChildElement() - XMLComment* InsertNewComment(const char* comment); - /// See InsertNewChildElement() - XMLText* InsertNewText(const char* text); - /// See InsertNewChildElement() - XMLDeclaration* InsertNewDeclaration(const char* text); - /// See InsertNewChildElement() - XMLUnknown* InsertNewUnknown(const char* text); - - - // internal: - enum ElementClosingType { - OPEN, // - CLOSED, // - CLOSING // - }; - ElementClosingType ClosingType() const { - return _closingType; - } - virtual XMLNode* ShallowClone( XMLDocument* document ) const override; - virtual bool ShallowEqual( const XMLNode* compare ) const override; - -protected: - char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; - -private: - XMLElement( XMLDocument* doc ); - virtual ~XMLElement(); - XMLElement( const XMLElement& ); // not supported - void operator=( const XMLElement& ); // not supported - - XMLAttribute* FindOrCreateAttribute( const char* name ); - char* ParseAttributes( char* p, int* curLineNumPtr ); - static void DeleteAttribute( XMLAttribute* attribute ); - XMLAttribute* CreateAttribute(); - - enum { BUF_SIZE = 200 }; - ElementClosingType _closingType; - // The attribute list is ordered; there is no 'lastAttribute' - // because the list needs to be scanned for dupes before adding - // a new attribute. - XMLAttribute* _rootAttribute; -}; - - -enum Whitespace { - PRESERVE_WHITESPACE, - COLLAPSE_WHITESPACE, - PEDANTIC_WHITESPACE -}; - - -/** A Document binds together all the functionality. - It can be saved, loaded, and printed to the screen. - All Nodes are connected and allocated to a Document. - If the Document is deleted, all its Nodes are also deleted. -*/ -class TINYXML2_LIB XMLDocument : public XMLNode -{ - friend class XMLElement; - // Gives access to SetError and Push/PopDepth, but over-access for everything else. - // Wishing C++ had "internal" scope. - friend class XMLNode; - friend class XMLText; - friend class XMLComment; - friend class XMLDeclaration; - friend class XMLUnknown; -public: - /// constructor - XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE ); - ~XMLDocument(); - - virtual XMLDocument* ToDocument() override { - TIXMLASSERT( this == _document ); - return this; - } - virtual const XMLDocument* ToDocument() const override { - TIXMLASSERT( this == _document ); - return this; - } - - /** - Parse an XML file from a character string. - Returns XML_SUCCESS (0) on success, or - an errorID. - - You may optionally pass in the 'nBytes', which is - the number of bytes which will be parsed. If not - specified, TinyXML-2 will assume 'xml' points to a - null terminated string. - */ - XMLError Parse( const char* xml, size_t nBytes=static_cast(-1) ); - - /** - Load an XML file from disk. - Returns XML_SUCCESS (0) on success, or - an errorID. - */ - XMLError LoadFile( const char* filename ); - - /** - Load an XML file from disk. You are responsible - for providing and closing the FILE*. - - NOTE: The file should be opened as binary ("rb") - not text in order for TinyXML-2 to correctly - do newline normalization. - - Returns XML_SUCCESS (0) on success, or - an errorID. - */ - XMLError LoadFile( FILE* ); - - /** - Save the XML file to disk. - Returns XML_SUCCESS (0) on success, or - an errorID. - */ - XMLError SaveFile( const char* filename, bool compact = false ); - - /** - Save the XML file to disk. You are responsible - for providing and closing the FILE*. - - Returns XML_SUCCESS (0) on success, or - an errorID. - */ - XMLError SaveFile( FILE* fp, bool compact = false ); - - bool ProcessEntities() const { - return _processEntities; - } - Whitespace WhitespaceMode() const { - return _whitespaceMode; - } - - /** - Returns true if this document has a leading Byte Order Mark of UTF8. - */ - bool HasBOM() const { - return _writeBOM; - } - /** Sets whether to write the BOM when writing the file. - */ - void SetBOM( bool useBOM ) { - _writeBOM = useBOM; - } - - /** Return the root element of DOM. Equivalent to FirstChildElement(). - To get the first node, use FirstChild(). - */ - XMLElement* RootElement() { - return FirstChildElement(); - } - const XMLElement* RootElement() const { - return FirstChildElement(); - } - - /** Print the Document. If the Printer is not provided, it will - print to stdout. If you provide Printer, this can print to a file: - @verbatim - XMLPrinter printer( fp ); - doc.Print( &printer ); - @endverbatim - - Or you can use a printer to print to memory: - @verbatim - XMLPrinter printer; - doc.Print( &printer ); - // printer.CStr() has a const char* to the XML - @endverbatim - */ - void Print( XMLPrinter* streamer=0 ) const; - virtual bool Accept( XMLVisitor* visitor ) const override; - - /** - Create a new Element associated with - this Document. The memory for the Element - is managed by the Document. - */ - XMLElement* NewElement( const char* name ); - /** - Create a new Comment associated with - this Document. The memory for the Comment - is managed by the Document. - */ - XMLComment* NewComment( const char* comment ); - /** - Create a new Text associated with - this Document. The memory for the Text - is managed by the Document. - */ - XMLText* NewText( const char* text ); - /** - Create a new Declaration associated with - this Document. The memory for the object - is managed by the Document. - - If the 'text' param is null, the standard - declaration is used.: - @verbatim - - @endverbatim - */ - XMLDeclaration* NewDeclaration( const char* text=0 ); - /** - Create a new Unknown associated with - this Document. The memory for the object - is managed by the Document. - */ - XMLUnknown* NewUnknown( const char* text ); - - /** - Delete a node associated with this document. - It will be unlinked from the DOM. - */ - void DeleteNode( XMLNode* node ); - - /// Clears the error flags. - void ClearError(); - - /// Return true if there was an error parsing the document. - bool Error() const { - return _errorID != XML_SUCCESS; - } - /// Return the errorID. - XMLError ErrorID() const { - return _errorID; - } - const char* ErrorName() const; - static const char* ErrorIDToName(XMLError errorID); - - /** Returns a "long form" error description. A hopefully helpful - diagnostic with location, line number, and/or additional info. - */ - const char* ErrorStr() const; - - /// A (trivial) utility function that prints the ErrorStr() to stdout. - void PrintError() const; - - /// Return the line where the error occurred, or zero if unknown. - int ErrorLineNum() const - { - return _errorLineNum; - } - - /// Clear the document, resetting it to the initial state. - void Clear(); - - /** - Copies this document to a target document. - The target will be completely cleared before the copy. - If you want to copy a sub-tree, see XMLNode::DeepClone(). - - NOTE: that the 'target' must be non-null. - */ - void DeepCopy(XMLDocument* target) const; - - // internal - char* Identify( char* p, XMLNode** node, bool first ); - - // internal - void MarkInUse(const XMLNode* const); - - virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const override{ - return 0; - } - virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const override{ - return false; - } - -private: - XMLDocument( const XMLDocument& ); // not supported - void operator=( const XMLDocument& ); // not supported - - bool _writeBOM; - bool _processEntities; - XMLError _errorID; - Whitespace _whitespaceMode; - mutable StrPair _errorStr; - int _errorLineNum; - char* _charBuffer; - int _parseCurLineNum; - int _parsingDepth; - // Memory tracking does add some overhead. - // However, the code assumes that you don't - // have a bunch of unlinked nodes around. - // Therefore it takes less memory to track - // in the document vs. a linked list in the XMLNode, - // and the performance is the same. - DynArray _unlinked; - - MemPoolT< sizeof(XMLElement) > _elementPool; - MemPoolT< sizeof(XMLAttribute) > _attributePool; - MemPoolT< sizeof(XMLText) > _textPool; - MemPoolT< sizeof(XMLComment) > _commentPool; - - static const char* _errorNames[XML_ERROR_COUNT]; - - void Parse(); - - void SetError( XMLError error, int lineNum, const char* format, ... ); - - // Something of an obvious security hole, once it was discovered. - // Either an ill-formed XML or an excessively deep one can overflow - // the stack. Track stack depth, and error out if needed. - class DepthTracker { - public: - explicit DepthTracker(XMLDocument * document) { - this->_document = document; - document->PushDepth(); - } - ~DepthTracker() { - _document->PopDepth(); - } - private: - XMLDocument * _document; - }; - void PushDepth(); - void PopDepth(); - - template - NodeType* CreateUnlinkedNode( MemPoolT& pool ); -}; - -template -inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT& pool ) -{ - TIXMLASSERT( sizeof( NodeType ) == PoolElementSize ); - TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() ); - NodeType* returnNode = new (pool.Alloc()) NodeType( this ); - TIXMLASSERT( returnNode ); - returnNode->_memPool = &pool; - - _unlinked.Push(returnNode); - return returnNode; -} - -/** - A XMLHandle is a class that wraps a node pointer with null checks; this is - an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 - DOM structure. It is a separate utility class. - - Take an example: - @verbatim - - - - - - - @endverbatim - - Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very - easy to write a *lot* of code that looks like: - - @verbatim - XMLElement* root = document.FirstChildElement( "Document" ); - if ( root ) - { - XMLElement* element = root->FirstChildElement( "Element" ); - if ( element ) - { - XMLElement* child = element->FirstChildElement( "Child" ); - if ( child ) - { - XMLElement* child2 = child->NextSiblingElement( "Child" ); - if ( child2 ) - { - // Finally do something useful. - @endverbatim - - And that doesn't even cover "else" cases. XMLHandle addresses the verbosity - of such code. A XMLHandle checks for null pointers so it is perfectly safe - and correct to use: - - @verbatim - XMLHandle docHandle( &document ); - XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement(); - if ( child2 ) - { - // do something useful - @endverbatim - - Which is MUCH more concise and useful. - - It is also safe to copy handles - internally they are nothing more than node pointers. - @verbatim - XMLHandle handleCopy = handle; - @endverbatim - - See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. -*/ -class TINYXML2_LIB XMLHandle -{ -public: - /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. - explicit XMLHandle( XMLNode* node ) : _node( node ) { - } - /// Create a handle from a node. - explicit XMLHandle( XMLNode& node ) : _node( &node ) { - } - /// Copy constructor - XMLHandle( const XMLHandle& ref ) : _node( ref._node ) { - } - /// Assignment - XMLHandle& operator=( const XMLHandle& ref ) { - _node = ref._node; - return *this; - } - - /// Get the first child of this handle. - XMLHandle FirstChild() { - return XMLHandle( _node ? _node->FirstChild() : 0 ); - } - /// Get the first child element of this handle. - XMLHandle FirstChildElement( const char* name = 0 ) { - return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 ); - } - /// Get the last child of this handle. - XMLHandle LastChild() { - return XMLHandle( _node ? _node->LastChild() : 0 ); - } - /// Get the last child element of this handle. - XMLHandle LastChildElement( const char* name = 0 ) { - return XMLHandle( _node ? _node->LastChildElement( name ) : 0 ); - } - /// Get the previous sibling of this handle. - XMLHandle PreviousSibling() { - return XMLHandle( _node ? _node->PreviousSibling() : 0 ); - } - /// Get the previous sibling element of this handle. - XMLHandle PreviousSiblingElement( const char* name = 0 ) { - return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); - } - /// Get the next sibling of this handle. - XMLHandle NextSibling() { - return XMLHandle( _node ? _node->NextSibling() : 0 ); - } - /// Get the next sibling element of this handle. - XMLHandle NextSiblingElement( const char* name = 0 ) { - return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 ); - } - - /// Safe cast to XMLNode. This can return null. - XMLNode* ToNode() { - return _node; - } - /// Safe cast to XMLElement. This can return null. - XMLElement* ToElement() { - return ( _node ? _node->ToElement() : 0 ); - } - /// Safe cast to XMLText. This can return null. - XMLText* ToText() { - return ( _node ? _node->ToText() : 0 ); - } - /// Safe cast to XMLUnknown. This can return null. - XMLUnknown* ToUnknown() { - return ( _node ? _node->ToUnknown() : 0 ); - } - /// Safe cast to XMLDeclaration. This can return null. - XMLDeclaration* ToDeclaration() { - return ( _node ? _node->ToDeclaration() : 0 ); - } - -private: - XMLNode* _node; -}; - - -/** - A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the - same in all regards, except for the 'const' qualifiers. See XMLHandle for API. -*/ -class TINYXML2_LIB XMLConstHandle -{ -public: - explicit XMLConstHandle( const XMLNode* node ) : _node( node ) { - } - explicit XMLConstHandle( const XMLNode& node ) : _node( &node ) { - } - XMLConstHandle( const XMLConstHandle& ref ) : _node( ref._node ) { - } - - XMLConstHandle& operator=( const XMLConstHandle& ref ) { - _node = ref._node; - return *this; - } - - const XMLConstHandle FirstChild() const { - return XMLConstHandle( _node ? _node->FirstChild() : 0 ); - } - const XMLConstHandle FirstChildElement( const char* name = 0 ) const { - return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 ); - } - const XMLConstHandle LastChild() const { - return XMLConstHandle( _node ? _node->LastChild() : 0 ); - } - const XMLConstHandle LastChildElement( const char* name = 0 ) const { - return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 ); - } - const XMLConstHandle PreviousSibling() const { - return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); - } - const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const { - return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); - } - const XMLConstHandle NextSibling() const { - return XMLConstHandle( _node ? _node->NextSibling() : 0 ); - } - const XMLConstHandle NextSiblingElement( const char* name = 0 ) const { - return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 ); - } - - - const XMLNode* ToNode() const { - return _node; - } - const XMLElement* ToElement() const { - return ( _node ? _node->ToElement() : 0 ); - } - const XMLText* ToText() const { - return ( _node ? _node->ToText() : 0 ); - } - const XMLUnknown* ToUnknown() const { - return ( _node ? _node->ToUnknown() : 0 ); - } - const XMLDeclaration* ToDeclaration() const { - return ( _node ? _node->ToDeclaration() : 0 ); - } - -private: - const XMLNode* _node; -}; - - -/** - Printing functionality. The XMLPrinter gives you more - options than the XMLDocument::Print() method. - - It can: - -# Print to memory. - -# Print to a file you provide. - -# Print XML without a XMLDocument. - - Print to Memory - - @verbatim - XMLPrinter printer; - doc.Print( &printer ); - SomeFunction( printer.CStr() ); - @endverbatim - - Print to a File - - You provide the file pointer. - @verbatim - XMLPrinter printer( fp ); - doc.Print( &printer ); - @endverbatim - - Print without a XMLDocument - - When loading, an XML parser is very useful. However, sometimes - when saving, it just gets in the way. The code is often set up - for streaming, and constructing the DOM is just overhead. - - The Printer supports the streaming case. The following code - prints out a trivially simple XML file without ever creating - an XML document. - - @verbatim - XMLPrinter printer( fp ); - printer.OpenElement( "foo" ); - printer.PushAttribute( "foo", "bar" ); - printer.CloseElement(); - @endverbatim -*/ -class TINYXML2_LIB XMLPrinter : public XMLVisitor -{ -public: - /** Construct the printer. If the FILE* is specified, - this will print to the FILE. Else it will print - to memory, and the result is available in CStr(). - If 'compact' is set to true, then output is created - with only required whitespace and newlines. - */ - XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); - virtual ~XMLPrinter() {} - - /** If streaming, write the BOM and declaration. */ - void PushHeader( bool writeBOM, bool writeDeclaration ); - /** If streaming, start writing an element. - The element must be closed with CloseElement() - */ - void OpenElement( const char* name, bool compactMode=false ); - /// If streaming, add an attribute to an open element. - void PushAttribute( const char* name, const char* value ); - void PushAttribute( const char* name, int value ); - void PushAttribute( const char* name, unsigned value ); - void PushAttribute( const char* name, int64_t value ); - void PushAttribute( const char* name, uint64_t value ); - void PushAttribute( const char* name, bool value ); - void PushAttribute( const char* name, double value ); - /// If streaming, close the Element. - virtual void CloseElement( bool compactMode=false ); - - /// Add a text node. - void PushText( const char* text, bool cdata=false ); - /// Add a text node from an integer. - void PushText( int value ); - /// Add a text node from an unsigned. - void PushText( unsigned value ); - /// Add a text node from a signed 64bit integer. - void PushText( int64_t value ); - /// Add a text node from an unsigned 64bit integer. - void PushText( uint64_t value ); - /// Add a text node from a bool. - void PushText( bool value ); - /// Add a text node from a float. - void PushText( float value ); - /// Add a text node from a double. - void PushText( double value ); - - /// Add a comment - void PushComment( const char* comment ); - - void PushDeclaration( const char* value ); - void PushUnknown( const char* value ); - - virtual bool VisitEnter( const XMLDocument& /*doc*/ ) override; - virtual bool VisitExit( const XMLDocument& /*doc*/ ) override { - return true; - } - - virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) override; - virtual bool VisitExit( const XMLElement& element ) override; - - virtual bool Visit( const XMLText& text ) override; - virtual bool Visit( const XMLComment& comment ) override; - virtual bool Visit( const XMLDeclaration& declaration ) override; - virtual bool Visit( const XMLUnknown& unknown ) override; - - /** - If in print to memory mode, return a pointer to - the XML file in memory. - */ - const char* CStr() const { - return _buffer.Mem(); - } - /** - If in print to memory mode, return the size - of the XML file in memory. (Note the size returned - includes the terminating null.) - */ - size_t CStrSize() const { - return _buffer.Size(); - } - /** - If in print to memory mode, reset the buffer to the - beginning. - */ - void ClearBuffer( bool resetToFirstElement = true ) { - _buffer.Clear(); - _buffer.Push(0); - _firstElement = resetToFirstElement; - } - -protected: - virtual bool CompactMode( const XMLElement& ) { return _compactMode; } - - /** Prints out the space before an element. You may override to change - the space and tabs used. A PrintSpace() override should call Print(). - */ - virtual void PrintSpace( int depth ); - virtual void Print( const char* format, ... ); - virtual void Write( const char* data, size_t size ); - virtual void Putc( char ch ); - - inline void Write(const char* data) { Write(data, strlen(data)); } - - void SealElementIfJustOpened(); - bool _elementJustOpened; - DynArray< const char*, 10 > _stack; - -private: - /** - Prepares to write a new node. This includes sealing an element that was - just opened, and writing any whitespace necessary if not in compact mode. - */ - void PrepareForNewNode( bool compactMode ); - void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. - - bool _firstElement; - FILE* _fp; - int _depth; - int _textDepth; - bool _processEntities; - bool _compactMode; - - enum { - ENTITY_RANGE = 64, - BUF_SIZE = 200 - }; - bool _entityFlag[ENTITY_RANGE]; - bool _restrictedEntityFlag[ENTITY_RANGE]; - - DynArray< char, 20 > _buffer; - - // Prohibit cloning, intentionally not implemented - XMLPrinter( const XMLPrinter& ); - XMLPrinter& operator=( const XMLPrinter& ); -}; - - -} // namespace tinyxml2 - -#if defined(_MSC_VER) -# pragma warning(pop) -#endif - -#endif // TINYXML2_INCLUDED diff --git a/CHANGELOG.rst b/CHANGELOG.rst deleted file mode 100644 index d469d9e1a..000000000 --- a/CHANGELOG.rst +++ /dev/null @@ -1,1123 +0,0 @@ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Changelog for package behaviortree_cpp -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -4.9.0 (2026-02-11) ------------------- -* Fix Blackboard thread-safety: 6 data races fixed, use shared_mutex for storage -* Fix XML parser null pointer dereference in loadSubtreeModel on missing SubTree ID -* Add TryCatch control node for try/catch recovery patterns -* Fix `#1111 `_: EntryUpdatedDecorator::halt() not halting its child (`#1112 `_) -* Add polymorphic shared_ptr port support (`#943 `_) (`#1107 `_) -* Fix `std::from_chars` compilation on older g++ versions (`#1110 `_) -* Fix clang-tidy warnings across tests, examples, and samples (`#1109 `_) -* Add exception tracking with node backtrace (`#990 `_) (`#1106 `_) -* Fix `#861 `_ -* Fix `#917 `_: add comments about preconditions -* Fix missing read_parameter_from_ports initialization in DelayNode (`#1103 `_) -* Fix `#880 `_: createTreeFromText now finds previously registered subtrees (`#1105 `_) -* Remove lexy dependency, replace with hand-written tokenizer and Pratt parser (`#1099 `_) -* Fix `#953 `_: getInput() now uses stored converter for plugin custom types (`#1104 `_) -* Improve test suite quality and coverage (`#1102 `_) -* Fix Groot2Publisher destructor infinite loop (`#1057 `_) (`#1100 `_) -* Fix misleading static_assert when extra args have wrong type (`#837 `_) (`#1098 `_) -* Fix DelayNode ignoring delay_msec when created from XML (`#1097 `_) -* Fix Windows build issues (`#762 `_, `#869 `_, `#836 `_) (`#1089 `_) -* Fix `#989 `_: JsonExporter use-after-move in vector converter registration (`#1090 `_) -* Fix `#672 `_: reject deeply-nested/recursive XML to prevent stack overflow (`#1091 `_) -* Fix `#930 `_: mock substitution hangs when TestNodeConfigs is absent (`#1086 `_) -* Detect recursive subtree cycles at parse time (`#979 `_) (`#1085 `_) -* Fix `#1046 `_: use-after-free when factory destroyed before tree (`#1081 `_) -* Fix `#934 `_: segfault when substituting a SubTree node (`#1083 `_) -* Fix `#937 `_: enable returning BehaviorTreeFactory by value (`#1082 `_) -* Add vcpkg installation instructions (`#421 `_) -* Fix `#942 `_: getLockedPortContent creates entry for default-remapped ports (`#1078 `_) -* Add code coverage CI with Codecov, Coveralls, Codacy, and SonarCloud (`#1068 `_) -* Fix Groot2Publisher destructor infinite loop (`#1058 `_) -* Remove deprecated `std::aligned_storage` (`#1061 `_) -* Add regression test for `#1065 `_: subtree string literal to LoopDouble (`#1072 `_) -* Add regression test for `#858 `_: getInput with default port value (`#1076 `_) -* Add regression test for `#832 `_: script compare with negative number (`#1071 `_) -* Add regression test for `#923 `_: ValidateScript OOB read with large scripts (`#1070 `_) -* Fix `#948 `_: parseString supports enums with convertFromString specializations (`#1075 `_) -* Fix `#982 `_: handle json: prefix in vector convertFromString specializations (`#1073 `_) -* Fix `#408 `_: debugMessage shows type info for remapped subtree entries (`#1079 `_) -* Fix `#969 `_: LoopNode accepts std::vector in addition to SharedQueue (`#1074 `_) -* Fix `#1029 `_: correct left-associativity for arithmetic operators in script parser (`#1069 `_) -* Generate .clangd in PROJECT_SOURCE_DIR for submodule/FetchContent support (`#1059 `_) -* Contributors: Christoph Hertzberg, Copilot, Davide Faconti, Frank, Vincent PALANCHER, alvintps, dependabot[bot] - -4.8.4 (2026-01-09) ------------------- -* extend the Groot example to reproduce issues with arrays -* add tool to generate XML models -* add documentation to classes -* sort includes with clang format -* add new name validation rules -* add claude file -* detect duplicated instance names -* cleanup doc -* add contributors guide -* move and cleanup tests -* Contributors: Davide Faconti - -4.8.3 (2025-12-29) ------------------- -* minor change -* remove nolint -* Entry should be non copyable -* miscellaneus -* fix -* run clang tidy in CI -* fix remaining warnings -* apply the rulke of 5 -* fix compilation in c++17 -* add clang tidy and fix warnings -* update copyright year -* add unit test -* fix multiple issues with SimpleString -* Merge pull request `#1043 `_ from uilianries/fix/cppzmq-visibility - [fix] Make cppzmq as public dependency to avoid linkage errors for tools -* Turn cppzmq dependency public -* Restore Star History and add Contributors section - Reintroduced the Star History section and added Contributors section to the README. -* Update copyright year in README.md -* Contributors: Davide Faconti, Uilian Ries - -4.8.2 (2025-10-30) ------------------- -* Merge pull request `#996 `_ from EnjoyRobotics/make-sequence-node-inheritable -* Merge branch 'master' of github.com:BehaviorTree/BehaviorTree.CPP -* fix issue `#1034 `_ -* Merge pull request `#1030 `_ from pleemann/tree_wake_up - Event-based tree ticking -* force tinyxml2_vendor in ROS2. See `#1033 `_ and `#1028 `_ -* added Tree::emitWakeUpSignal -* Lint -* Propagate node config to parent -* Make tick method protected -* Contributors: Davide Faconti, pleemann, redvinaa - -4.8.1 (2025-10-23) ------------------- - -4.8.0 (2025-10-14) ------------------- -* fix issue in destruction order -* fix memory leak -* fix thread safety issues -* Improve error message -* Leave a note for posterity -* Fix windows builds -* Do not fail fast. We want results of both sanitizer runs -* Combine sanitizer actions into a single file -* use gtest_discover_tests to regiester the unit tests - this modern approach registers many individual tests instead of a single monolitic test - so if one fails the rest continue running which allows the developer to flag multiple - failing tests on a single run - It also speeds up testing since tests run in parallel -* Add support for sanitizers including some GHAs -* Remove unused conan.cmake (`#1016 `_) -* Improve handling of dependencies (`#1012 `_) -* update tinyxml to version 11.0 -* fix potential compilation errors -* compile for c++ 17 (`#1013 `_) -* Contributors: Davide Faconti, Eric Riff - -4.7.3 (2025-10-01) ------------------- -* remove cpp-sqlite -* update cppzmq to 4.11.0 -* remove wildcards from 3rd party -* Clean up VerifyXML logic (`#1000 `_) - * Refactor VerifyXML to clarify logic - - Reduces duplication in VerifyXML by handling the ID check for built-in - node types up front so they can then be definitively looked up in the - registered nodes. - - Enhances error messaging in VerifyXML by using *either* the node name - *or* the ID, depending on which is appropriate, instead of leaving - users guessing "which Decorator is wrong" - - Fixes custom Action and Condition nodes using shorthand syntax not - being properly verified - - Fixes `` not being verified with the - same logic as `` - - Fixes `` not triggering a behavior lookup when - `` would. - * fix tests that were failing due to bad assumptions -* Append SQLite3_INCLUDE_DIRS to BTCPP_EXTRA_INCLUDE_DIRS, otherwise sqlite3.h won't be found (`#1002 `_) - Co-authored-by: alejandro.suarez@omron.com -* fix: use dynamically growing error buffer in ParseScript (`#1007 `_) - * fix: use dynamically growing error buffer in ParseScript - * style: format code - * fix: use dynamically growing error buffer in ValidateScript - --------- - Co-authored-by: ahuo -* fix: validate __type field before accessing in fromJson (`#1009 `_) - Co-authored-by: ahuo -* fix: check path attribute before using (`#1005 `_) - Co-authored-by: ahuo -* Set current_child_idx of SequenceNode protected (`#991 `_) -* Add convertFromString> (`#992 `_) -* Update README.md fix `#985 `_ - Duuuude -* fix: exclude 3rd party libraries from sonar issue tracking (`#984 `_) -* change CI file -* Contributors: Alejandro SuÃĄrez, Davide Faconti, Ezra Brooks, Marcus Ebner von Eschenbach, Shaur(ya) Kumar, Vince Reda, Yiyi Wang - -4.7.2 (2025-05-29) ------------------- -* Fix issue `#978 `_ : skipped was not working properly -* Added codespell as a pre-commit hook. (`#977 `_) -* fix: Make impossible to accidentally copy JsonExporter singleton (`#975 `_) -* Contributors: Davide Faconti, Leander Stephen D'Souza, tony-p - -4.7.1 (2025-05-13) ------------------- -* fix ROS CI -* Add action to publish Doxygen documentation as GH Page (`#972 `_) -* Update Doxyfile -* Make BT::Any::copyInto const (`#970 `_) -* more changes related to TestNode -* Contributors: David Sobek, Davide Faconti, Marcus Ebner von Eschenbach - -4.7.0 (2025-04-24) ------------------- -* change TestNodeConfig preferred constructor -* Fix dangling‐capture in TestNodeConfig -* Fix Precondition to only check condition once (`#904 `_) -* fix issue 945 -* extend JSON conversion to include vectors (`#965 `_) -* Fix CI, add BUILD_TESTS and remove catkin support -* Fix testing CMake issue to resolve Rolling regression (`#961 `_) -* Bug fix/set blackboard (`#955 `_) -* feat: add fuzzing harnesses (`#925 `_) -* fix warnings -* Add const to applyVisitor (`#935 `_) -* try fix (`#941 `_) -* add workflow for sonarcube (`#936 `_) -* Fix issue `#909 `_: static queue in Loop -* apply changes suggested in `#893 `_ -* apply fix mentioned in `#916 `_ -* apply fixes suggested in `#919 `_ -* fix issue `#918 `_ (introduced in `#885 `_) -* add fix suggested in `#920 `_ -* add unit test related to `#931 `_ -* Fix compilation error when targeting C++23 (`#926 `_) ^~~~~~~~~~~~~ -* Fixes issue # `#929 `_ and `#921 `_ -* apply check suggested in `#924 `_ -* Fix ROS 2 build when ZeroMQ or SQlite3 include are not in the default include path (`#911 `_) - * Fix ROS 2 build when ZeroMQ or SQlite3 include are not in the default include path - * Update ament_build.cmake -* Fix/use correct compiler pixi/conda (`#914 `_) - * fix: Use the cxx-compiler package which will set the correct compiler for the platform, and setup the required environment for it to work as expected - * misc: update pixi versions in pipeline -* Add "other ports" to NodeConfig (`#910 `_) -* [retry_node] Refresh max_attempts\_ in case it changed (`#905 `_) - Co-authored-by: Guillaume Doisy -* use relative path in .Doxyfile (`#882 `_) -* Additional XML verification for ReactiveSequence nodes (`#885 `_) - Co-authored-by: AndyZe -* fix script parse error while 'A==-1' (`#896 `_) - Co-authored-by: wangzheng -* Expose return value of wait_for (`#887 `_) -* fix(examples): update t11_groot_howto log filename (`#886 `_) -* put minitrace in the build_interface link library (`#874 `_) - fixes the cmake export set when building behavior tree on standard cmake: CMake Error: install(EXPORT "behaviortree_cppTargets" ...) includes target "behaviortree_cpp" which requires target "minitrace" that is not in any export set. -* Improved XML parsing error message to say where in the XML the offending port is found. (`#876 `_) - Example output: - a port with name [ball_pose] is found in the XML (, line 7) but not in the providedPorts() of its registered node type. -* Refactored the TreeNode::executeTick() function to use a scoped timer for performance monitoring. (`#861 `_) (`#863 `_) - Update src/tree_node.cpp - Co-authored-by: wangzheng - Co-authored-by: Davide Faconti -* fix issue `#852 `_: thread safety in Loggers -* Lexy updated -* tinyXML updated to version 10.0 -* cppzmq updated to version 4.10 -* fix the "all_skipped" logic -* fixed: support utf-8 path xml-file (`#845 `_) - * fixed: 1. added compile version check to support Chinese path xml-file parsing 2. cmake add msvc /utf-8 options - * change cmake /utf-8 option add mode -* Export plugins to share directory & register CrossDoor plugin (`#804 `_) -* Contributors: Aglargil, AndyZe, Antoine Hoarau, David Sobek, Davide Faconti, Guillaume Doisy, Isar Meijer, Jake Keller, Marq Rasmussen, Michele Tartari, Silvio Traversaro, Tony Najjar, b-adkins, ckrah, devis12, kinly, tony-p, vincent-hui - -4.6.2 (2024-06-26) ------------------- -* Initialize template variable `T out` (`#839 `_) -* Building with a recent compiler fails due incompatible expected library (`#833 `_) - * nonstd::expected updated to 0.8 -* fix issue `#829 `_: support again custom JSON converters -* fix issue `#834 `_: enable minitrace -* allow multiple instances of the loggers -* fix issue `#827 `_ : verify name -* add TickMonitorCallback -* Fix typo in FallbackNode constructor parameter name (`#830 `_) -* fix segfault and throw instead when manifest is nullptr -* Add in call to ament_export_targets. (`#826 `_) -* Contributors: Davide Faconti, S. Messerschmidt, Sharmin Ramli, avikus-seonghyeon.kwon - -4.6.1 (2024-05-20) ------------------- -* remove flatbuffers from public API and old file_logger -* fix issue `#824 `_: use global in Blackboard::set -* Add test for setting a global blackboard entry using a node's output port `#823 `_ -* examples renamed -* Contributors: Davide Faconti, Robin MÃŧller - -4.6.0 (2024-04-28) ------------------- -* add tutorial 19 about the global blackboard -* renamed examples to match website -* Update TestNode and the corresponding tutorial -* bug fixes related to sequence_id and unit tests added -* Add string concatenation operator to scripting (`#802 `_) -* Add library alias for BT::behaviortree_cpp (`#808 `_) -* add Time Stamped blackboard (`#805 `_) -* add additional information and functionality to SQLiteLogger -* add syntax for entries in the root blackboard ("@" prefix) -* Fix/pixi build (`#791 `_) -* fix unit tests in Windows -* fix windows compilation -* Update cmake_windows.yml -* Deprecate Balckboard::clear(). Issue `#794 `_ -* Support string vector conversion for ports (`#790 `_) -* add more convertToString for integers -* warn about overwritten enums -* fix ambiguous to_json -* Extend unit test for blackboard backup to run the second tree (`#789 `_) -* json conversion changed and -* issue `#755 `_ : add backchaining test and change reactive nodes checks (`#770 `_) -* Update switch_node.h -* test moved and port remapping fixed -* Create pull_request_template.md - -* adding pre-commit -* handle enums conversions is assignment -* Contributors: Davide Faconti, Sean Geles, Sebastian Castro, Victor MassaguÊ Respall, avikus-seonghyeon.kwon, tony-p - -4.5.2 (2024-03-07) ------------------- -* bugfix: string to enum/integer/boolean in scripts -* bug fix in scripting comparison -* added more pretty-prints to demangler -* fixes and checks in default values, based on PR `#773 `_ -* Initialize std::atomic_bool (`#772 `_) -* Fix issue `#767 `_ and `#768 `_ -* updated default port syntax: "{=}" -* new default port capability: blackbard entries -* fix issue `#757 `_ : skipped nodes should not call post-condition ALWAYS -* Merge pull request `#756 `_ from imere/imere-patch-1 -* fix(test): Typo in gtest_blackboard.cpp -* Contributors: Davide Faconti, Lu Z, Marq Rasmussen - -4.5.1 (2024-01-23) ------------------- -* Support enums and real numbers in Node Switch -* improve Any::castPtr and add example -* fix issue `#748 `_ : static error messages -* Merge pull request `#746 `_ from galou/snprintf - Use snprintf instead of sprintf -* Use snprintf instead of sprintf - - Augment the buffer size on doc error. - - Let sprintf in switch_node.h since the max. string length is known. -* Contributors: Davide Faconti, GaÃĢl Écorchard - -4.5.0 (2024-01-10) ------------------- -* fix typo in unit test `#733 `_ -* allow Input/Output ports with type Any -* Merge pull request `#703 `_ from galou/export_xsd - Implement writeTreeXSD() to generate an XSD -* Any::isType() will return the original type. Cherry picking from `#708 `_ -* fix `#734 `_ -* remove unneeded includes -* add Any::castPtr -* add alias KeyValueVector -* Merge pull request `#730 `_ from adlarkin/add_metadata - Add optional metadata to TreeNodeManifest -* Contributors: Ashton Larkin, Davide Faconti, GaÃĢl Écorchard - -4.4.3 (2023-12-19) ------------------- -* Merge pull request #709 from galou/unset_blackboard -* fix issue `#725 `_ : SetBlackboard can copy entries -* add more unit tests -* fix typos `#721 `_ -* fix: guard macro declaration to prevent redefinition warning -* fix: Rename scoped lock so it doesn't hide the outer lock triggering a compiler warning -* add private ports to exclude from autoremapping `#706 `_ -* fix issue `#713 `_: getNodesByPath should be const -* Contributors: Davide Faconti, Nestor Gonzalez, Tony Paulussen - -4.4.2 (2023-11-28) ------------------- -* fix issue `#702 `_ : output ports require {} -* Merge pull request `#691 `_ from galou/small_refactor_and_doc - Small code refactor, log- and doc changes -* Merge pull request `#701 `_ from tony-p/fix/file-loggers-protected - fix: ensure public get config overload is used -* ci: use pixi github action -* fix: ensure public get config overload is used -* Small code refactor, log- and doc changes -* Contributors: Davide Faconti, GaÃĢl Écorchard, Tony Paulussen - -4.4.1 (2023-11-12) ------------------- -* erase server_port+1 -* add reset by default in base classes (fix `#694 `_) -* fix issue `#696 `_ (wrong autoremapping) -* Remove traces of SequenceStar -* fix `#685 `_ (timeout in ZMP publisher) -* clang: fix warning - fix warning: lambda capture 'this' is not used -* Use feature test macro to check availability of `std::from_chars` -* fix warning in older compilers -* Contributors: Christoph Hertzberg, Davide Faconti, GaÃĢl Écorchard, Shen Xingjian, Sid - -4.4.0 (2023-10-16) ------------------- -* Update ex05_subtree_model.cpp -* added any::stringToNumber -* added SubTree model example -* unit test for issue 660 -* adding SubTree model -* minor changes -* change blackboard entry -* Update simple_string.hpp -* SimpleString: fix warning by checking upper size limit (`#666 `_) -* Contributors: Adam Boseley, Davide Faconti - -4.3.8 (2023-10-09) ------------------- -* ReactiveSequence and ReactiveFallback will behave more similarly to 3.8 -* bug fix in wakeUpSignal -* ignore newlines in script -* stop ordering ports in TreeNodesModel -* add a specific tutorial for plugins -* Contributors: Davide Faconti - -4.3.7 (2023-09-12) ------------------- -* Test and fix issue `#653 `_: AnyTypeAllowed by default -* more time margin for Windows tests -* Add support for successful conda builds (`#650 `_) -* fix: Update how unit tests are executed in the github workflow so they are actually run on windows (`#647 `_) -* Add unit test related to SequenceWithMemory `#636 `_ -* Contributors: Davide Faconti, tony-p - -4.3.6 (2023-08-31) ------------------- -* Simplify the visualization of custom type in Groot2 and improved tutorial 12 -* fix compilation warnings -* Apply changes in ReactiveSequence to ReactiveFallback too -* test that logging works correctly with ReactiveSequence `#643 `_ -* reduce the number of times preconditions scripts are executed -* PauseWithRetry test added -* Contributors: Davide Faconti - -4.3.5 (2023-08-14) ------------------- -* fix issue `#621 `_: ConsumeQueue -* feat: add template specialization for convertFromString deque (`#628 `_) -* unit test added -* Update groot2_publisher.h (`#630 `_) -* unit test issue `#629 `_ -* WhileDoElseNode can have 2 or 3 children (`#625 `_) -* fix issue `#624 `_ : add TimeoutNode::halt() -* fix recording_fist_time issue on windows (`#618 `_) -* Contributors: Aglargil, Davide Faconti, Michael Terzer, benyamin saedi, muritane - -4.3.4 (2023-07-25) ------------------- -* Fix error #617 in TestNode -* minitrace updated -* fix issue #615 : don't execute preconditions if state is RUNNING -* README.md -* fix issue `#605 `_: strip whitespaces and better error message -* Export cxx-standard with target. (`#604 `_) -* feature `#603 `_: add static method [std::string description()] to manifest -* fix issue with move semantic -* Contributors: Davide Faconti, Sebastian Kasperski - -4.3.3 (2023-07-05) ------------------- -* bug fix `#601 `_: onHalted not called correctly in Control Nodes -* Groot recording (`#598 `_) - * add recording to groot publisher - * fixed - * protocols compatibility - * reply with first timestamp - * remove prints -* Fix error when building static library (`#599 `_) -* fix warnings -* 4.3.2 -* prepare release -* fix `#595 `_ : improvement in blackboard/scripting types (`#597 `_) -* Merge branch 'master' of github.com:BehaviorTree/BehaviorTree.CPP -* Merge branch 'parallel_all' -* Fix Issue 593 (`#594 `_): support skipping in Parallel node -* fix ParallelAll -* adding ParallelAll, WIP -* Contributors: Davide Faconti, Oleksandr Perepadia - -4.3.2 (2023-06-27) ------------------- -* fix `#595 `_ : improvement in blackboard/scripting types (`#597 `_) -* Fix Issue 593 (`#594 `_): support skipping in Parallel node -* adding ParallelAll -* Contributors: Davide Faconti - -4.3.1 (2023-06-21) ------------------- -* fix issue `#592 `_ -* use lambda in tutorial -* add script condition -* "fix" issue `#587 `_: ReactiveSequence should set conditions to IDLE -* better error message -* Fix issue `#585 `_ -* Contributors: Davide Faconti - -4.3.0 (2023-06-13) ------------------- -* use PImpl in multiple classes -* updated FileLogger2 -* better error messages -* blackboard refactoring to fix buggy _autoremap -* improved support for default values -* fix error and add nodiscard -* Fix `#580 `_ : more informative error when not specializing BT::toStr -* add builtin models to WriteTreeToXML -* add simple example to generate logs -* add Sleep Node -* Fix `#271 `_: better error message -* remove EOL ros2 from CI -* Contributors: Davide Faconti - -4.2.1 (2023-06-07) ------------------- -* Fix `#570 `_: string_view set in blackboard -* Fix missing attribute in generated XML (writeTreeNodesModelXML) -* Allow registration of TestNode -* Contributors: Davide Faconti, Oleksandr Perepadia - -4.2.0 (2023-05-23) ------------------- -* add more informative IDLE status -* more informative error message when trying to register virtual classes -* fixes and simpler getAnyLocked -* add Tree::getNodesByPath -* add FileLogger2 -* change getPortAny name and fic loop_node -* Lexy updated to release 2022.12.1 -* do not skip pre-post condition in substituted tick -* added Loop node -* deprecating getAny -* revert new behavior of Sequence and Fallback -* add resetChild to all the decorators that missed it -* Add test related to issue `#539 `_ -* related to `#555 `_ -* Critical bug fix in XML exporting -* Fix writeTreeNodesModelXML -* fix ament not registering executables as tests -* fix std::system_error in TimeoutNode -* minor changes, mostly comments -* add version string -* old ZMQ publisher removed -* Add RunOnce, based on `#472 `_ -* Contributors: Alberto Soragna, Davide Faconti, GaÃĢl Écorchard, Mithun Kinarullathil, Sergei Molchanov - -4.1.1 (2023-03-29) ------------------- -* adding sqlite logger -* fix warning -* better cmake -* ManualSelector removed -* magic_enum updated -* fix issue `#530 `_: use convertFromString in scripting assignments -* added unit test -* files moved -* fix groot2 publisher -* minor fixes in blackboard -* fix XML: Subtree should remember the remapped ports -* add the ability to load substitution rules from JSON -* Update README.md -* Contributors: Davide Faconti - -4.1.0 (2023-03-18) ------------------- -* temporary disable codeql -* Groot2 interface (`#528 `_) - * refactored groot2 interface - * protocol updated -* merging groot2 publisher -* add observer -* prepare 4.1 -* Update README.md -* fix issue `#525 `_ when ReactiveSequence contains skipped children -* fix reactive sequence (issue `#526 `_ and `#525 `_) -* better test -* add cast to ENUMS in ports -* changes ported from 4.1 -* fix samples -* better include paths -* Control node and Decorators RUNNING before first child -* blackboard: update getKeys and add mutex to scripting -* add [[nodiscard]] and some other minor changes -* add screenshot -* change the behavior of tickOnce to actually loop is wake up signal isâ€Ļ (`#522 `_) - * change the behavior of tickOnce to actually loop is wake up signal is received - * fix warning -* Cmake conan (`#521 `_) - * boost coroutine substituted with minicoro. 3rd party updates - * cmake refactoring + conan - * fix cmake - * fix build with conan and change CI -* fix CI in ROS1 (`#519 `_) -* fix alloc-dealloc-mismatch for _storage.str.data (`#518 `_) -* Fix issue `#515 `_: reactive sequence not skipped correctly -* Fix issue `#517 `_ -* Merge branch 'master' of github.com:BehaviorTree/BehaviorTree.CPP -* fix issue `#492 `_ (Threads::Threads) -* Fix boost dependency in package.xml (`#512 `_) - `libboost-coroutine-dev` has been merged into rosdistro on February 21st - 2023. Link to merge request: https://github.com/ros/rosdistro/pull/35789/. -* fix compilation -* revert breaking change -* Merge branch 'master' of github.com:BehaviorTree/BehaviorTree.CPP -* make default value of port optional, to allow empty strings -* Contributors: Alberto Soragna, Bart Keulen, Davide Faconti - -4.0.2 (2023-02-17) ------------------- -* fix issue `#501 `_ -* fix issue `#505 `_ -* solve issue `#506 `_ -* prevent useless exception catcking -* fix issue `#507 `_ -* adding the uid to the log to uniquely identify the nodes (`#502 `_) -* fix in SharedLibrary and cosmetic changes to the code -* using tinyxml ErrorStr() instead of ErrorName() to get more info about missing file (`#497 `_) -* Fixed use of ros_pkg for ROS1 applications (`#483 `_) -* Fix error message StdCoutLogger -> MinitraceLogger (`#495 `_) -* Fix boost dependency in package.xml (`#493 `_) - Co-authored-by: Bart Keulen -* support Enums in string conversion -* fix issue 489 -* updated example. Demonstrate pass by reference -* lexy updated -* rename haltChildren to resetChildren -* revert `#329 `_ -* Merge branch 'master' of github.com:BehaviorTree/BehaviorTree.CPP -* Small improvements (`#479 `_) - * Make message for allowed port names more explicit - Also throw an exception for unknown port direction rather than using - `PortDirection::INOUT`. - * Small code improvements - * Remove code without effect -* Fix some renaming for V4 (`#480 `_) -* Define NodeConfiguration for BT3 compatibility (`#477 `_) -* Implement `#404 `_ to solve `#435 `_ (gtest not found) -* fix issue `#474 `_ Make libraries dependencies private -* fix issue `#413 `_ (Delay logic) -* change suggested in `#444 `_ -* add XML converter -* Add CodeQL workflow (`#471 `_) -* Update README.md -* Contributors: Ana, Bart Keulen, Christian Henkel, Davide Faconti, GaÃĢl Écorchard, Jorge, Mahmoud Farshbafdoustar, Norawit Nangsue - -4.0.1 (2022-11-19) ------------------- -* version 4.X -* Contributors: Adam Aposhian, Adam Sasine, Alberto Soragna, Ali AydÄąn KÜÇÜKÇÖLLÜ, AndyZe, Davide Faconti, Dennis, GaÃĢl Écorchard, Jafar, Joseph Schornak, Luca Bonamini, Paul Bovbel, SubaruArai, Tim Clephas, Will - -3.7.0 (2022-05-23) ------------ -* add netlify stuff -* Event based trigger introduced - Added a new mechanism to emit "state changed" events that can "wake up" a tree. - In short, it just provide an interruptible "sleep" function. -* Fixed bug where including relative paths would fail to find the correct file (`#358 `_) - * Added unit tests to verify current behavior - * Fixed bug where including relative paths would fail to find the correct file - * Added gtest environment to access executable path - This path lets tests access files relative to the executable for better transportability - * Changed file commandto add_custom_target - The file command only copies during the cmake configure step. If source files change, file is not ran again -* Added pure CMake action to PR checks (`#378 `_) - * Added CMake CI to PR checks - * Renamed action to follow pattern -* updated documentation -* add the ability to register multiple BTs (`#373 `_) -* Update ros1.yaml -* fix `#338 `_ -* fix issue `#330 `_ -* fix issue `#360 `_ -* Merge branch 'master' of github.com:BehaviorTree/BehaviorTree.CPP -* Update Tutorial 2 Docuemtation (`#372 `_) -* Update tutorial_09_coroutines.md (`#359 `_) - Minor fix, renamed Timepoint to TimePoint. -* Export dependency on ament_index_cpp (`#362 `_) - To make dependent packages try to link ament_index_cpp, export the - dependency explicitly. -* Change order of lock to prevent deadlock. (`#368 `_) - Resolves `#367 `_. -* Fix `#320 `_ : forbid references in Any -* Update action_node.h -* Contributors: Adam Sasine, Davide Faconti, Fabian Schurig, Griswald Brooks, Hyeongsik Min, Robodrome, imgbot[bot], panwauu - -3.6.1 (2022-03-06) ------------------- -* remove windows tests -* fix thread safety -* fix CI -* Don't restart SequenceStar on halt (`#329 `_) - * Add more SequenceStar tests - * Fix typo in test name - * Don't reset SequenceStar on halt -* [docs] add missing node `SmashDoor` (`#342 `_) -* ROS2 include ros_pkg attribute support (`#351 `_) - * ROS2 include pkg support - * ros2 build fixed - Co-authored-by: Benjamin Linne -* [ImgBot] Optimize images (`#334 `_) - *Total -- 90.34kb -> 61.77kb (31.63%) - /docs/images/Tutorial1.svg -- 10.08kb -> 6.33kb (37.19%) - /docs/images/FetchBeerFails.svg -- 9.00kb -> 5.93kb (34.13%) - /docs/images/FetchBeer2.svg -- 21.19kb -> 14.41kb (32%) - /docs/images/Tutorial2.svg -- 34.19kb -> 23.75kb (30.54%) - /docs/images/DecoratorEnterRoom.svg -- 15.88kb -> 11.35kb (28.54%) - Co-authored-by: ImgBotApp -* [Docs] BT_basics fix typo (`#343 `_) -* [docs] Clarify sentence (`#344 `_) - `... will sleep up to 8 hours or less, if he/she is fully rested.` was not clear. It can also be understood as `If he/she is fully rested, the character will sleep ...` -* [docs] match text to graphics (`#340 `_) -* Docs: BT_basics fix typo (`#337 `_) -* Merge branch 'master' of github.com:BehaviorTree/BehaviorTree.CPP -* fix svg -* Fix CMake ENABLE_COROUTINES flag with Boost < 1.59 (`#335 `_) - Co-authored-by: Cam Fulton -* Add ENABLE_COROUTINES CMake option (`#316 `_) - * Add DISABLE_COROUTINES CMake option - * Change convention of CMake coroutine flag to ENABLE - Co-authored-by: Cam Fulton -* [ImgBot] Optimize images (`#333 `_) - *Total -- 152.97kb -> 114.57kb (25.1%) - /docs/images/ReactiveSequence.svg -- 7.58kb -> 4.59kb (39.47%) - /docs/images/SequenceNode.svg -- 11.28kb -> 7.12kb (36.87%) - /docs/images/SequenceStar.svg -- 11.22kb -> 7.09kb (36.8%) - /docs/images/DecoratorEnterRoom.svg -- 20.71kb -> 13.30kb (35.77%) - /docs/images/FallbackBasic.svg -- 19.09kb -> 12.64kb (33.79%) - /docs/images/FetchBeer.svg -- 24.30kb -> 16.36kb (32.66%) - /docs/images/SequenceBasic.svg -- 6.32kb -> 5.49kb (13.04%) - /docs/images/Tutorial1.svg -- 6.67kb -> 5.94kb (10.98%) - /docs/images/FetchBeerFails.svg -- 6.46kb -> 5.83kb (9.76%) - /docs/images/FetchBeer2.svg -- 14.99kb -> 13.76kb (8.18%) - /docs/images/Tutorial2.svg -- 24.35kb -> 22.44kb (7.85%) - Co-authored-by: ImgBotApp -* doc fix -* Merge branch 'new_doc' -* remove deprecated code -* updated documentation -* [Fix] Fix cmake version warning and -Wformat warning (`#319 `_) - Co-authored-by: Homalozoa -* Update README.md -* Fix Windows shared lib build (`#323 `_) -* fix shadowed variable in string_view.hpp (`#327 `_) -* Build Sample Nodes By Default to Fix Github Action (`#332 `_) - * Fix github action - * Change working directory in github action step - * Build samples by default -* Added BlackboardCheckBool decorator node (`#326 `_) - * Added tests for BlackboardCheck decorator node - * Added BlackboardCheckBool decorator node -* Fixed typo "Exeption" -> "Exception" (`#331 `_) -* WIP -* fix `#325 `_ -* Contributors: Adam Sasine, Affonso, Guilherme, Alberto Soragna, Davide Faconti, Homalozoa X, Jake Keller, Philippe Couvignou, Tobias Fischer, benjinne, fultoncjb, goekce, imgbot[bot] - -3.6.0 (2021-11-10) ------------------- -* Build samples independently of examples (`#315 `_) -* Fix dependency in package.xml (`#313 `_) -* Fix doc statement (`#309 `_) - Fix sentence -* Fix references to RetryUntilSuccesful (`#308 `_) - * Fix github action - * Fix references to RetryUntilSuccesful -* added subclass RetryNodeTypo (`#295 `_) - Co-authored-by: Subaru Arai -* Fix github action (`#302 `_) -* Minor spelling correction (`#305 `_) - Corrected `the_aswer` to `the_answer` -* Update FallbackNode.md (`#306 `_) - typo correction. -* Add signal handler for Windows (`#307 `_) -* fix -* file renamed and documentation fixed -* Update documentation for reactive sequence (`#286 `_) -* Update FallbackNode.md (`#287 `_) - Fix the pseudocode in the documentation of 'Reactive Fallback' according to its source code. -* Update fallback documentation to V3 (`#288 `_) - * Update FallbackNode.md description to V3 - * Fix typo -* Use pedantic for non MSVC builds (`#289 `_) -* Merge branch 'master' of https://github.com/BehaviorTree/BehaviorTree.CPP -* updated to latest flatbuffers -* Update README.md -* Fix issue `#273 `_ -* remove potential crash when an unfinished tree throws an exception -* remove appveyor -* Merge branch 'git_actions' -* Fixes for compilation on windows. (`#248 `_) - * Fix for detecting ZeroMQ on windows - Naming convention is a bit different for ZeroMQ, specifically on Windows with vcpkg. While ZMQ and ZeroMQ are valid on linux, the ZMQ naming convention only works on linux. - * Compilation on windows not working with /WX - * Macro collision on Windows - On windows, the macros defined in the abstract logger collides with other in windows.h. Made them lowercase to avoid collision -* Remove native support for Conan (`#280 `_) -* add github workflow -* Registered missing dummy nodes for examples (`#275 `_) - * Added CheckTemperature dummy node - * Added SayHello dummy node -* add zmq.hpp in 3rdparty dirfectory -* add test -* fix some warnings -* Fix bug on halt of delay node (`#272 `_) - - When DelayNode is halted and ticked again, it always returned FAILURE since the state of DelayNode was not properly reset. - - This commit fixes unexpected behavior of DelayNode when it is halted. - Co-authored-by: Jinwoo Choi -* Clear all of blackboard's content (`#269 `_) -* Added printTreeRecursively overload with ostream parameter (`#264 `_) - * Added overload to printTreeRecursively - * Changed include to iosfwd - * Added test to verify function writes to stream - * Added call to overload without stream parameter - * Fixed conversion error - * Removed overload in favor of default argument -* Fix typo (`#260 `_) - Co-authored-by: Francesco Vigni -* Update README.md -* abstract_logger.h: fixed a typo (`#257 `_) -* Contributors: Adam Sasine, Affonso, Guilherme, Akash, Billy, Cong Liu, Daisuke Nishimatsu, Davide Faconti, Francesco Vigni, Heben, Jake Keller, Per-Arne Andersen, Ross Weir, Steve Macenski, SubaruArai, Taehyeon, Uilian Ries, Yadu, Yuwei Liang, matthews-jca, swarajpeppermint - -3.5.6 (2021-02-03) ------------------- -* fix issue `#227 `_ -* fix issue `#256 `_ -* Merge branch 'master' of https://github.com/BehaviorTree/BehaviorTree.CPP -* fix issue `#250 `_ -* Fixed typos on SequenceNode.md (`#254 `_) -* Contributors: Davide Faconti, LucasNolasco - -3.5.5 (2021-01-27) ------------------- -* fix issue `#251 `_ -* Contributors: Davide Faconti - -3.5.4 (2020-12-10) ------------------- -* Update bt_factory.cpp (`#245 `_) -* Use the latest version of zmq.hpp -* Improved switching BTs with active Groot monitoring (ZMQ logger destruction) (`#244 `_) - * Skip 100ms (max) wait for detached thread - * add {} to single line if statements -* Update retry_node.cpp -* fix -* fix issue `#230 `_ -* Contributors: Davide Faconti, Florian Gramß, amangiat88 - -3.5.3 (2020-09-10) ------------------- -* fix issue `#228 `_ . Retry and Repeat node need to halt the child -* better tutorial -* Contributors: Davide Faconti - -3.5.2 (2020-09-02) ------------------- -* fix warning and follow coding standard -* docs: Small changes to tutorial 02 (`#225 `_) - Co-authored-by: Valerio Magnago -* Merge branch 'master' of https://github.com/BehaviorTree/BehaviorTree.CPP -* tutorial 1 fixed -* decreasing warning level to fix issue `#220 `_ -* fix compilation -* Allow BT factory to define clock source for TimerQueue/TimerNode (`#215 `_) - * Allow BT factory to define clock source for TimerQueue/TimerNode - * Fix unit tests - Co-authored-by: Cam Fulton - Co-authored-by: Davide Faconti -* Added delay node and wait for enter keypress node (`#182 `_) - * Added delay node and wait for enter press node - * Fixed unsigned int to int conversion bug - * Added a new timer to keep a track of delay timeout and return RUNNING in the meanwhile - * Removed wait for keypress node - * Review changes suggested by gramss - Co-authored-by: Indraneel Patil -* Update SequenceNode.md (`#211 `_) -* add failure threshold to parallel node with tests (`#216 `_) -* Update tutorial_05_subtrees.md - I believe that the API has been updated. Reflecting the same in this tutorial. -* Contributors: Aayush Naik, Davide Faconti, Indraneel Patil, Renan Salles, Valerio Magnago, Wuqiqi123, fultoncjb - -3.5.1 (2020-06-11) ------------------- -* trying to fix compilation in eloquent Minor fix on line 19 -* Update README.md -* more badges -* readme updated -* fix ros2 compilation? -* move to github actions -* replace dot by zero in boost version (`#197 `_) -* Always use std::string_view for binary compatibility (fix issue `#200 `_) -* Adding ForceRunningNode Decorator (`#192 `_) -* updated doc -* Add XML parsing support for custom Control Nodes (`#194 `_) -* Fix typo -* [Windows] Compare `std::type_info` objects to check type. (`#181 `_) -* Fix pseudocode for ReactiveFallback. (`#191 `_) -* Contributors: Aayush Naik, Darío HereÃąÃē, Davide Faconti, Francisco Martín Rico, G.Doisy, Sarathkrishnan Ramesh, Sean Yen, Ting Chang - -3.5.0 (2020-05-14) ------------------- -* added IfThenElse and WhileDoElse -* issue `#190 `_ -* unit test added -* reverting to a better solution -* RemappedSubTree added -* Fix issue `#188 `_ -* added function const std::string& key (issue `#183 `_) -* Contributors: Davide Faconti, daf@blue-ocean-robotics.com - -* added IfThenElse and WhileDoElse -* issue `#190 `_ -* unit test added -* reverting to a better solution -* RemappedSubTree added -* Fix issue `#188 `_ -* added function const std::string& key (issue `#183 `_) -* Contributors: Davide Faconti, daf@blue-ocean-robotics.com - -3.1.1 (2019-11-10) ------------------- -* fix samples compilation (hopefully) -* Contributors: Davide Faconti - -3.1.0 (2019-10-30) ------------------- -* Error message corrected -* fix windows and mingw compilation (?) -* Merge pull request `#70 `_ from Masadow/patch-3 - Added 32bits compilation configuration for msvc -* make Tree non copyable -* fix `#114 `_ -* Merge branch 'master' of https://github.com/BehaviorTree/BehaviorTree.CPP -* critical bug fix affecting AsyncActionNode - When a Tree is copied, all the thread related to AsyncActionNode where - invoked. - As a consequence, they are never executed, despite the fact that the - value RUNNING is returned. -* Fix issue `#109 `_ -* fix `#111 `_ -* Merge pull request `#108 `_ from daniel-serrano/add-RobMoSys-acknowledgement - Add robmosys acknowledgement -* Add robomosys acknowledgement as requested -* Add robomosys acknowledgement as requested -* added more comments (issue `#102 `_) -* Update README.md -* Add files via upload -* Merge pull request `#96 `_ from LoyVanBeek/patch-1 - Fix typo -* Update tutorial_04_sequence_star.md -* fix compilation -* removing backward_cpp - Motivation: backward_cpp is SUPER useful, but it is a library to use at - the application level. It makes no sense to add it at the library level. -* Merge pull request `#95 `_ from LoyVanBeek/patch-1 - Remove 0 in front of http://... URL to publication -* Remove 0 in front of http://... URL to publication - Hopefully, this makes the link correctly click-able when rendered to HTML -* fix issue `#84 `_ (Directories) -* add infinite loop to Repeat and Retry (issue `#80 `_) -* fix unit test -* issue `#82 `_ -* fix issue `#82 `_ -* Added 32bits compilation configuration for msvc -* Contributors: Daniel Serrano, Davide Facont, Davide Faconti, Jimmy Delas, Loy - -3.0.7 (2019-04-02) ------------------- -* this should fix issue with tinyXML2 once and for all (maybe...) -* improvement #79 -* doc fix -* Deprecating tag in SubTree -* fix windows compilation -* Update README.md -* back to c++11 -* Contributors: Davide Faconti, Ferran Roure - -3.0.4 (2019-03-19) ------------------- -* fix issue #72 with sibling subtrees -* Update .travis.yml -* Contributors: Davide Faconti - -3.0.3 (2019-03-12) ------------------- -* moving to C++14... deal with it -* updated tinyXML2. Should fix several issues too -* add "d" to debug library on Windows -* fixed compilation error on Windows x64 (issue #63) -* Improved MSVC compilation - Added _CRT_SECURE_NO_WARNINGS flag for msvc compilation -* adding TreeNode::modifyPortsRemapping that might be useful in the future -* Merge pull request #64 from luminize/patch-1 - docs/xml_format.md -* Merge pull request #65 from luminize/patch-2 - docs/tutorial_01_first_tree.md: fix typo -* docs/tutorial_01_first_tree.md: fix typo -* fix compilation in Windows/Release -* remove a warning in Windows -* Update README.md -* Merge branch 'windows_compilation' -* fix issue #63 : compile on windows -* Update .travis.yml -* Create .appveyor.yml -* fix compilation on windows -* fix potential issue -* bug fix -* Update README.md -* Contributors: Bas de Bruijn, Davide Faconti, Jimmy Delas, hlzl - -3.0.2 (2019-03-04) ------------------- -* make flatbuffers visible to other project (such as Groot) -* docs fix -* Contributors: Davide Faconti - -3.0.0 (2019-02-27) ------------------- -* Merge branch 'ver_3'. Too many changes to count... -* Contributors: Davide Facont, Davide Faconti, ImgBotApp, Victor Lopez - -2.5.1 (2019-01-14) ------------------- -* fix installation directory -* #39 Fix Conan version (#42) - Signed-off-by: Uilian Ries -* Update .travis.yml -* Conan package distribution (#39) -* Non-functional refactoring of xml_parsing to clean up the code -* cosmetic changes in the code of BehaviorTreeFactory -* XML schema. Related to enhancement #40 -* call setRegistrationName() for built-in Nodes - The method is called by BehaviorTreefactory, therefore it - registrationName is empty if trees are created programmatically. -* Reset reference count when destroying logger (issue #38) -* Contributors: Davide Facont, Davide Faconti, Uilian Ries - -2.5.0 (2018-12-12) ------------------- -* Introducing SyncActionNode that is more self explaining and less ambiguous -* fix potential problem related to ControlNode::haltChildren() -* Adding example/test of navigation and recovery behavior. Related to issue #36 -* Contributors: Davide Faconti - -2.4.4 (2018-12-12) ------------------- -* adding virtual TreeNode::onInit() [issue #33] -* fix issue #34 : if you don't implement convertFromString, it will compile but it may throw -* Pretty demangled names and obsolete comments removed -* bug fixes -* more comments -* [enhancement #32]: add CoroActionNode and rename ActionNode as "AsynActionNode" - The name ActionNode was confusing and it has been deprecated. -* Update README.md -* removed old file -* Fix issue #31 : convertFromString mandatory for TreeNode::getParam, not Blackboard::get -* Cherry piking changes from PR #19 which solve issue #2 CONAN support -* Contributors: Davide Faconti - -2.4.3 (2018-12-07) ------------------- -* Merge branch 'master' into ros2 -* removed old file -* Fix issue #31 : convertFromString mandatory for TreeNode::getParam, not Blackboard::get -* 2.4.3 -* version bump -* Merge pull request #30 from nuclearsandwich/patch-1 - Fix typo in package name. -* Remove extra find_package(ament_cmake_gtest). - This package should only be needed if BUILD_TESTING is on and is - find_package'd below if ament_cmake is found and BUILD_TESTING is on. -* Fix typo in package name. -* added video to readme -* Cherry piking changes from PR #19 which solve issue #2 CONAN support -* Merge pull request #29 from nuclearsandwich/ament-gtest-dep - Add test dependency on ament_cmake_gtest. -* Add test dependency on ament_cmake_gtest. -* fix travis removing CI -* Contributors: Davide Faconti, Steven! RagnarÃļk - -2.4.2 (2018-12-05) ------------------- -* support ament -* change to ament -* Contributors: Davide Faconti - -2.4.1 (2018-12-05) ------------------- -* fix warnings and dependencies in ROS, mainly related to ZMQ -* Contributors: Davide Faconti - -2.4.0 (2018-12-05) ------------------- -* Merge pull request #27 from mjeronimo/bt-12-4-2018 - Add support for ament/colcon build -* updated documentation -* Merge pull request #25 from BehaviorTree/include_xml - Add the ability to include an XML from another one -* supports ROS package getPath (issue #17) -* Trying to fix writeXML (issue #24) -* New feature: include XMl from other XMLs (issue #17) -* more verbose error message -* adding unit tests for Repeat and Retry nodes #23 -* Bug fix in Retry and Repeat Decorators (needs unit test) -* Throw if the parameter in blackboard can't be read -* Try to prevent error #22 in user code -* changed the protocol of the XML -* fixing issue #22 -* Contributors: Davide Faconti, Michael Jeronimo - -2.3.0 (2018-11-28) ------------------- -* Fix: registerBuilder did not register the manifest. It was "broken" as public API method -* Use the Pimpl idiom to hide zmq from the header file -* move header of minitrace in the cpp file -* Fixed a crash occurring when you didn't initialized a Tree object (#20) -* Fix issue #16 -* add ParallelNode to pre-registered entries in factory (issue #13) -* removed M_PI -* Update the documentation -* Contributors: Davide Faconti, Jimmy Delas - -2.2.0 (2018-11-20) ------------------- -* fix typo -* method contains() added to BlackBoard -* back compatible API change to improve the wrapping of legacy code (issue #15) - Eventually, SimpleAction, SimpleDecorators and SimpleCondition can use - blackboard and NodeParameters too. -* reduce potential memory allocations using string_view -* fix important issue with SubtreeNode -* Read at every tick the parameter if Blackboard is used -* Adding NodeParameters to ParallelNode -* travis update -* merge pull request #14 related to #10 (with some minor changes) -* Fix issue #8 and warning reported in #4 - Fixed problem of visibility with TinyXML2 -* Contributors: Davide Faconti, Uilian Ries - -2.1.0 (2018-11-16) ------------------- -* version 2.1. New directory structure -* Contributors: Davide Faconti diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 4459bce1e..000000000 --- a/CLAUDE.md +++ /dev/null @@ -1,131 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Build Commands - -```bash -# Plain CMake (recommended for development) -mkdir build && cmake -S . -B build && cmake --build build --parallel - -# With Conan (CMake 3.23+ required) -conan install . -s build_type=Release --build=missing -cmake --preset conan-release -cmake --build --preset conan-release - -# Pixi/Conda -pixi run build -``` - -Requires CMake 3.16.3+ and C++17 compiler. The project exports `CMAKE_EXPORT_COMPILE_COMMANDS=ON` by default. - -## Testing - -```bash -# Run all tests via CTest -ctest --test-dir build - -# Run test executable directly -./build/tests/behaviortree_cpp_test - -# Run specific test -./build/tests/behaviortree_cpp_test --gtest_filter="TestName*" - -# Pixi -pixi run test -``` - -Test files are in `tests/` using Google Test. Key test categories: `gtest_blackboard.cpp`, `gtest_factory.cpp`, `gtest_tree.cpp`, `gtest_sequence.cpp`, `gtest_fallback.cpp`, `gtest_parallel.cpp`, `gtest_decorator.cpp`, `gtest_reactive.cpp`, `gtest_ports.cpp`, `gtest_port_type_rules.cpp`. - -## Linting and Formatting - -```bash -# Pre-commit hooks (clang-format, codespell) -pre-commit install -pre-commit run -a - -# Clang-tidy (requires clangd-21, build must exist for compile_commands.json) -./run_clang_tidy.sh [build_path] -``` - -Install clang-tidy-21: -```bash -wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh -sudo ./llvm.sh 21 -sudo apt install clangd-21 clang-tidy-21 -``` - -Code style: Google C++ with 90-char line limit, 2-space indent. See `.clang-format` and `.clang-tidy` for details. - -## Architecture - -**Namespace:** `BT::` -**Library:** `behaviortree_cpp` - -### Node Hierarchy - -All behavior tree nodes inherit from `TreeNode` (`include/behaviortree_cpp/tree_node.h`): - -- **LeafNode**: `ActionNode`, `ConditionNode` - user-defined tasks and checks -- **ControlNode**: `SequenceNode`, `FallbackNode`, `ParallelNode`, `ReactiveSequence`, `ReactiveFallback`, `SwitchNode`, `IfThenElseNode`, `WhileDoElseNode` -- **DecoratorNode**: `InverterNode`, `RetryNode`, `RepeatNode`, `TimeoutNode`, `DelayNode`, `SubtreeNode` - -### Node Status - -`TreeNodeStatus`: `IDLE`, `RUNNING`, `SUCCESS`, `FAILURE`, `SKIPPED` - -### Key Components - -| Component | Location | Purpose | -|-----------|----------|---------| -| `BehaviorTreeFactory` | `bt_factory.h` | Node registration, XML parsing, tree creation | -| `Blackboard` | `blackboard.h` | Shared typed key-value storage between nodes | -| Port System | `basic_types.h` | Type-safe dataflow: `InputPort`, `OutputPort`, `BidirectionalPort` | -| XML Parser | `xml_parsing.cpp` | Loads trees from XML with type validation | -| Script Parser | `scripting/` | Embedded expression language for conditions | - -### Port System Rules - -Ports enable type-safe data passing between nodes via the Blackboard: -- Same-typed ports always connect -- Generic ports (`AnyTypeAllowed`, `BT::Any`) accept any type -- `std::string` output acts as "universal donor" (converts via `convertFromString`) -- Type locks after first strongly-typed write -- Reserved names: `name`, `ID`, names starting with `_` - -See `docs/PORT_CONNECTION_RULES.md` for detailed rules. - -### Source Layout - -``` -src/ -├── *.cpp # Core: tree_node, blackboard, xml_parsing, bt_factory -├── actions/ # Built-in action nodes -├── controls/ # Control flow nodes (sequence, fallback, parallel, etc.) -├── decorators/ # Decorator nodes (retry, repeat, timeout, etc.) -└── loggers/ # Logging infrastructure (Groot2, SQLite, file) - -include/behaviortree_cpp/ -├── *.h # Public API headers -├── controls/ # Control node headers -├── decorators/ # Decorator node headers -├── loggers/ # Logger headers -├── scripting/ # Script parser (lexy-based) -└── contrib/ # Third-party contributions -``` - -### Integration Points - -- **Groot2**: Visual editor integration via ZeroMQ (`BTCPP_GROOT_INTERFACE` option) -- **ROS2**: Auto-detected via `ament_cmake`, uses colcon build -- **Conan**: Package manager support for non-ROS builds - -### Vendored Dependencies - -All in `3rdparty/`: TinyXML2, cppzmq, flatbuffers, lexy, minicoro, minitrace. Controlled via `USE_VENDORED_*` CMake options. - -## Contributing - -- Run `pre-commit run -a` and `./run_clang_tidy.sh` before PRs -- Bug fixes should include a failing test that passes after the fix -- Consider API/ABI compatibility implications diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 416c2c332..000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,331 +0,0 @@ -cmake_minimum_required(VERSION 3.16.3) # version on Ubuntu Focal - -project(behaviortree_cpp VERSION 4.9.0 LANGUAGES C CXX) - -# create compile_commands.json -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set(CMAKE_CXX_STANDARD 17) - -#---- project configuration ---- -option(BTCPP_SHARED_LIBS "Build shared libraries" ON) -option(BTCPP_BUILD_TOOLS "Build commandline tools" ON) -option(BTCPP_EXAMPLES "Build tutorials and examples" ON) -option(BUILD_TESTING "Build the unit tests" ON) -option(BTCPP_GROOT_INTERFACE "Add Groot2 connection. Requires ZeroMQ" ON) -option(BTCPP_SQLITE_LOGGING "Add SQLite logging." ON) -option(BTCPP_ENABLE_ASAN "Enable Address Sanitizer" OFF) -option(BTCPP_ENABLE_UBSAN "Enable Undefined Behavior Sanitizer" OFF) -option(BTCPP_ENABLE_TSAN "Enable Thread Sanitizer" OFF) - -option(USE_V3_COMPATIBLE_NAMES "Use some alias to compile more easily old 3.x code" OFF) -option(ENABLE_FUZZING "Enable fuzzing builds" OFF) -option(USE_AFLPLUSPLUS "Use AFL++ instead of libFuzzer" OFF) -option(ENABLE_DEBUG "Enable debug build with full symbols" OFF) -option(FORCE_STATIC_LINKING "Force static linking of all dependencies" OFF) - -option(USE_VENDORED_CPPZMQ "Use the bundled version of cppzmq" ON) -option(USE_VENDORED_FLATBUFFERS "Use the bundled version of flatbuffers" ON) -option(USE_VENDORED_MINICORO "Use the bundled version of minicoro" ON) -option(USE_VENDORED_MINITRACE "Use the bundled version of minitrace" ON) - -set(BTCPP_LIB_DESTINATION lib) -set(BTCPP_INCLUDE_DESTINATION include) -set(BTCPP_BIN_DESTINATION bin) - -set(BASE_FLAGS "") - -if(ENABLE_DEBUG) - list(APPEND BASE_FLAGS - -g3 - -ggdb3 - -O0 - -fno-omit-frame-pointer - ) -endif() - -# Include fuzzing configuration if enabled -if(ENABLE_FUZZING) - include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/fuzzing_build.cmake) -else() - # Apply base flags for non-fuzzing builds - add_compile_options(${BASE_FLAGS}) - add_link_options(${BASE_FLAGS}) -endif() - -set(CMAKE_CONFIG_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake") -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CONFIG_PATH}") - -include(sanitizers) - -set(BTCPP_LIBRARY ${PROJECT_NAME}) - -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - message(STATUS "Setting build type to 'Release' as none was specified.") - set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Release" "MinSizeRel" "RelWithDebInfo") -endif() - -if(MSVC) - add_definitions(-D_CRT_SECURE_NO_WARNINGS -DWIN32_LEAN_AND_MEAN) -else() - add_definitions(-Wpedantic -fno-omit-frame-pointer) -endif() - -if(USE_V3_COMPATIBLE_NAMES) - add_definitions(-DUSE_BTCPP3_OLD_NAMES) -endif() - -# Update the policy setting to avoid an error when loading the ament_cmake package -# at the current cmake version level -if(POLICY CMP0057) - cmake_policy(SET CMP0057 NEW) -endif() - -find_package(ament_cmake QUIET) - -if ( ament_cmake_FOUND ) - - add_definitions( -DUSING_ROS2 ) - message(STATUS "------------------------------------------") - message(STATUS "BehaviorTree is being built using AMENT.") - message(STATUS "------------------------------------------") - include(cmake/ament_build.cmake) - - find_package(tinyxml2_vendor REQUIRED) - find_package(TinyXML2 REQUIRED) -else() - message(STATUS "------------------------------------------") - message(STATUS "BehaviorTree is being built without AMENT.") - message(STATUS "------------------------------------------") - include(cmake/conan_build.cmake) - - option(USE_VENDORED_TINYXML2 "Use the bundled version of tinyxml2" ON) - if(USE_VENDORED_TINYXML2) - add_subdirectory(3rdparty/tinyxml2) - else() - find_package(tinyxml2 REQUIRED) - endif() -endif() - -############################################################# -# Handle dependencies - -find_package(Threads REQUIRED) - -if(BTCPP_GROOT_INTERFACE) - if(USE_VENDORED_CPPZMQ) - add_subdirectory(3rdparty/cppzmq) - else() - find_package(cppzmq REQUIRED) - endif() -endif() - -if(BTCPP_SQLITE_LOGGING) - find_package(SQLite3 REQUIRED) -endif() - -if(USE_VENDORED_FLATBUFFERS) - add_subdirectory(3rdparty/flatbuffers) -else() - find_package(flatbuffers REQUIRED) -endif() - -if(USE_VENDORED_MINICORO) - add_subdirectory(3rdparty/minicoro) -else() - find_package(minicoro REQUIRED) -endif() - -if(USE_VENDORED_MINITRACE) - add_subdirectory(3rdparty/minitrace) -else() - find_package(minitrace REQUIRED) -endif() - -list(APPEND BT_SOURCE - src/action_node.cpp - src/basic_types.cpp - src/behavior_tree.cpp - src/blackboard.cpp - src/bt_factory.cpp - src/decorator_node.cpp - src/condition_node.cpp - src/control_node.cpp - src/shared_library.cpp - src/tree_node.cpp - src/script_parser.cpp - src/script_tokenizer.cpp - src/json_export.cpp - src/xml_parsing.cpp - - src/actions/test_node.cpp - src/actions/sleep_node.cpp - src/actions/updated_action.cpp - - src/decorators/delay_node.cpp - src/decorators/inverter_node.cpp - src/decorators/repeat_node.cpp - src/decorators/retry_node.cpp - src/decorators/subtree_node.cpp - src/decorators/timeout_node.cpp - src/decorators/updated_decorator.cpp - - src/controls/if_then_else_node.cpp - src/controls/fallback_node.cpp - src/controls/parallel_node.cpp - src/controls/parallel_all_node.cpp - src/controls/reactive_sequence.cpp - src/controls/reactive_fallback.cpp - src/controls/sequence_node.cpp - src/controls/sequence_with_memory_node.cpp - src/controls/switch_node.cpp - src/controls/try_catch_node.cpp - src/controls/while_do_else_node.cpp - - src/loggers/bt_cout_logger.cpp - src/loggers/bt_file_logger_v2.cpp - src/loggers/bt_minitrace_logger.cpp - src/loggers/bt_observer.cpp - ) - - -if(BTCPP_GROOT_INTERFACE) - # should be found already, at this stage - list(APPEND BT_SOURCE src/loggers/groot2_publisher.cpp ) -endif() - -if(BTCPP_SQLITE_LOGGING) - list(APPEND BT_SOURCE src/loggers/bt_sqlite_logger.cpp ) -endif() - -###################################################### - -if (UNIX) - list(APPEND BT_SOURCE src/shared_library_UNIX.cpp ) -endif() - -if (WIN32) - set(CMAKE_DEBUG_POSTFIX "d") - list(APPEND BT_SOURCE src/shared_library_WIN.cpp ) -endif() - -if (BTCPP_SHARED_LIBS) - set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) - add_library(${BTCPP_LIBRARY} SHARED ${BT_SOURCE}) -else() - set(CMAKE_POSITION_INDEPENDENT_CODE ON) - add_library(${BTCPP_LIBRARY} STATIC ${BT_SOURCE}) -endif() - -message(STATUS "BTCPP_EXTRA_LIBRARIES: ${BTCPP_EXTRA_LIBRARIES}") - -target_link_libraries(${BTCPP_LIBRARY} - PRIVATE - Threads::Threads - ${CMAKE_DL_LIBS} - $ - $ - $ - $ - PUBLIC - ${BTCPP_EXTRA_LIBRARIES} -) - -if(BTCPP_GROOT_INTERFACE) - target_link_libraries(${BTCPP_LIBRARY} - PUBLIC - $ - ) -endif() - -if(BTCPP_SQLITE_LOGGING) - target_link_libraries(${BTCPP_LIBRARY} - PRIVATE - $ - ) -endif() - -target_include_directories(${BTCPP_LIBRARY} - PUBLIC - $ - $ - PRIVATE - ${BTCPP_EXTRA_INCLUDE_DIRS} - ) - -target_compile_definitions(${BTCPP_LIBRARY} PUBLIC BTCPP_LIBRARY_VERSION="${CMAKE_PROJECT_VERSION}") - -target_compile_features(${BTCPP_LIBRARY} PUBLIC cxx_std_17) - -if(MSVC) - target_compile_options(${BTCPP_LIBRARY} PRIVATE "/source-charset:utf-8") -else() - if(ENABLE_DEBUG) - target_compile_options(${BTCPP_LIBRARY} PRIVATE -Wall -Wextra -g3 -ggdb3 -O0 -fno-omit-frame-pointer) - else() - target_compile_options(${BTCPP_LIBRARY} PRIVATE -Wall -Wextra) - endif() -endif() - -add_library(BT::${BTCPP_LIBRARY} ALIAS ${BTCPP_LIBRARY}) - -# Add fuzzing targets -if(ENABLE_FUZZING) - add_fuzzing_targets() -endif() - -############################################################# -message( STATUS "BTCPP_LIB_DESTINATION: ${BTCPP_LIB_DESTINATION} " ) -message( STATUS "BTCPP_INCLUDE_DESTINATION: ${BTCPP_INCLUDE_DESTINATION} " ) - -if (BUILD_TESTING OR BTCPP_EXAMPLES) - add_subdirectory(sample_nodes) -endif() - -###################################################### - -include(CTest) -message( STATUS "BUILD_TESTING: ${BUILD_TESTING} " ) -if (BUILD_TESTING) - add_subdirectory(tests) -endif() - -if(BTCPP_BUILD_TOOLS) - add_subdirectory(tools) -endif() - -if(BTCPP_EXAMPLES) - add_subdirectory(examples) -endif() - -###################################################### -# Generate .clangd configuration file for standalone header checking -file(WRITE ${PROJECT_SOURCE_DIR}/.clangd -"CompileFlags: - Add: - - -xc++ - - -std=c++17 - - -I${PROJECT_SOURCE_DIR}/include - - -I${PROJECT_SOURCE_DIR}/3rdparty - - -I${PROJECT_SOURCE_DIR}/3rdparty/minitrace - - -I${PROJECT_SOURCE_DIR}/3rdparty/tinyxml2 - - -I${PROJECT_SOURCE_DIR}/3rdparty/minicoro -") - -###################################################### -# INSTALL - -INSTALL(TARGETS ${BTCPP_LIBRARY} - EXPORT ${BTCPP_LIBRARY}Targets - ARCHIVE DESTINATION ${BTCPP_LIB_DESTINATION} - LIBRARY DESTINATION ${BTCPP_LIB_DESTINATION} - RUNTIME DESTINATION ${BTCPP_BIN_DESTINATION} - INCLUDES DESTINATION ${BTCPP_INCLUDE_DESTINATION} - ) - -INSTALL( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ - DESTINATION ${BTCPP_INCLUDE_DESTINATION} - FILES_MATCHING PATTERN "*.h*") - -export_btcpp_package() diff --git a/CONTRIBUTORS_GUIDE.md b/CONTRIBUTORS_GUIDE.md deleted file mode 100644 index 8fd3c9f6e..000000000 --- a/CONTRIBUTORS_GUIDE.md +++ /dev/null @@ -1,18 +0,0 @@ -# Contributors Guide - -Before submitting a Pull Request, please follow these instructions: - -- Unless your code is self explaining, add comments. -- Consider if your proposed change introduces API, ABI, back-compatibility or behavioral changes. -- If your code is fixing a bug, please create a unit test to reproduce the bug, i.e. a test that fails before the fix and pass after the fix. -- You use [pre-commit](https://pre-commit.com/) to apply automatically all the required linting rules (clang-format in particular). -- You should also execute the script `./run_clang_tidy.sh` and correct all the warnings. - -You will need to install the latest **clang-tidy-21** as follows: - -``` - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh 21 - sudo apt install clangd-21 clang-tidy-21 -``` diff --git a/Doxyfile b/Doxyfile deleted file mode 100644 index 2d8dcfab1..000000000 --- a/Doxyfile +++ /dev/null @@ -1,2483 +0,0 @@ -# Doxyfile 1.8.11 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. -# -# All text after a double hash (##) is considered a comment and is placed in -# front of the TAG it is preceding. -# -# All text after a single hash (#) is considered a comment and will be ignored. -# The format is: -# TAG = value [value, ...] -# For lists, items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (\" \"). - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. -# The default value is: UTF-8. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by -# double-quotes, unless you are using Doxywizard) that should identify the -# project for which the documentation is generated. This name is used in the -# title of most generated pages and in a few other places. -# The default value is: My Project. - -PROJECT_NAME = BehaviorTree - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. This -# could be handy for archiving the generated documentation or if some version -# control system is used. - -PROJECT_NUMBER = - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer a -# quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = "Core Library to create and execute Behavior Trees" - -# With the PROJECT_LOGO tag one can specify a logo or an icon that is included -# in the documentation. The maximum height of the logo should not exceed 55 -# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy -# the logo to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path -# into which the generated documentation will be written. If a relative path is -# entered, it will be relative to the location where doxygen was started. If -# left blank the current directory will be used. - -OUTPUT_DIRECTORY = ./doc - -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this -# option can be useful when feeding doxygen a huge amount of source files, where -# putting all generated files in the same directory would otherwise causes -# performance problems for the file system. -# The default value is: NO. - -CREATE_SUBDIRS = YES - -# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII -# characters to appear in the names of generated files. If set to NO, non-ASCII -# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode -# U+3044. -# The default value is: NO. - -ALLOW_UNICODE_NAMES = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. -# The default value is: English. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member -# descriptions after the members that are listed in the file and class -# documentation (similar to Javadoc). Set to NO to disable this. -# The default value is: YES. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief -# description of a member or function before the detailed description -# -# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. -# The default value is: YES. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator that is -# used to form the text in various listings. Each string in this list, if found -# as the leading text of the brief description, will be stripped from the text -# and the result, after processing the whole list, is used as the annotated -# text. Otherwise, the brief description is used as-is. If left blank, the -# following values are used ($name is automatically replaced with the name of -# the entity):The $name class, The $name widget, The $name file, is, provides, -# specifies, contains, represents, a, an and the. - -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# doxygen will generate a detailed section even if there is only a brief -# description. -# The default value is: NO. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. -# The default value is: NO. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path -# before files name in the file list and in the header files. If set to NO the -# shortest path that makes the file name unique will be used -# The default value is: YES. - -FULL_PATH_NAMES = YES - -# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. -# Stripping is only done if one of the specified strings matches the left-hand -# part of the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the path to -# strip. -# -# Note that you can specify absolute paths here, but also relative paths, which -# will be relative from the directory where doxygen is started. -# This tag requires that the tag FULL_PATH_NAMES is set to YES. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the -# path mentioned in the documentation of a class, which tells the reader which -# header file to include in order to use a class. If left blank only the name of -# the header file containing the class definition is used. Otherwise one should -# specify the list of include paths that are normally passed to the compiler -# using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but -# less readable) file names. This can be useful is your file systems doesn't -# support long names like on DOS, Mac, or CD-ROM. -# The default value is: NO. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the -# first line (until the first dot) of a Javadoc-style comment as the brief -# description. If set to NO, the Javadoc-style will behave just like regular Qt- -# style comments (thus requiring an explicit @brief command for a brief -# description.) -# The default value is: NO. - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first -# line (until the first dot) of a Qt-style comment as the brief description. If -# set to NO, the Qt-style will behave just like regular Qt-style comments (thus -# requiring an explicit \brief command for a brief description.) -# The default value is: NO. - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a -# multi-line C++ special comment block (i.e. a block of //! or /// comments) as -# a brief description. This used to be the default behavior. The new default is -# to treat a multi-line C++ comment block as a detailed description. Set this -# tag to YES if you prefer the old behavior instead. -# -# Note that setting this tag to YES also means that rational rose comments are -# not recognized any more. -# The default value is: NO. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the -# documentation from any documented member that it re-implements. -# The default value is: YES. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new -# page for each member. If set to NO, the documentation of a member will be part -# of the file/class/namespace that contains it. -# The default value is: NO. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen -# uses this value to replace tabs by spaces in code fragments. -# Minimum value: 1, maximum value: 16, default value: 4. - -TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that act as commands in -# the documentation. An alias has the form: -# name=value -# For example adding -# "sideeffect=@par Side Effects:\n" -# will allow you to put the command \sideeffect (or @sideeffect) in the -# documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. - -ALIASES = - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources -# only. Doxygen will then generate output that is more tailored for C. For -# instance, some of the names that are used will be different. The list of all -# members will be omitted, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or -# Python sources only. Doxygen will then generate output that is more tailored -# for that language. For instance, namespaces will be presented as packages, -# qualified scopes will look different, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources. Doxygen will then generate output that is tailored for Fortran. -# The default value is: NO. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for VHDL. -# The default value is: NO. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given -# extension. Doxygen has a built-in mapping, but you can override or extend it -# using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: -# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: -# Fortran. In the later case the parser tries to guess whether the code is fixed -# or free formatted code, this is the default for Fortran type files), VHDL. For -# instance to make doxygen treat .inc files as Fortran files (default is PHP), -# and .f files as C (default is Fortran), use: inc=Fortran f=C. -# -# Note: For files without extension you can use no_extension as a placeholder. -# -# Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments -# according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you can -# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in -# case of backward compatibilities issues. -# The default value is: YES. - -MARKDOWN_SUPPORT = YES - -# When enabled doxygen tries to link words that correspond to documented -# classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by putting a % sign in front of the word or -# globally by setting AUTOLINK_SUPPORT to NO. -# The default value is: YES. - -AUTOLINK_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should set this -# tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. -# The default value is: NO. - -BUILTIN_STL_SUPPORT = YES - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. -# The default value is: NO. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. -# The default value is: NO. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate -# getter and setter methods for a property. Setting this option to YES will make -# doxygen to replace the get and set methods by a property in the documentation. -# This will only work if the methods are indeed getting or setting a simple -# type. If this is not the case, or you want to show the methods anyway, you -# should set this option to NO. -# The default value is: YES. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. -# The default value is: NO. - -DISTRIBUTE_GROUP_DOC = NO - -# If one adds a struct or class to a group and this option is enabled, then also -# any nested class or struct is added to the same group. By default this option -# is disabled and one has to add nested compounds explicitly via \ingroup. -# The default value is: NO. - -GROUP_NESTED_COMPOUNDS = NO - -# Set the SUBGROUPING tag to YES to allow class member groups of the same type -# (for instance a group of public functions) to be put as a subgroup of that -# type (e.g. under the Public Functions section). Set it to NO to prevent -# subgrouping. Alternatively, this can be done per class using the -# \nosubgrouping command. -# The default value is: YES. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions -# are shown inside the group in which they are included (e.g. using \ingroup) -# instead of on a separate page (for HTML and Man pages) or section (for LaTeX -# and RTF). -# -# Note that this feature does not work in combination with -# SEPARATE_MEMBER_PAGES. -# The default value is: NO. - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions -# with only public data fields or simple typedef fields will be shown inline in -# the documentation of the scope in which they are defined (i.e. file, -# namespace, or group documentation), provided this scope is documented. If set -# to NO, structs, classes, and unions are shown on a separate page (for HTML and -# Man pages) or section (for LaTeX and RTF). -# The default value is: NO. - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or -# enum is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically be -# useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. -# The default value is: NO. - -TYPEDEF_HIDES_STRUCT = NO - -# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This -# cache is used to resolve symbols given their name and scope. Since this can be -# an expensive process and often the same symbol appears multiple times in the -# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small -# doxygen will become slower. If the cache is too large, memory is wasted. The -# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range -# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 -# symbols. At the end of a run doxygen will report the cache usage and suggest -# the optimal cache size from a speed point of view. -# Minimum value: 0, maximum value: 9, default value: 0. - -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in -# documentation are documented, even if no documentation was available. Private -# class members and static file members will be hidden unless the -# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. -# Note: This will also disable the warnings about undocumented members that are -# normally produced when WARNINGS is set to YES. -# The default value is: NO. - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will -# be included in the documentation. -# The default value is: NO. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal -# scope will be included in the documentation. -# The default value is: NO. - -EXTRACT_PACKAGE = NO - -# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be -# included in the documentation. -# The default value is: NO. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO, -# only classes defined in header files are included. Does not have any effect -# for Java sources. -# The default value is: YES. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. If set to YES, local methods, -# which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO, only methods in the interface are -# included. -# The default value is: NO. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base name of -# the file that contains the anonymous namespace. By default anonymous namespace -# are hidden. -# The default value is: NO. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all -# undocumented members inside documented classes or files. If set to NO these -# members will be included in the various overviews, but no documentation -# section is generated. This option has no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. If set -# to NO, these classes will be included in the various overviews. This option -# has no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO, these declarations will be -# included in the documentation. -# The default value is: NO. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO, these -# blocks will be appended to the function's detailed documentation block. -# The default value is: NO. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation that is typed after a -# \internal command is included. If the tag is set to NO then the documentation -# will be excluded. Set it to YES to include the internal documentation. -# The default value is: NO. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES, upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. -# The default value is: system dependent. - -CASE_SENSE_NAMES = NO - -# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES, the -# scope will be hidden. -# The default value is: NO. - -HIDE_SCOPE_NAMES = NO - -# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will -# append additional text to a page's title, such as Class Reference. If set to -# YES the compound reference will be hidden. -# The default value is: NO. - -HIDE_COMPOUND_REFERENCE= NO - -# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of -# the files that are included by a file in the documentation of that file. -# The default value is: YES. - -SHOW_INCLUDE_FILES = YES - -# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each -# grouped member an include statement to the documentation, telling the reader -# which file to include in order to use the member. -# The default value is: NO. - -SHOW_GROUPED_MEMB_INC = NO - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include -# files with double quotes in the documentation rather than with sharp brackets. -# The default value is: NO. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the -# documentation for inline members. -# The default value is: YES. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the -# (detailed) documentation of file and class members alphabetically by member -# name. If set to NO, the members will appear in declaration order. -# The default value is: YES. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief -# descriptions of file, namespace and class members alphabetically by member -# name. If set to NO, the members will appear in declaration order. Note that -# this will also influence the order of the classes in the class list. -# The default value is: NO. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the -# (brief and detailed) documentation of class members so that constructors and -# destructors are listed first. If set to NO the constructors will appear in the -# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. -# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief -# member documentation. -# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting -# detailed member documentation. -# The default value is: NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy -# of group names into alphabetical order. If set to NO the group names will -# appear in their defined order. -# The default value is: NO. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by -# fully-qualified names, including namespaces. If set to NO, the class list will -# be sorted only by class name, not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the alphabetical -# list. -# The default value is: NO. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper -# type resolution of all parameters of a function it will reject a match between -# the prototype and the implementation of a member function even if there is -# only one candidate or it is obvious which candidate to choose by doing a -# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still -# accept a match between prototype and implementation in such cases. -# The default value is: NO. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo -# list. This list is created by putting \todo commands in the documentation. -# The default value is: YES. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test -# list. This list is created by putting \test commands in the documentation. -# The default value is: YES. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug -# list. This list is created by putting \bug commands in the documentation. -# The default value is: YES. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) -# the deprecated list. This list is created by putting \deprecated commands in -# the documentation. -# The default value is: YES. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional documentation -# sections, marked by \if ... \endif and \cond -# ... \endcond blocks. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the -# initial value of a variable or macro / define can have for it to appear in the -# documentation. If the initializer consists of more lines than specified here -# it will be hidden. Use a value of 0 to hide initializers completely. The -# appearance of the value of individual variables and macros / defines can be -# controlled using \showinitializer or \hideinitializer command in the -# documentation regardless of this setting. -# Minimum value: 0, maximum value: 10000, default value: 30. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES, the -# list will mention the files that were used to generate the documentation. -# The default value is: YES. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This -# will remove the Files entry from the Quick Index and from the Folder Tree View -# (if specified). -# The default value is: YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces -# page. This will remove the Namespaces entry from the Quick Index and from the -# Folder Tree View (if specified). -# The default value is: YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command command input-file, where command is the value of the -# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided -# by doxygen. Whatever the program writes to standard output is used as the file -# version. For an example see the documentation. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. You can -# optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. -# -# Note that if you run doxygen from a directory containing a file called -# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE -# tag is left empty. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files containing -# the reference definitions. This must be a list of .bib files. The .bib -# extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. -# For LaTeX the style of the bibliography can be controlled using -# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. See also \cite for info how to create references. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# Configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated to -# standard output by doxygen. If QUIET is set to YES this implies that the -# messages are off. -# The default value is: NO. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES -# this implies that the warnings are on. -# -# Tip: Turn warnings on while writing the documentation. -# The default value is: YES. - -WARNINGS = YES - -# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate -# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag -# will automatically be disabled. -# The default value is: YES. - -WARN_IF_UNDOCUMENTED = YES - -# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. -# The default value is: YES. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that -# are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. -# The default value is: NO. - -WARN_NO_PARAMDOC = NO - -# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. -# The default value is: NO. - -WARN_AS_ERROR = NO - -# The WARN_FORMAT tag determines the format of the warning messages that doxygen -# can produce. The string should contain the $file, $line, and $text tags, which -# will be replaced by the file and line number from which the warning originated -# and the warning text. Optionally the format may contain $version, which will -# be replaced by the version of the file (if it could be obtained via -# FILE_VERSION_FILTER) -# The default value is: $file:$line: $text. - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning and error -# messages should be written. If left blank the output is written to standard -# error (stderr). - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# Configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag is used to specify the files and/or directories that contain -# documented source files. You may enter file names like myfile.cpp or -# directories like /usr/src/myproject. Separate the files or directories with -# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING -# Note: If this tag is empty the current directory is searched. - -INPUT = ./include \ - ./docs/mainpage.md - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses -# libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of -# possible encodings. -# The default value is: UTF-8. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. -# -# Note that for custom extensions or not directly supported extensions you also -# need to set EXTENSION_MAPPING for the extension otherwise the files are not -# read by doxygen. -# -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl, -# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js. - -FILE_PATTERNS = *.c \ - *.cc \ - *.cxx \ - *.cpp \ - *.c++ \ - *.java \ - *.ii \ - *.ixx \ - *.ipp \ - *.i++ \ - *.inl \ - *.idl \ - *.ddl \ - *.odl \ - *.h \ - *.hh \ - *.hxx \ - *.hpp \ - *.h++ \ - *.cs \ - *.d \ - *.php \ - *.php4 \ - *.php5 \ - *.phtml \ - *.inc \ - *.m \ - *.markdown \ - *.md \ - *.mm \ - *.dox \ - *.py \ - *.pyw \ - *.f90 \ - *.f \ - *.for \ - *.tcl \ - *.vhd \ - *.vhdl \ - *.ucf \ - *.qsf \ - *.as \ - *.js - -# The RECURSIVE tag can be used to specify whether or not subdirectories should -# be searched for input files as well. -# The default value is: NO. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = ./3rdparty \ - ./gtest \ - ./include/behaviortree_cpp/contrib - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. -# The default value is: NO. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or directories -# that contain example code fragments that are included (see the \include -# command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank all -# files are included. - -EXAMPLE_PATTERNS = * - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude commands -# irrespective of the value of the RECURSIVE tag. -# The default value is: NO. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or directories -# that contain images that are to be included in the documentation (see the -# \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command: -# -# -# -# where is the value of the INPUT_FILTER tag, and is the -# name of an input file. Doxygen will then use the output that the filter -# program writes to standard output. If FILTER_PATTERNS is specified, this tag -# will be ignored. -# -# Note that the filter must not add or remove lines; it is applied before the -# code is scanned, but not when the output code is generated. If lines are added -# or removed, the anchors will not be placed correctly. -# -# Note that for custom extensions or not directly supported extensions you also -# need to set EXTENSION_MAPPING for the extension otherwise the files are not -# properly processed by doxygen. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: pattern=filter -# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how -# filters are used. If the FILTER_PATTERNS tag is empty or if none of the -# patterns match the file name, INPUT_FILTER is applied. -# -# Note that for custom extensions or not directly supported extensions you also -# need to set EXTENSION_MAPPING for the extension otherwise the files are not -# properly processed by doxygen. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will also be used to filter the input files that are used for -# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). -# The default value is: NO. - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and -# it is also possible to disable source filtering for a specific pattern using -# *.ext= (so without naming a filter). -# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. - -FILTER_SOURCE_PATTERNS = - -# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that -# is part of the input, its contents will be placed on the main page -# (index.html). This can be useful if you have a project on for instance GitHub -# and want to reuse the introduction page also for the doxygen output. - -USE_MDFILE_AS_MAINPAGE = docs/mainpage.md - -#--------------------------------------------------------------------------- -# Configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will be -# generated. Documented entities will be cross-referenced with these sources. -# -# Note: To get rid of all source code in the generated output, make sure that -# also VERBATIM_HEADERS is set to NO. -# The default value is: NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. -# The default value is: NO. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any -# special comment blocks from generated source code fragments. Normal C, C++ and -# Fortran comments will always remain visible. -# The default value is: YES. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. -# The default value is: NO. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES then for each documented function -# all documented entities called/used by that function will be listed. -# The default value is: NO. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES then the hyperlinks from functions in REFERENCES_RELATION and -# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will -# link to the documentation. -# The default value is: YES. - -REFERENCES_LINK_SOURCE = YES - -# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the -# source code will show a tooltip with additional information such as prototype, -# brief description and links to the definition and documentation. Since this -# will make the HTML file larger and loading of large files a bit slower, you -# can opt to disable this feature. -# The default value is: YES. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -SOURCE_TOOLTIPS = YES - -# If the USE_HTAGS tag is set to YES then the references to source code will -# point to the HTML generated by the htags(1) tool instead of doxygen built-in -# source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version -# 4.8.6 or higher. -# -# To use it do the following: -# - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file -# - Make sure the INPUT points to the root of the source tree -# - Run doxygen as normal -# -# Doxygen will invoke htags (and that will in turn invoke gtags), so these -# tools must be available from the command line (i.e. in the search path). -# -# The result: instead of the source browser generated by doxygen, the links to -# source code will now point to the output of htags. -# The default value is: NO. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a -# verbatim copy of the header file for each class for which an include is -# specified. Set to NO to disable this. -# See also: Section \class. -# The default value is: YES. - -VERBATIM_HEADERS = YES - -# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the -# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the -# cost of reduced performance. This can be particularly helpful with template -# rich C++ code for which doxygen's built-in parser lacks the necessary type -# information. -# Note: The availability of this option depends on whether or not doxygen was -# generated with the -Duse-libclang=ON option for CMake. -# The default value is: NO. - -CLANG_ASSISTED_PARSING = YES - -# If clang assisted parsing is enabled you can provide the compiler with command -# line options that you would normally use when invoking the compiler. Note that -# the include paths will already be set by doxygen for the files and directories -# specified with INPUT and INCLUDE_PATH. -# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. - -CLANG_OPTIONS = - -#--------------------------------------------------------------------------- -# Configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all -# compounds will be generated. Enable this if the project contains a lot of -# classes, structs, unions or interfaces. -# The default value is: YES. - -ALPHABETICAL_INDEX = YES - -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output -# The default value is: YES. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a -# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of -# it. -# The default directory is: html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each -# generated HTML page (for example: .htm, .php, .asp). -# The default value is: .html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a user-defined HTML header file for -# each generated HTML page. If the tag is left blank doxygen will generate a -# standard header. -# -# To get valid HTML the header file that includes any scripts and style sheets -# that doxygen needs, which is dependent on the configuration options used (e.g. -# the setting GENERATE_TREEVIEW). It is highly recommended to start with a -# default header using -# doxygen -w html new_header.html new_footer.html new_stylesheet.css -# YourConfigFile -# and then modify the file new_header.html. See also section "Doxygen usage" -# for information on how to generate the default header that doxygen normally -# uses. -# Note: The header is subject to change so you typically have to regenerate the -# default header when upgrading to a newer version of doxygen. For a description -# of the possible markers and block names see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each -# generated HTML page. If the tag is left blank doxygen will generate a standard -# footer. See HTML_HEADER for more information on how to generate a default -# footer and what special commands can be used inside the footer. See also -# section "Doxygen usage" for information on how to generate the default footer -# that doxygen normally uses. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style -# sheet that is used by each HTML page. It can be used to fine-tune the look of -# the HTML output. If left blank doxygen will generate a default style sheet. -# See also section "Doxygen usage" for information on how to generate the style -# sheet that doxygen normally uses. -# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as -# it is more robust and this tag (HTML_STYLESHEET) will in the future become -# obsolete. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_STYLESHEET = - -# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined -# cascading style sheets that are included after the standard style sheets -# created by doxygen. Using this option one can overrule certain style aspects. -# This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefore more robust against future updates. -# Doxygen will copy the style sheet files to the output directory. -# Note: The order of the extra style sheet files is of importance (e.g. the last -# style sheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_STYLESHEET = 3rdparty/doxygen-awesome-css/doxygen-awesome.css \ - 3rdparty/doxygen-awesome-css/doxygen-awesome-sidebar-only.css - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that the -# files will be copied as-is; there are no commands or markers available. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value -# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 -# purple, and 360 is red again. -# Minimum value: 0, maximum value: 359, default value: 220. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A -# value of 255 will produce the most vivid colors. -# Minimum value: 0, maximum value: 255, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the -# luminance component of the colors in the HTML output. Values below 100 -# gradually make the output lighter, whereas values above 100 make the output -# darker. The value divided by 100 is the actual gamma applied, so 80 represents -# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not -# change the gamma. -# Minimum value: 40, maximum value: 240, default value: 80. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = NO - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_DYNAMIC_SECTIONS = NO - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries -# shown in the various tree structured indices initially; the user can expand -# and collapse entries dynamically later on. Doxygen will expand the tree to -# such a level that at most the specified number of entries are visible (unless -# a fully collapsed tree already exceeds this amount). So setting the number of -# entries 1 will produce a full collapsed tree by default. 0 is a special value -# representing an infinite number of entries and will result in a full expanded -# tree by default. -# Minimum value: 0, maximum value: 9999, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_INDEX_NUM_ENTRIES = 100 - -# If the GENERATE_DOCSET tag is set to YES, additional index files will be -# generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_DOCSET = NO - -# This tag determines the name of the docset feed. A documentation feed provides -# an umbrella under which multiple documentation sets from a single provider -# (such as a company or product suite) can be grouped. -# The default value is: Doxygen generated docs. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# This tag specifies a string that should uniquely identify the documentation -# set bundle. This should be a reverse domain-name style string, e.g. -# com.mycompany.MyDocSet. Doxygen will append .docset to the name. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. -# The default value is: org.doxygen.Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. -# The default value is: Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three -# additional HTML index files: index.hhp, index.hhc, and index.hhk. The -# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. -# -# The HTML Help Workshop contains a compiler that can convert all HTML output -# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML -# files are now used as the Windows 98 help format, and will replace the old -# Windows help format (.hlp) on all Windows platforms in the future. Compressed -# HTML files also contain an index, a table of contents, and you can search for -# words in the documentation. The HTML workshop also contains a viewer for -# compressed HTML files. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_HTMLHELP = NO - -# The CHM_FILE tag can be used to specify the file name of the resulting .chm -# file. You can add a path in front of the file if the result should not be -# written to the html output directory. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_FILE = - -# The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler (hhc.exe). If non-empty, -# doxygen will try to run the HTML help compiler on the generated index.hhp. -# The file has to be specified with full path. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -HHC_LOCATION = - -# The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the master .chm file (NO). -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -GENERATE_CHI = NO - -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) -# and project file content. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_INDEX_ENCODING = - -# The BINARY_TOC flag controls whether a binary table of contents is generated -# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it -# enables the Previous and Next buttons. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members to -# the table of contents of the HTML help documentation and to the tree view. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that -# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help -# (.qch) of the generated HTML documentation. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify -# the file name of the resulting .qch file. The path specified is relative to -# the HTML output folder. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help -# Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt -# Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- -# folders). -# The default value is: doc. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_VIRTUAL_FOLDER = doc - -# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom -# filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_SECT_FILTER_ATTRS = - -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be -# generated, together with the HTML files, they form an Eclipse help plugin. To -# install this plugin and make it available under the help contents menu in -# Eclipse, the contents of the directory containing the HTML and XML files needs -# to be copied into the plugins directory of eclipse. The name of the directory -# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. -# After copying Eclipse needs to be restarted before the help appears. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the Eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have this -# name. Each documentation set should have its own identifier. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# If you want full control over the layout of the generated HTML pages it might -# be necessary to disable the index and replace it with your own. The -# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top -# of each HTML page. A value of NO enables the index and the value YES disables -# it. Since the tabs in the index contain the same information as the navigation -# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -DISABLE_INDEX = NO - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. If the tag -# value is set to YES, a side panel will be generated containing a tree-like -# index structure (just like the one that is generated for HTML Help). For this -# to work a browser that supports JavaScript, DHTML, CSS and frames is required -# (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_TREEVIEW = YES - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that -# doxygen will group on one line in the generated HTML documentation. -# -# Note that a value of 0 will completely suppress the enum values from appearing -# in the overview section. -# Minimum value: 0, maximum value: 20, default value: 4. -# This tag requires that the tag GENERATE_HTML is set to YES. - -ENUM_VALUES_PER_LINE = 4 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used -# to set the initial width (in pixels) of the frame in which the tree is shown. -# Minimum value: 0, maximum value: 1500, default value: 250. -# This tag requires that the tag GENERATE_HTML is set to YES. - -TREEVIEW_WIDTH = 250 - -# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to -# external symbols imported via tag files in a separate window. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of LaTeX formulas included as images in -# the HTML documentation. When you change the font size after a successful -# doxygen run you need to manually remove any form_*.png images from the HTML -# output directory to force them to be regenerated. -# Minimum value: 8, maximum value: 50, default value: 10. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX -# installed or if you want to formulas look prettier in the HTML output. When -# enabled you may also need to install MathJax separately and configure the path -# to it using the MATHJAX_RELPATH option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -USE_MATHJAX = NO - -# When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. -# Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. -# The default value is: HTML-CSS. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_FORMAT = HTML-CSS - -# When MathJax is enabled you need to specify the location relative to the HTML -# output directory using the MATHJAX_RELPATH option. The destination directory -# should contain the MathJax.js script. For instance, if the mathjax directory -# is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax -# Content Delivery Network so you can quickly see the result without installing -# MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest - -# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax -# extension names that should be enabled during MathJax rendering. For example -# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_EXTENSIONS = - -# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces -# of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an -# example see the documentation. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_CODEFILE = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for -# the HTML output. The underlying search engine uses javascript and DHTML and -# should work on any modern browser. Note that when using HTML help -# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) -# there is already a search function so this one should typically be disabled. -# For large projects the javascript based search engine can be slow, then -# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to -# search using the keyboard; to jump to the search box use + S -# (what the is depends on the OS and browser, but it is typically -# , /