diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 000000000..bf05c2cf1 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,37 @@ +# Copyright 2019 - 2021 Alexander Grund +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) +# +# Sample codecov configuration file. Edit as required + +codecov: + max_report_age: off + require_ci_to_pass: no + notify: + # posix + windows coverage jobs both upload, so wait for both + after_n_builds: 2 + wait_for_ci: no + +# project = whole-codebase %; report it but never let it gate a merge. +# patch = coverage of the lines this PR changed; that stays the real gate. +coverage: + status: + project: + default: + informational: true + patch: + default: + target: 100% + +# Change how pull request comments look +comment: + layout: "condensed_header, condensed_files, condensed_footer" + hide_project_coverage: true + +# Ignore specific files or folders. Glob patterns are supported. +# See https://docs.codecov.com/docs/ignoring-paths +ignore: + - example/** + - test/** + # vendored third-party rapidxml parser, not our code to test + - include/boost/graph/detail/rapidxml.hpp diff --git a/.drone/drone.sh b/.drone/drone.sh index f8c7c28be..3f4b0d875 100755 --- a/.drone/drone.sh +++ b/.drone/drone.sh @@ -23,7 +23,7 @@ git submodule update --init tools/boost_install git submodule update --init libs/headers git submodule update --init tools/boostdep cp -r $TRAVIS_BUILD_DIR/* libs/graph -python tools/boostdep/depinst/depinst.py graph +python tools/boostdep/depinst/depinst.py -I example graph ./bootstrap.sh ./b2 headers diff --git a/.github/scripts/dep_table.py b/.github/scripts/dep_table.py new file mode 100644 index 000000000..0073be3ca --- /dev/null +++ b/.github/scripts/dep_table.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 +"""Print a markdown table of Boost dependency changes between two CI log archives. + +Usage: dep_table.py BASELINE.zip AFTER.zip + +Each archive is a GitHub Actions run-log zip. The `deps` job of the +dependency-report workflow prints two marker-delimited boostdep reports into +its log: + + ===DEP-BRIEF-START=== boostdep --brief graph ===DEP-BRIEF-END=== + ===DEP-PRIMARY-START=== boostdep graph (primary) ===DEP-PRIMARY-END=== + +From those it derives two metrics and prints their delta vs the baseline: + - the set of transitive Boost modules graph depends on (from --brief: + Primary + Secondary sections = the full transitive closure), and + - the header-inclusion weight of each direct dependency (from the primary + report: how many distinct boost/graph files pull that dependency in). +Weights are the live signal, they drop toward zero as coupling is removed; +the module count is the coarse target that only moves when a dep hits zero. +""" +import re +import sys +import zipfile + +BRIEF = ("===DEP-BRIEF-START===", "===DEP-BRIEF-END===") +PRIMARY = ("===DEP-PRIMARY-START===", "===DEP-PRIMARY-END===") +# Module names as boostdep prints them, e.g. "numeric~conversion". +MODULE = re.compile(r"[A-Za-z0-9_.~-]+") +TIMESTAMP = re.compile(r"^\d{4}-\d\d-\d\dT[\d:.]+Z\s?") # GitHub log line prefix +ANSI = re.compile(r"\x1b\[[0-9;]*m") + + +def read_clean_lines(zip_path): + """Top-level per-job logs, with GitHub timestamp and ANSI prefixes stripped.""" + lines = [] + with zipfile.ZipFile(zip_path) as z: + for entry in z.namelist(): + if "/" in entry or not entry.endswith(".txt"): + continue + for ln in z.read(entry).decode("utf-8", "replace").splitlines(): + lines.append(TIMESTAMP.sub("", ANSI.sub("", ln))) + return lines + + +def block(lines, markers): + """Lines strictly between the marker lines, matched exactly. + + Exact matching is what skips the echoed `echo ""` command lines + GitHub prepends to a run step, so we capture boostdep's real stdout. + """ + start, end = markers + out, capturing = [], False + for ln in lines: + s = ln.strip() + if s == start: + capturing = True + continue + if s == end and capturing: + break + if capturing: + out.append(ln) + return out + + +def parse_brief(lines): + """--brief output -> set of module names (one bare name per line).""" + mods = set() + for ln in lines: + s = ln.strip() + if not s or s.startswith("#") or s.lower().startswith("brief dependency"): + continue + if MODULE.fullmatch(s): + mods.add(s) + return mods + + +def parse_weights(lines): + """Primary report -> {dependency: number of distinct graph files that pull it in}.""" + weights, cur = {}, None + for ln in lines: + head = re.match(r"^([A-Za-z0-9_.~-]+):\s*$", ln) # "module:" at column 0 + if head: + cur = head.group(1) + weights.setdefault(cur, set()) + continue + frm = re.match(r"^\s+from\s+(.+?)\s*$", ln) + if frm and cur is not None: + weights[cur].add(frm.group(1)) + return {k: len(v) for k, v in weights.items()} + + +def main(base_zip, pr_zip): + bl, pl = read_clean_lines(base_zip), read_clean_lines(pr_zip) + base_mods = parse_brief(block(bl, BRIEF)) + pr_mods = parse_brief(block(pl, BRIEF)) + base_w = parse_weights(block(bl, PRIMARY)) + pr_w = parse_weights(block(pl, PRIMARY)) + + # Header-inclusion weights: the live signal. Only rows that changed, most-reduced first. + print("**Header-inclusion weights** (graph files pulling each direct dependency in):") + print() + changed = [] + for dep in base_w.keys() | pr_w.keys(): + b, p = base_w.get(dep, 0), pr_w.get(dep, 0) + if b != p: + changed.append((p - b, dep, b, p)) + if changed: + print("| Dependency | develop | PR | Δ |") + print("|-----|--------:|---:|----:|") + for d, dep, b, p in sorted(changed): # reductions (negative delta) first + print(f"| {dep} | {b} | {p} | {d:+d} |") + else: + print("_No header-inclusion-weight changes._") + print() + + # Transitive module set: the coarse target. + added = sorted(pr_mods - base_mods) + removed = sorted(base_mods - pr_mods) + nb, np_ = len(base_mods), len(pr_mods) + diff = np_ - nb + print(f"**Transitive Boost modules:** {nb} → {np_} ({f'{diff:+d}' if diff else '0'})") + if added: + print(f"- added: {', '.join(added)}") + if removed: + print(f"- removed: {', '.join(removed)}") + + +if __name__ == "__main__": + if len(sys.argv) != 3: + sys.exit("usage: dep_table.py BASELINE.zip AFTER.zip") + main(sys.argv[1], sys.argv[2]) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 181121e61..2b91c4f0f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,7 @@ jobs: run: cp -r $GITHUB_WORKSPACE/* libs/graph working-directory: ../boost-root - name: Install deps - run: python tools/boostdep/depinst/depinst.py graph + run: python tools/boostdep/depinst/depinst.py -I example graph working-directory: ../boost-root - name: Bootstrap run: ./bootstrap.sh @@ -53,10 +53,10 @@ jobs: run: ../../../b2 print_config_info toolset=$TOOLSET cxxstd=${{ matrix.cxxstd }} working-directory: ../boost-root/libs/config/test - name: Test - run: ../../../b2 toolset=$TOOLSET cxxstd=${{ matrix.cxxstd }} + run: ../../../b2 toolset=$TOOLSET cxxstd=${{ matrix.cxxstd }} cxxflags="-Wall -Wextra" working-directory: ../boost-root/libs/graph/test macos: - runs-on: macos-latest + runs-on: macos-15 strategy: fail-fast: false matrix: @@ -71,6 +71,8 @@ jobs: commit-filter: '[skip ci];[ci skip];[CI SKIP];[SKIP CI];***CI SKIP***;***SKIP CI***;[windows];[Windows];[WINDOWS];[linux];[Linux];[LINUX]' commit-filter-separator: ';' fail-fast: true + - name: Print pinned AppleClang version + run: clang++ --version - name: Checkout main boost run: git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root - name: Update tools/boostdep @@ -80,7 +82,7 @@ jobs: run: cp -r $GITHUB_WORKSPACE/* libs/graph working-directory: ../boost-root - name: Install deps - run: python tools/boostdep/depinst/depinst.py graph + run: python tools/boostdep/depinst/depinst.py -I example graph working-directory: ../boost-root - name: Bootstrap run: ./bootstrap.sh @@ -92,7 +94,7 @@ jobs: run: ../../../b2 print_config_info toolset=${{ matrix.toolset }} cxxstd=${{ matrix.cxxstd }} working-directory: ../boost-root/libs/config/test - name: Test - run: ../../../b2 toolset=${{ matrix.toolset }} cxxstd=${{ matrix.cxxstd }} define=CI_SUPPRESS_KNOWN_ISSUES + run: ../../../b2 toolset=${{ matrix.toolset }} cxxstd=${{ matrix.cxxstd }} define=CI_SUPPRESS_KNOWN_ISSUES cxxflags="-Wall -Wextra" working-directory: ../boost-root/libs/graph/test windows_msvc_14_3: runs-on: windows-2022 @@ -121,7 +123,7 @@ jobs: run: xcopy /s /e /q %GITHUB_WORKSPACE% libs\graph working-directory: ../boost-root - name: Install deps - run: python tools/boostdep/depinst/depinst.py graph + run: python tools/boostdep/depinst/depinst.py -I example graph working-directory: ../boost-root - name: Bootstrap run: bootstrap diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 000000000..13c0077ae --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,269 @@ +# Copyright 2020-2021 Peter Dimov +# Copyright 2021 Andrey Semashev +# Copyright 2021 Alexander Grund +# Copyright 2022 James E. King III +# Copyright 2023 Matt Borland +# Copyright 2026 Arnaud Becheler +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt) +--- +name: codecov + +on: + pull_request: + push: + branches: + - master + - develop + - bugfix/** + - feature/** + - fix/** + - pr/** + +env: + GIT_FETCH_JOBS: 8 + NET_RETRY_COUNT: 5 + B2_CI_VERSION: 1 + B2_VARIANT: debug,release + B2_LINK: shared,static + LCOV_BRANCH_COVERAGE: 1 + # gcov emits an unwind edge for every call it cannot prove nothrow, so any line + # calling e.g. BOOST_TEST_EQ carries a branch that is never taken. Drop those, + # and the lone fallthrough left behind, so only real conditionals are reported. + # region and branch_region are what implement the LCOV_EXCL_LINE, LCOV_EXCL_START + # and LCOV_EXCL_BR_* markers. lcov enables them by default only when --filter is + # absent, so they have to be listed here or every marker in the tree is ignored. + LCOV_OPTIONS: --filter region,branch_region,exception,orphan + CODECOV_NAME: Github Actions + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + +jobs: + posix: + defaults: + run: + shell: bash + + strategy: + fail-fast: false + matrix: + include: + - { name: Collect coverage, coverage: yes, + compiler: gcc-14, cxxstd: '23', os: ubuntu-24.04, install: 'g++-14', address-model: '64' } + + timeout-minutes: 120 + runs-on: ${{matrix.os}} + container: ${{matrix.container}} + env: {B2_USE_CCACHE: 1} + + steps: + - name: Setup environment + run: | + if [ -f "/etc/debian_version" ]; then + echo "DEBIAN_FRONTEND=noninteractive" >> $GITHUB_ENV + export DEBIAN_FRONTEND=noninteractive + fi + if [ -n "${{matrix.container}}" ] && [ -f "/etc/debian_version" ]; then + apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common curl + # Need (newer) git, and the older Ubuntu container may require requesting the key manually using port 80 + curl -sSL --retry ${NET_RETRY_COUNT:-5} 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0xE1DD270288B4E6030699E45FA1715D88E1DF1F24' | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/git-core_ubuntu_ppa.gpg + for i in {1..${NET_RETRY_COUNT:-3}}; do sudo -E add-apt-repository -y ppa:git-core/ppa && break || sleep 10; done + apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + osver=$(lsb_release -sr | cut -f1 -d.) + pkgs="g++ git" + # Ubuntu 22+ has only Python 3 in the repos + if [ -n "$osver" ] && [ "$osver" -ge "22" ]; then + pkgs+=" python-is-python3 libpython3-dev" + else + pkgs+=" python libpython-dev" + fi + apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y $pkgs + fi + # For jobs not compatible with ccache, use "ccache: no" in the matrix + if [[ "${{ matrix.ccache }}" == "no" ]]; then + echo "B2_USE_CCACHE=0" >> $GITHUB_ENV + fi + git config --global pack.threads 0 + + - uses: actions/checkout@v4 + with: + # For coverage builds fetch the whole history, else only 1 commit using a 'fake ternary' + fetch-depth: ${{ matrix.coverage && '0' || '1' }} + + - name: Cache ccache + uses: actions/cache@v4 + if: env.B2_USE_CCACHE + with: + path: ~/.ccache + key: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-${{github.sha}} + restore-keys: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}- + + - name: Fetch Boost.CI + uses: actions/checkout@v4 + with: + repository: boostorg/boost-ci + ref: master + path: boost-ci-cloned + + - name: Get CI scripts folder + run: | + # Copy ci folder if not testing Boost.CI + [[ "$GITHUB_REPOSITORY" =~ "boost-ci" ]] || cp -r boost-ci-cloned/ci . + rm -rf boost-ci-cloned + + - name: Install packages + if: startsWith(matrix.os, 'ubuntu') + run: | + SOURCE_KEYS=(${{join(matrix.source_keys, ' ')}}) + SOURCES=(${{join(matrix.sources, ' ')}}) + # Add this by default + SOURCES+=(ppa:ubuntu-toolchain-r/test) + for key in "${SOURCE_KEYS[@]}"; do + for i in {1..$NET_RETRY_COUNT}; do + keyfilename=$(basename -s .key $key) + curl -sSL --retry ${NET_RETRY_COUNT:-5} "$key" | sudo gpg --dearmor > /etc/apt/trusted.gpg.d/${keyfilename} && break || sleep 10 + done + done + for source in "${SOURCES[@]}"; do + for i in {1..$NET_RETRY_COUNT}; do + sudo add-apt-repository $source && break || sleep 10 + done + done + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + if [[ -z "${{matrix.install}}" ]]; then + pkgs="${{matrix.compiler}}" + pkgs="${pkgs/gcc-/g++-}" + else + pkgs="${{matrix.install}}" + fi + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y $pkgs + + - name: Setup GCC Toolchain + if: matrix.gcc_toolchain + run: | + GCC_TOOLCHAIN_ROOT="$HOME/gcc-toolchain" + echo "GCC_TOOLCHAIN_ROOT=$GCC_TOOLCHAIN_ROOT" >> $GITHUB_ENV + if ! command -v dpkg-architecture; then + apt-get install -y dpkg-dev + fi + MULTIARCH_TRIPLET="$(dpkg-architecture -qDEB_HOST_MULTIARCH)" + mkdir -p "$GCC_TOOLCHAIN_ROOT" + ln -s /usr/include "$GCC_TOOLCHAIN_ROOT/include" + ln -s /usr/bin "$GCC_TOOLCHAIN_ROOT/bin" + mkdir -p "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET" + ln -s "/usr/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" + + - name: Setup multiarch + if: matrix.multiarch + run: | + sudo apt-get install --no-install-recommends -y binfmt-support qemu-user-static + sudo docker run --rm --privileged multiarch/qemu-user-static --reset -p yes + git clone https://github.com/jeking3/bdde.git + echo "$(pwd)/bdde/bin/linux" >> ${GITHUB_PATH} + echo "BDDE_DISTRO=${{ matrix.distro }}" >> ${GITHUB_ENV} + echo "BDDE_EDITION=${{ matrix.edition }}" >> ${GITHUB_ENV} + echo "BDDE_ARCH=${{ matrix.arch }}" >> ${GITHUB_ENV} + echo "B2_WRAPPER=bdde" >> ${GITHUB_ENV} + + - name: Setup Boost + env: + B2_ADDRESS_MODEL: ${{matrix.address-model}} + B2_COMPILER: ${{matrix.compiler}} + B2_CXXSTD: ${{matrix.cxxstd}} + B2_SANITIZE: ${{matrix.sanitize}} + B2_STDLIB: ${{matrix.stdlib}} + # More entries can be added in the same way, see the B2_ARGS assignment in ci/enforce.sh for the possible keys. + B2_DEFINES: ${{matrix.defines}} + # Variables set here (to non-empty) will override the top-level environment variables, e.g. + B2_VARIANT: ${{matrix.variant}} + # Set the (B2) target(s) to build, defaults to the test folder of the current library + # Can alternatively be done like this in the build step or in the build command of the build step, e.g. `run: B2_TARGETS=libs/$SELF/doc ci/build.sh` + # B2_TARGETS: libs/foo/test//bar + run: source ci/github/install.sh + + - name: Setup coverage collection + if: matrix.coverage + run: ci/github/codecov.sh "setup" + + - name: Run tests + if: '!matrix.coverity' + run: ci/build.sh + + - name: Upload coverage + if: matrix.coverage + run: ci/codecov.sh "upload" + env: + BOOST_CI_CODECOV_IO_UPLOAD: skip + + - name: Upload coverage + if: matrix.coverage + uses: codecov/codecov-action@v4 + with: + disable_search: true + file: coverage.info + name: Github Actions + token: ${{secrets.CODECOV_TOKEN}} + verbose: true + + windows: + defaults: + run: + shell: cmd + strategy: + fail-fast: false + matrix: + include: + - { name: Collect MSVC coverage, coverage: yes, + toolset: msvc-14.3, cxxstd: 'latest', addrmd: '64', os: windows-2022 } + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v4 + + - name: Fetch Boost.CI + uses: actions/checkout@v4 + with: + repository: boostorg/boost-ci + ref: master + path: boost-ci-cloned + - name: Get CI scripts folder + run: | + REM Copy ci folder if not testing Boost.CI + if "%GITHUB_REPOSITORY%" == "%GITHUB_REPOSITORY:boost-ci=%" xcopy /s /e /q /i /y boost-ci-cloned\ci .\ci + rmdir /s /q boost-ci-cloned + - name: Setup Boost + run: ci\github\install.bat + + - name: Run tests + if: '!matrix.coverage' + run: ci\build.bat + env: + B2_TOOLSET: ${{matrix.toolset}} + B2_CXXSTD: ${{matrix.cxxstd}} + B2_ADDRESS_MODEL: ${{matrix.addrmd}} + B2_DEFINES: ${{matrix.defines}} + B2_VARIANT: ${{matrix.variant}} + B2_LINK: ${{matrix.link}} + + - name: Collect coverage + shell: powershell + if: matrix.coverage + run: ci\opencppcoverage.ps1 + env: + B2_TOOLSET: ${{matrix.toolset}} + B2_CXXSTD: ${{matrix.cxxstd}} + B2_ADDRESS_MODEL: ${{matrix.addrmd}} + B2_DEFINES: ${{matrix.defines}} + B2_VARIANT: ${{matrix.variant}} + B2_LINK: ${{matrix.link}} + + - name: Upload + uses: codecov/codecov-action@v5 + with: + disable_search: true + files: __out/cobertura.xml + name: ${{env.CODECOV_NAME}} (Windows) + token: ${{secrets.CODECOV_TOKEN}} + verbose: true \ No newline at end of file diff --git a/.github/workflows/dependency-count-comment.yml b/.github/workflows/dependency-count-comment.yml new file mode 100644 index 000000000..ddf49b0a1 --- /dev/null +++ b/.github/workflows/dependency-count-comment.yml @@ -0,0 +1,61 @@ +name: dependency-count-comment + +on: + workflow_run: + workflows: ["dependency-report"] + types: [completed] + +permissions: + actions: read + pull-requests: write + contents: read + +jobs: + comment: + if: github.event.workflow_run.event == 'pull_request' + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + PR_RUN: ${{ github.event.workflow_run.id }} + HEAD_SHA: ${{ github.event.workflow_run.head_sha }} + steps: + - uses: actions/checkout@v4 + + - name: Download this PR run's log archive + run: gh api "repos/$REPO/actions/runs/$PR_RUN/logs" > pr-logs.zip + + - name: Download latest successful develop run's log archive + run: | + DEV=$(gh run list --workflow dependency-report --branch develop --status success \ + --limit 1 --json databaseId --jq '.[0].databaseId') + if [ -z "$DEV" ]; then echo "no develop baseline run found" >&2; exit 1; fi + echo "DEV_RUN=$DEV" >> "$GITHUB_ENV" + gh api "repos/$REPO/actions/runs/$DEV/logs" > base-logs.zip + + - name: Generate table + run: | + { + echo "Boost dependency footprint vs \`develop\` (auto-generated)." + echo "PR run \`$PR_RUN\` vs develop run \`$DEV_RUN\` (\`${HEAD_SHA:0:10}\`)." + echo + python3 .github/scripts/dep_table.py base-logs.zip pr-logs.zip + } > table.md + + - name: Resolve PR number + id: pr + run: | + num=$(gh api "repos/$REPO/pulls?state=open&per_page=100" \ + --jq "map(select(.head.sha==\"$HEAD_SHA\"))[0].number") + if [ -z "$num" ]; then + echo "no open PR found with head $HEAD_SHA" >&2 + exit 1 + fi + echo "num=$num" >> "$GITHUB_OUTPUT" + + - name: Post or update sticky comment + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: dependency-counts + number: ${{ steps.pr.outputs.num }} + path: table.md diff --git a/.github/workflows/dependency-report.yml b/.github/workflows/dependency-report.yml new file mode 100644 index 000000000..c788d5e06 --- /dev/null +++ b/.github/workflows/dependency-report.yml @@ -0,0 +1,42 @@ +name: dependency-report + +# Computes graph's Boost dependency footprint with boostdep and prints a +# marker-delimited report into the job log, on every push and PR. The +# dependency-count-comment workflow reads these logs (this PR's run and the +# latest develop run) and posts the diff as a PR comment. Kept separate from +# CI so ci.yml is untouched. + +on: [ push, pull_request ] + +jobs: + deps: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - name: Set up Boost tree and build boostdep + run: | + git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root + cd ../boost-root + cp -r $GITHUB_WORKSPACE/* libs/graph + git submodule update --init tools/boostdep + # depinst pulls graph's deps; also ensure boostdep's own dep + # (Boost.Filesystem) is present since boostdep links against it. + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" graph + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" filesystem + ./bootstrap.sh + ./b2 headers + # boostdep #includes and links the compiled + # library, so build it with b2 (a bare c++ compile can't resolve that). + ./b2 tools/boostdep/build + - name: Boostdep dependency report + working-directory: ../boost-root + run: | + BOOSTDEP=$(find "$PWD" -type f -name boostdep -perm -u+x 2>/dev/null | grep -v '/src/' | head -1) + if [ -z "$BOOSTDEP" ]; then echo "boostdep executable not found after build" >&2; exit 1; fi + echo "using boostdep: $BOOSTDEP" + echo "===DEP-BRIEF-START===" + "$BOOSTDEP" --boost-root . --track-sources --no-track-tests --brief graph + echo "===DEP-BRIEF-END===" + echo "===DEP-PRIMARY-START===" + "$BOOSTDEP" --boost-root . --track-sources --no-track-tests graph + echo "===DEP-PRIMARY-END===" diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 58eb9e5ab..696d7eb6c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -7,7 +7,7 @@ name: docs-check # includes, broken xrefs) # # No deployment. The real publishing path is boostorg/release-tools, -# which auto-detects doc/build_antora.sh and ships to +# which builds via doc/Jamfile.v2 (boostrelease target) and ships to # www.boost.org/doc/libs//libs/graph/. on: @@ -25,6 +25,12 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Install Stanford GraphBase + run: | + sudo add-apt-repository -y multiverse + sudo apt-get update + sudo apt-get install -y sgb + - name: Install Node 20 uses: actions/setup-node@v4 with: @@ -40,7 +46,7 @@ jobs: git submodule update --init tools/boostdep rm -rf libs/graph cp -r "$GITHUB_WORKSPACE" libs/graph - python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" graph + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" -I doc/modules/ROOT/examples graph git submodule update --init --depth 1 libs/static_assert ./bootstrap.sh ./b2 headers @@ -59,4 +65,4 @@ jobs: # against the committed package-lock.json. - name: Build the site (release-tools entry point) working-directory: doc - run: ./build_antora.sh playbook.yml + run: ./build_antora.sh diff --git a/.gitignore b/.gitignore index 4786df32c..f64ed44e8 100644 --- a/.gitignore +++ b/.gitignore @@ -11,10 +11,6 @@ example/routing-table.dat example/figs/ospf-sptree.dot CMakeFiles/ -# Antora docs build artifacts -doc/build/ -doc/node_modules/ - # macOS .DS_Store **/.DS_Store diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c9c7f9b5..3c22f7f89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,41 +21,31 @@ target_link_libraries(boost_graph Boost::any Boost::array Boost::assert - Boost::bimap Boost::concept_check Boost::config Boost::container_hash - Boost::conversion Boost::core Boost::detail - Boost::foreach Boost::function Boost::integer Boost::iterator Boost::lexical_cast - Boost::math - Boost::move + Boost::mp11 Boost::mpl Boost::multi_index - Boost::multiprecision + Boost::int128 Boost::optional Boost::parameter Boost::preprocessor Boost::property_map - Boost::property_tree Boost::random Boost::range Boost::serialization - Boost::smart_ptr - Boost::spirit Boost::throw_exception - Boost::tti Boost::tuple Boost::type_traits - Boost::typeof Boost::unordered Boost::utility - Boost::xpressive PRIVATE Boost::regex ) diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..127a5bc39 --- /dev/null +++ b/LICENSE @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 80859a5c3..7480e378b 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ # Boost Graph Library -[![Docs](https://img.shields.io/badge/docs-boost.org-blue.svg)](https://www.boost.org/doc/libs/release/libs/graph/doc/index.html) -[![C++14](https://img.shields.io/badge/C%2B%2B-14-blue.svg)](https://en.cppreference.com/w/cpp/14) -[![CI](https://github.com/boostorg/graph/actions/workflows/ci.yml/badge.svg)](https://github.com/boostorg/graph/actions/workflows/ci.yml) -[![License: BSL-1.0](https://img.shields.io/badge/License-BSL_1.0-blue.svg)](https://www.boost.org/LICENSE_1_0.txt) -[![Boost release](https://img.shields.io/github/v/release/boostorg/boost?label=Boost&color=orange)](https://github.com/boostorg/boost/releases) +[![Branch](https://img.shields.io/badge/branch-master-brightgreen.svg)](https://github.com/boostorg/graph/tree/master) [![Documentation](https://img.shields.io/badge/docs-master-brightgreen.svg)](https://www.boost.org/doc/libs/master/libs/graph/doc/html/graph/index.html) [![CI](https://github.com/boostorg/graph/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/graph/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/boostorg/graph/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/graph/branch/master) [![Deps](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/graph.html) [![Enter the Matrix](https://img.shields.io/badge/matrix-master-brightgreen.svg)](https://regression.boost.org/master/developer/graph.html)
+[![Branch](https://img.shields.io/badge/branch-develop-brightgreen.svg)](https://github.com/boostorg/graph/tree/develop) [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](https://www.boost.org/doc/libs/develop/libs/graph/doc/html/graph/index.html) [![CI](https://github.com/boostorg/graph/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/graph/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/boostorg/graph/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/graph/branch/develop) [![Deps](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/graph.html) [![Enter the Matrix](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](https://regression.boost.org/develop/developer/graph.html)
+[![Docs](https://img.shields.io/badge/docs-boost.org-blue.svg)](https://www.boost.org/doc/libs/release/libs/graph/doc/index.html) [![C++14](https://img.shields.io/badge/C%2B%2B-14-blue.svg)](https://en.cppreference.com/w/cpp/14) [![License: BSL-1.0](https://img.shields.io/badge/License-BSL_1.0-blue.svg)](https://www.boost.org/LICENSE_1_0.txt) [![Boost release](https://img.shields.io/github/v/release/boostorg/boost?label=Boost&color=orange)](https://github.com/boostorg/boost/releases) The Boost Graph Library (BGL) is a generic library that allows users to: diff --git a/build.jam b/build.jam index af9f24242..37853d0ae 100644 --- a/build.jam +++ b/build.jam @@ -10,42 +10,31 @@ constant boost_dependencies : /boost/any//boost_any /boost/array//boost_array /boost/assert//boost_assert - /boost/bimap//boost_bimap - /boost/bind//boost_bind /boost/concept_check//boost_concept_check /boost/config//boost_config /boost/container_hash//boost_container_hash - /boost/conversion//boost_conversion /boost/core//boost_core /boost/detail//boost_detail - /boost/foreach//boost_foreach /boost/function//boost_function /boost/integer//boost_integer /boost/iterator//boost_iterator /boost/lexical_cast//boost_lexical_cast - /boost/math//boost_math_tr1 - /boost/move//boost_move + /boost/mp11//boost_mp11 /boost/mpl//boost_mpl /boost/multi_index//boost_multi_index - /boost/multiprecision//boost_multiprecision + /boost/int128//boost_int128 /boost/optional//boost_optional /boost/parameter//boost_parameter /boost/preprocessor//boost_preprocessor /boost/property_map//boost_property_map - /boost/property_tree//boost_property_tree /boost/random//boost_random /boost/range//boost_range /boost/serialization//boost_serialization - /boost/smart_ptr//boost_smart_ptr - /boost/spirit//boost_spirit /boost/throw_exception//boost_throw_exception - /boost/tti//boost_tti /boost/tuple//boost_tuple /boost/type_traits//boost_type_traits - /boost/typeof//boost_typeof /boost/unordered//boost_unordered - /boost/utility//boost_utility - /boost/xpressive//boost_xpressive ; + /boost/utility//boost_utility ; project /boost/graph ; diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index b213e5498..882f6fb5b 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -4,8 +4,6 @@ # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) -import mpi ; - constant boost_dependencies_private : /boost/regex//boost_regex ; diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 000000000..34b23da89 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,2 @@ +/build/ +/node_modules/ diff --git a/doc/CONTRIBUTING.md b/doc/CONTRIBUTING.md index d3813bf0c..7d2e370b3 100644 --- a/doc/CONTRIBUTING.md +++ b/doc/CONTRIBUTING.md @@ -11,7 +11,7 @@ sources under `doc/modules/ROOT/`. | `doc/modules/ROOT/examples/` | One `.cpp` per page; the build script captures stdout into a sibling `.txt` | | `doc/modules/ROOT/nav.adoc` | Left-side navigation tree | | `doc/templates/` | Starter templates: `algorithm.adoc`, `generator.adoc`, `graph_class.adoc` — copy and fill in | -| `doc/playbook.yml` | Antora playbook (UI bundle, content sources) | +| `doc/graph-playbook.yml` | Antora playbook (UI bundle, content sources) | | `doc/modules/ROOT/examples/Jamfile` | b2 rules that compile every example and snapshot its stdout into a sibling `.txt` | | `doc/build_example_outputs.sh`| g++-only fallback that does the same thing as the Jamfile, for contributors without a `boost-root` checkout | @@ -37,11 +37,11 @@ b2 libs/graph/doc/modules/ROOT/examples # 2) Build the static site. cd libs/graph -npx antora doc/playbook.yml +npx antora doc/graph-playbook.yml # 3) Open the result. -open doc/build/site/index.html # macOS -xdg-open doc/build/site/index.html # Linux +open doc/html/index.html # macOS +xdg-open doc/html/index.html # Linux ``` CI runs the same commands on every push. diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 new file mode 100644 index 000000000..476ed98e2 --- /dev/null +++ b/doc/Jamfile.v2 @@ -0,0 +1,28 @@ +# Copyright 2026 Arnaud Becheler +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +import path ; + +make html_ : build_antora.sh : @run-script ; + +actions run-script +{ + bash $(>) +} + +path-constant DOC_DIR : . ; +.node_modules = [ path.join $(DOC_DIR) node_modules ] ; + +make cleanup_node_modules_ : html_ : @cleanup-node-modules ; + +actions cleanup-node-modules +{ + rm -rf $(.node_modules) +} + +############################################################################### +alias boostdoc ; +explicit boostdoc ; +alias boostrelease : html_ cleanup_node_modules_ ; +explicit boostrelease ; diff --git a/doc/antora.yml b/doc/antora.yml index 07e646cec..047c7308e 100644 --- a/doc/antora.yml +++ b/doc/antora.yml @@ -2,9 +2,5 @@ name: graph version: ~ title: Boost.Graph start_page: index.adoc -asciidoc: - attributes: - source-language: cpp@ - table-caption: false nav: - modules/ROOT/nav.adoc diff --git a/doc/build_antora.sh b/doc/build_antora.sh index bdeda74f0..b4f72a530 100755 --- a/doc/build_antora.sh +++ b/doc/build_antora.sh @@ -3,28 +3,14 @@ # Distributed under the Boost Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) # -# Official repository: https://github.com/boostorg/graph -# -# Picked up by boostorg/release-tools' build_docs/{linuxdocs.sh,macosdocs.sh, -# windowsdocs.ps1} via auto-detection: presence of this file selects the -# Antora build pipeline. Output lands in doc/build/site/. +# Run by boostorg/release-tools via the doc/Jamfile.v2 boostrelease target, +# following the boostorg/unordered scheme. Output lands in doc/html/. -set -xe +set -ex SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) cd "$SCRIPT_DIR" -if [ $# -eq 0 ]; then - PLAYBOOK="playbook.yml" -else - PLAYBOOK="$1" -fi - -echo "Installing npm dependencies..." npm ci - -echo "Building docs with Antora using $PLAYBOOK..." -PATH="$(pwd)/node_modules/.bin:${PATH}" -export PATH -npx antora --clean --fetch "$PLAYBOOK" -echo "Done" +npx antora graph-playbook.yml +cp -f html/index.html html/graph.html diff --git a/doc/build_example_outputs.sh b/doc/build_example_outputs.sh index c764513e0..d416e041b 100755 --- a/doc/build_example_outputs.sh +++ b/doc/build_example_outputs.sh @@ -35,6 +35,9 @@ extra_libs_for() { io/graphml.cpp|io/graphviz.cpp|algorithms/isomorphism/isomorphism.cpp) echo "-lboost_graph" ;; + extending/sgb_miles_span.cpp) + echo "-lgb" + ;; *) echo "" ;; diff --git a/doc/graph-playbook.yml b/doc/graph-playbook.yml new file mode 100644 index 000000000..c583aa381 --- /dev/null +++ b/doc/graph-playbook.yml @@ -0,0 +1,21 @@ +output: + dir: html + +site: + title: Boost.Graph Documentation + start_page: graph::index.adoc + +antora: + extensions: + - require: '@cppalliance/antora-downloads-extension' + +content: + sources: + - url: .. + start_path: doc + branches: HEAD + +ui: + bundle: + url: https://github.com/boostorg/graph-ui-bundle/raw/c80db72a7ba804256beb36e3a46d9c7df265d8d7/ui-bundle.zip + output_dir: graph/_ diff --git a/doc/index.html b/doc/index.html deleted file mode 100644 index 2df8130a6..000000000 --- a/doc/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - Boost.Graph - - - - Automatic redirection failed, please go to - ../../../doc/antora/graph/index.html -
- - Boost.Graph
-
- Distributed under the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt)
-
-
- - diff --git a/doc/modules/ROOT/examples/Jamfile b/doc/modules/ROOT/examples/Jamfile index d1ab6204d..e09365dea 100644 --- a/doc/modules/ROOT/examples/Jamfile +++ b/doc/modules/ROOT/examples/Jamfile @@ -29,6 +29,10 @@ local needs-graph-lib = algorithms/isomorphism/isomorphism.cpp ; +local needs-sgb-lib = + extending/sgb_miles_span.cpp + ; + # Capture stdout of the input executable into the output file. actions snapshot { @@ -49,6 +53,10 @@ for local cpp in $(examples) { libs = /boost/graph//boost_graph ; } + if $(rel) in $(needs-sgb-lib) + { + libs = -lgb ; + } exe $(name) : $(cpp) : $(libs) ; make $(name).txt diff --git a/doc/modules/ROOT/examples/algorithms/network_flow/stoer_wagner.cpp b/doc/modules/ROOT/examples/algorithms/network_flow/stoer_wagner.cpp index edd98f317..0f859a8a8 100644 --- a/doc/modules/ROOT/examples/algorithms/network_flow/stoer_wagner.cpp +++ b/doc/modules/ROOT/examples/algorithms/network_flow/stoer_wagner.cpp @@ -5,20 +5,19 @@ struct EdgeProps { int weight; }; -using namespace boost; - -using Graph = adjacency_list; +using Graph = boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS, + boost::no_property, EdgeProps >; int main() { Graph g{4}; - add_edge(0, 1, EdgeProps{2}, g); - add_edge(0, 2, EdgeProps{3}, g); - add_edge(1, 2, EdgeProps{3}, g); - add_edge(1, 3, EdgeProps{2}, g); - add_edge(2, 3, EdgeProps{4}, g); + boost::add_edge(0, 1, EdgeProps{2}, g); + boost::add_edge(0, 2, EdgeProps{3}, g); + boost::add_edge(1, 2, EdgeProps{3}, g); + boost::add_edge(1, 3, EdgeProps{2}, g); + boost::add_edge(2, 3, EdgeProps{4}, g); auto weight_map = get(&EdgeProps::weight, g); - int cut = stoer_wagner_min_cut(g, weight_map); + // only the min-cut weight is needed here, so discard the partition + int cut = boost::graph::stoer_wagner_min_cut(g, weight_map, boost::dummy_property_map()); std::cout << "Stoer-Wagner min cut: " << cut << "\n"; } diff --git a/doc/modules/ROOT/examples/algorithms/shortest_paths/r_c_shortest.cpp b/doc/modules/ROOT/examples/algorithms/shortest_paths/r_c_shortest.cpp index 7e524e1e0..3b5bed2de 100644 --- a/doc/modules/ROOT/examples/algorithms/shortest_paths/r_c_shortest.cpp +++ b/doc/modules/ROOT/examples/algorithms/shortest_paths/r_c_shortest.cpp @@ -42,7 +42,7 @@ int main() { std::vector path; Res result{0, 0}; - r_c_shortest_paths(g, get(vertex_index, g), get(&Edge::idx, g), + r_c_shortest_paths(g, get(vertex_index, g), vertex(0, g), vertex(3, g), path, result, Res{0, 0}, ResExt{}, Dom{}); diff --git a/doc/modules/ROOT/examples/algorithms/utility/maximum_adjacency_search.cpp b/doc/modules/ROOT/examples/algorithms/utility/maximum_adjacency_search.cpp index 5d754c3d6..e70d14503 100644 --- a/doc/modules/ROOT/examples/algorithms/utility/maximum_adjacency_search.cpp +++ b/doc/modules/ROOT/examples/algorithms/utility/maximum_adjacency_search.cpp @@ -1,26 +1,52 @@ #include #include +#include +#include +#include #include #include struct Edge { int weight; }; -int main() { - using namespace boost; - using Graph = adjacency_list; +using Graph = boost::adjacency_list; +using vertex_descriptor = boost::graph_traits::vertex_descriptor; +using weight_type = int; + +// records the vertices in the order the search visits them +struct order_recorder : boost::graph::default_mas_visitor { + std::vector order; + void finish_vertex(vertex_descriptor u, const Graph&) { order.push_back(u); } +}; +int main() { Graph g(5); - add_edge(0, 1, Edge{2}, g); - add_edge(0, 4, Edge{3}, g); - add_edge(1, 2, Edge{3}, g); - add_edge(1, 4, Edge{2}, g); - add_edge(2, 3, Edge{4}, g); - add_edge(3, 4, Edge{1}, g); - - // Bundled weight via member pointer — passed through the named parameter. - maximum_adjacency_search(g, - boost::weight_map(get(&Edge::weight, g))); - - std::cout << "Maximum adjacency search completed\n"; - std::cout << "Last vertex visited has highest connectivity\n"; + boost::add_edge(0, 1, Edge{2}, g); + boost::add_edge(0, 4, Edge{3}, g); + boost::add_edge(1, 2, Edge{3}, g); + boost::add_edge(1, 4, Edge{2}, g); + boost::add_edge(2, 3, Edge{4}, g); + boost::add_edge(3, 4, Edge{1}, g); + + auto weight_map = boost::get(&Edge::weight, g); + + // keyed max priority queue the search runs on: reach counts plus heap positions + using index_map_type = boost::property_map::const_type; + using distances_map_type = boost::shared_array_property_map; + using index_in_heap_type = std::vector::size_type; + using indices_map_type = boost::shared_array_property_map; + using max_priority_queue_type = boost::d_ary_heap_indirect>; + + auto distances_map = boost::make_shared_array_property_map(boost::num_vertices(g), weight_type(0), boost::get(boost::vertex_index, g)); + auto indices_map = boost::make_shared_array_property_map(boost::num_vertices(g), index_in_heap_type(-1), boost::get(boost::vertex_index, g)); + max_priority_queue_type pq(distances_map, indices_map); + + order_recorder visitor; + vertex_descriptor start = *boost::vertices(g).first; + + // std::ref lets the visitor keep its state across the copy the algorithm makes + boost::graph::maximum_adjacency_search(g, weight_map, std::ref(visitor), start, pq); + + std::cout << "Visit order:"; + for (vertex_descriptor v : visitor.order) std::cout << ' ' << v; + std::cout << "\nLast visited vertex (highest connectivity): " << visitor.order.back() << '\n'; } diff --git a/doc/modules/ROOT/examples/algorithms/utility/maximum_adjacency_search.txt b/doc/modules/ROOT/examples/algorithms/utility/maximum_adjacency_search.txt index 3660ba478..f720a5ee1 100644 --- a/doc/modules/ROOT/examples/algorithms/utility/maximum_adjacency_search.txt +++ b/doc/modules/ROOT/examples/algorithms/utility/maximum_adjacency_search.txt @@ -1,2 +1,2 @@ -Maximum adjacency search completed -Last vertex visited has highest connectivity +Visit order: 0 4 1 2 3 +Last visited vertex (highest connectivity): 3 diff --git a/doc/modules/ROOT/examples/algorithms/utility/maximum_adjacency_search_default_queue.cpp b/doc/modules/ROOT/examples/algorithms/utility/maximum_adjacency_search_default_queue.cpp new file mode 100644 index 000000000..5b6c57eb3 --- /dev/null +++ b/doc/modules/ROOT/examples/algorithms/utility/maximum_adjacency_search_default_queue.cpp @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +struct Edge { int weight; }; + +using Graph = boost::adjacency_list; +using vertex_descriptor = boost::graph_traits::vertex_descriptor; + +// records the vertices in the order the search visits them +struct order_recorder : boost::graph::default_mas_visitor { + std::vector order; + void finish_vertex(vertex_descriptor u, const Graph&) { order.push_back(u); } +}; + +int main() { + Graph g(5); + boost::add_edge(0, 1, Edge{2}, g); + boost::add_edge(0, 4, Edge{3}, g); + boost::add_edge(1, 2, Edge{3}, g); + boost::add_edge(1, 4, Edge{2}, g); + boost::add_edge(2, 3, Edge{4}, g); + boost::add_edge(3, 4, Edge{1}, g); + + auto weight_map = boost::get(&Edge::weight, g); + + order_recorder visitor; + + // std::ref lets the visitor keep its state across the copy the algorithm makes + boost::graph::maximum_adjacency_search(g, weight_map, std::ref(visitor), *vertices(g).first); + + std::cout << "Visit order:"; + for (vertex_descriptor v : visitor.order) std::cout << ' ' << v; + std::cout << "\nLast visited vertex (highest connectivity): " << visitor.order.back() << '\n'; +} diff --git a/doc/modules/ROOT/examples/algorithms/utility/maximum_adjacency_search_default_queue.txt b/doc/modules/ROOT/examples/algorithms/utility/maximum_adjacency_search_default_queue.txt new file mode 100644 index 000000000..f720a5ee1 --- /dev/null +++ b/doc/modules/ROOT/examples/algorithms/utility/maximum_adjacency_search_default_queue.txt @@ -0,0 +1,2 @@ +Visit order: 0 4 1 2 3 +Last visited vertex (highest connectivity): 3 diff --git a/doc/modules/ROOT/examples/extending/sgb_miles_span.cpp b/doc/modules/ROOT/examples/extending/sgb_miles_span.cpp new file mode 100644 index 000000000..6fea29731 --- /dev/null +++ b/doc/modules/ROOT/examples/extending/sgb_miles_span.cpp @@ -0,0 +1,51 @@ +#include +#include +#include + +// Accumulates the Prim distance labels as vertices are finalized. +// Each label is the weight of the edge that joined the vertex to the tree. +template +struct total_length_visitor : boost::dijkstra_visitor<> { + using length_type = typename boost::property_traits::value_type; + + total_length_visitor(length_type& t, DistanceMap d) : total(t), distance_map(d) {} + + template + void finish_vertex(Vertex v, const Graph&) { total += boost::get(distance_map, v); } + + length_type& total; + DistanceMap distance_map; +}; + +int main() { + // Native Stanford GraphBase graph built from real city mileage data. + const unsigned long city_count = 100; + const long north_weight = 0; + const long west_weight = 0; + const long population_weight = 0; + const unsigned long max_distance = 0; + const unsigned long max_degree = 10; + const long seed = 0; + Graph* g = miles(city_count, north_weight, west_weight, population_weight, max_distance, max_degree, seed); + if (g == nullptr) { + std::cerr << "Could not build the miles graph, SGB panic code " << panic_code << "\n"; + return 1; + } + + // Prim reuses the SGB per vertex utility fields as its work maps. + auto distance_map = boost::get(boost::z_property(), g); + auto parent_map = boost::get(boost::w_property(), g); + auto weight_map = boost::get(boost::edge_length_t(), g); + auto index_map = boost::get(boost::vertex_index, g); + + long total_length = 0; + total_length_visitor vis(total_length, distance_map); + + auto root = *boost::vertices(g).first; + boost::prim_minimum_spanning_tree(g, root, parent_map, distance_map, weight_map, index_map, vis); + + std::cout << "Graph ID: " << g->id << "\n"; + std::cout << "Minimum spanning tree length: " << total_length << "\n"; + + gb_recycle(g); +} diff --git a/doc/modules/ROOT/examples/extending/sgb_miles_span.txt b/doc/modules/ROOT/examples/extending/sgb_miles_span.txt new file mode 100644 index 000000000..b052414a5 --- /dev/null +++ b/doc/modules/ROOT/examples/extending/sgb_miles_span.txt @@ -0,0 +1,2 @@ +Graph ID: miles(100,0,0,0,0,10,0) +Minimum spanning tree length: 14467 diff --git a/doc/modules/ROOT/nav.adoc b/doc/modules/ROOT/nav.adoc index ab05a9feb..35f2ac387 100644 --- a/doc/modules/ROOT/nav.adoc +++ b/doc/modules/ROOT/nav.adoc @@ -202,7 +202,8 @@ * xref:extending/overview.adoc[Extending the BGL] ** xref:extending/constructing_algorithms.adoc[Worked Example: Graph Coloring] ** xref:extending/custom_storage.adoc[Custom Adjacency List Storage] -** xref:extending/leda_conversion.adoc[Adapting Existing Graph Structures] +** xref:extending/leda_conversion.adoc[LEDA Graph Interface] +** xref:extending/stanford_graph.adoc[Stanford GraphBase Interface] * xref:about/overview.adoc[About] ** xref:about/design.adoc[Design Rationale] ** xref:about/graph_theory_review.adoc[Graph Theory Review] diff --git a/doc/modules/ROOT/pages/about/users.adoc b/doc/modules/ROOT/pages/about/users.adoc index 439383ea4..109838d23 100644 --- a/doc/modules/ROOT/pages/about/users.adoc +++ b/doc/modules/ROOT/pages/about/users.adoc @@ -33,3 +33,4 @@ course at DataSim] Intelligence framework] * https://www.pgRouting.org/[pgRouting extends the PostGIS/PostgreSQL geospatial database to provide geospatial routing functionality.] +* https://doc.cgal.org/latest/Manual/packages.html#PkgBGL[CGAL, the Computational Geometry Algorithms Library, provides models for the Graph concept, and introduces the concept FaceGraph] diff --git a/doc/modules/ROOT/pages/adaptors/subgraph.adoc b/doc/modules/ROOT/pages/adaptors/subgraph.adoc index 294ff9776..689a35195 100644 --- a/doc/modules/ROOT/pages/adaptors/subgraph.adoc +++ b/doc/modules/ROOT/pages/adaptors/subgraph.adoc @@ -30,18 +30,47 @@ template class subgraph; ---- -The `subgraph` class wraps an `adjacency_list` and maintains a tree of -subgraphs. The root graph owns all vertices and edges. Child subgraphs hold -subsets of the root's vertices, and their edge sets are _induced_: any edge in -the root whose both endpoints are in the child automatically appears in the -child. - -Each subgraph uses _local_ descriptors (0-based within that subgraph). Use -`local_to_global()` and `global_to_local()` to convert between local and root -descriptors. - -Adding an edge to a child subgraph also adds it to all ancestor subgraphs. -Adding a vertex to a child subgraph also adds it to all ancestors. +`subgraph` represents parts of a single graph as independent graphs, without +copying the data and without the parts drifting out of sync with the whole. All +vertices and edges are stored once, in the root graph. Each subgraph is a +lightweight view onto a subset of that storage which still behaves like a full +graph, so it can be passed to any BGL algorithm. + +[TIP] +==== +Consider a national road network: intersections are vertices and roads are +edges. An analysis might focus on one city, then one district within that city, +then compare against the whole country. Rather than three separate copies kept +consistent by hand, `subgraph` keeps one dataset and offers lightweight views +onto its parts. The country is the root, a city is a child subgraph, and a +district is a child of that city. Each view behaves like a normal graph and can +be handed to an algorithm such as `dijkstra_shortest_paths` exactly like any +other BGL graph. +==== + +These views nest into a tree. The _root_ subgraph holds the entire graph and +owns all of its vertices and edges. Each _child_ is a subset of its parent's +vertices, and a child may in turn have children of its own. A child's edges are +_induced_: an edge belongs to a child exactly when both of its endpoints do, so +only vertices are ever added to a child, never edges directly. + +Because the storage is shared rather than copied, the levels stay linked in both +directions. A property set at one level, such as an edge weight or a vertex +color, is visible from every level. Adding a vertex or edge to a child also adds +it to every ancestor up to the root, so an edit made while working on one part +keeps the whole hierarchy consistent. + +Each subgraph numbers its own vertices and edges 0-based, as required by the +many algorithms that assume a contiguous index space. A descriptor is therefore +meaningful only within one subgraph. `local_to_global()` and `global_to_local()` +translate a descriptor between a subgraph's local numbering and the root's. + +Choosing among the graph views: + +* `filtered_graph` for a read-only view that hides some vertices or edges. +* `copy_graph` for an independent copy that does not stay linked to the original. +* `subgraph` when mutability, per-region local numbering, and a parent/child + hierarchy over shared storage are all needed. == Template Parameters @@ -102,16 +131,49 @@ edge_descriptor global_to_local(edge_descriptor e_global) const; Convert between local (subgraph-relative) and global (root) descriptors. +[WARNING] +==== +These conversions have preconditions, and the two directions differ. + +* `global_to_local` requires that the element is in this subgraph. In debug +builds a violation trips `BOOST_ASSERT`; with assertions disabled it returns a +default-constructed descriptor (`null_vertex()` for vertices). When the element +might not be present, query membership first with `find_vertex()` or +`find_edge()`. +* `local_to_global` requires a valid local descriptor of this subgraph. A +violation is undefined behaviour (an unchecked lookup) in all build +configurations. + +On the root subgraph every conversion is the identity, so any element is +accepted. +==== + ''' [source,cpp] ---- std::pair find_vertex(vertex_descriptor u_global) const; + +std::pair +find_edge(edge_descriptor e_global) const; ---- -Returns `(local_descriptor, true)` if the global vertex is in this subgraph, -`(_, false)` otherwise. +Membership queries that never assert. `find_vertex` returns +`(local_descriptor, true)` if the global vertex is in this subgraph, and +`(null_vertex(), false)` otherwise. `find_edge` behaves the same way for edges, +returning a default-constructed `edge_descriptor` in the not-found case. These +are the safe form of `global_to_local`, for the case where the element is not +known in advance to be in the subgraph. + +[NOTE] +==== +*Descriptor identity and stability.* For an element that is present, the +conversions round-trip: `global_to_local(local_to_global(x)) == x`, and the +edge index is preserved. Properties live in the root's storage and are shared +across the whole tree, so the same logical element carries the same property +value no matter which subgraph's descriptor reaches it. +==== === Hierarchy Navigation diff --git a/doc/modules/ROOT/pages/algorithms/cycle_detection/hawick_circuits.adoc b/doc/modules/ROOT/pages/algorithms/cycle_detection/hawick_circuits.adoc index 8b0bd7bf9..be2572252 100644 --- a/doc/modules/ROOT/pages/algorithms/cycle_detection/hawick_circuits.adoc +++ b/doc/modules/ROOT/pages/algorithms/cycle_detection/hawick_circuits.adoc @@ -120,4 +120,4 @@ The algorithm is described in detail in https://www.researchgate.net/publication == Notes * `hawick_circuits` enumerates all elementary circuits including redundant ones caused by parallel edges. Use `hawick_unique_circuits` to suppress those duplicates. -* The visitor is passed by value. If your visitor contains state, consider holding it by pointer or reference so that changes made during the algorithm are visible to the caller. +* The visitor is passed by value. If your visitor contains state, consider holding it by pointer or reference so that changes made during the algorithm are visible to the caller. If `visitor` is a `std::reference_wrapper`, it will be unwrapped before the `.cycle` method is called on it, which allows passing a visitor that shouldn't be copied. diff --git a/doc/modules/ROOT/pages/algorithms/network_flow/stoer_wagner_min_cut.adoc b/doc/modules/ROOT/pages/algorithms/network_flow/stoer_wagner_min_cut.adoc index 9d5912d47..9e3890c63 100644 --- a/doc/modules/ROOT/pages/algorithms/network_flow/stoer_wagner_min_cut.adoc +++ b/doc/modules/ROOT/pages/algorithms/network_flow/stoer_wagner_min_cut.adoc @@ -6,7 +6,98 @@ Determines a min-cut and the min-cut weight of a connected, undirected graph. *Complexity:* _O_(_V_ * _E_ + _V_^2^ log _V_) + *Defined in:* `` -== Example +== Description + +A _cut_ of a graph _G_ is a partition of the vertices into two, non-empty sets. The _weight_ of such a partition is the number of edges between the two sets if _G_ is unweighted, or the sum of the weights of all edges between the two sets if _G_ is weighted. A _min-cut_ is a cut having the least weight. + +Sometimes a graph has multiple min-cuts, but all have the same weight. The `stoer_wagner_min_cut` function implements the +https://en.wikipedia.org/wiki/Stoer%E2%80%93Wagner_algorithm[Stoer-Wagner algorithm] and determines exactly one of the min-cuts as well as its weight. + +.A min-cut of a weighted graph having min-cut weight 4 +image::stoer_wagner_imgs/stoer_wagner-example-min-cut.gif[A min-cut of a weighted graph having min-cut weight 4,width=376] + +[WARNING] +==== +The `stoer_wagner_min_cut` function moved to `namespace boost::graph`. The +`boost::` overloads, both positional and named parameter, are kept for backward +compatibility but are deprecated. Removal planned for Boost 1.95. +==== + +== Overloads + +=== (1) Fully Positional + +[source,cpp] +---- +namespace boost::graph { +template +typename property_traits::value_type +stoer_wagner_min_cut( + const UndirectedGraph& g, WeightMap weights, + ParityMap parities, VertexAssignmentMap assignments, + KeyedUpdatablePriorityQueue& pq, IndexMap index_map); +} +---- + +[cols="1,2,5"] +|=== +| Direction | Parameter | Description + +| IN +| `const UndirectedGraph& g` +| A connected, undirected graph. The graph type must be a model of + xref:concepts/VertexListGraph.adoc[Vertex List Graph] + and xref:concepts/IncidenceGraph.adoc[Incidence Graph]. + +| IN +| `WeightMap weights` +| The weight or length of each edge in the graph. The `WeightMap` type + must be a model of + link:../../property_map/doc/ReadablePropertyMap.html[Readable Property Map] + and its value type must be + http://www.boost.org/sgi/stl/LessThanComparable.html[Less Than Comparable] + and summable. The key type of this map needs to be the graph's edge + descriptor type. + +| OUT +| `ParityMap parities` +| Records which of the two min-cut sets each vertex belongs to, by setting the + parity to `true` (one set) or `false` (the other). `ParityMap` must be a + model of a + link:../../property_map/doc/WritablePropertyMap.html[Writable Property Map] + and its value type should be a bool type. The key type must be the graph's + vertex descriptor type. Pass `boost::dummy_property_map()` when only the + min-cut weight is needed. + +| UTIL +| `VertexAssignmentMap assignments` +| Work space mapping each vertex to the vertex it is assigned to. Must be a + model of + link:../../property_map/doc/ReadWritePropertyMap.html[Read/Write Property Map]. + The key and value types must be the graph's vertex descriptor type. No + particular meaning should be derived from its values after completion. + +| UTIL +| `KeyedUpdatablePriorityQueue& pq` +| A max priority queue keyed on the reach counts. It must be a model of + xref:concepts/property_types/KeyedUpdatableQueue.adoc[Keyed Updatable Queue] and a + max-xref:concepts/property_types/UpdatableQueue.adoc[Updatable Priority Queue]. + The value type must be the graph's vertex descriptor and the key type + must be the weight type. It must be empty when passed in. + +| IN +| `IndexMap index_map` +| Maps each vertex to an integer in the range `[0, num_vertices(g))`. + `IndexMap` must be a model of + link:../../property_map/doc/ReadablePropertyMap.html[Readable Property Map]. + The value type must be an integer type and the key type the graph's vertex + descriptor type. + +|=== + +==== Example [source,cpp] ---- @@ -20,10 +111,75 @@ include::example$algorithms/network_flow/stoer_wagner.txt[] ''' -=== (1) Named parameter version +=== (2) Five arguments overload -.A min-cut of a weighted graph having min-cut weight 4 -image::stoer_wagner_imgs/stoer_wagner-example-min-cut.gif[A min-cut of a weighted graph having min-cut weight 4,width=376] +The index map is the least interesting argument, so this form defaults it to `get(vertex_index, g)`. Requires the graph to have an interior `vertex_index_t` property. + +[source,cpp] +---- +namespace boost::graph { +template +typename property_traits::value_type +stoer_wagner_min_cut( + const UndirectedGraph& g, WeightMap weights, + ParityMap parities, VertexAssignmentMap assignments, + KeyedUpdatablePriorityQueue& pq); +} +---- + +''' + +=== (3) Three arguments overload + +Building the assignment map and the priority queue is the cumbersome part, so this form defaults them along with the index map. Pass `boost::dummy_property_map()` for `parities` when only the min-cut weight is needed. + +[source,cpp] +---- +namespace boost::graph { +template +typename property_traits::value_type +stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities); +} +---- + +''' + +=== (4) Six arguments overload (deprecated) + +[WARNING] +==== +Deprecated: this overload moved to `namespace boost::graph`. Use the positional +`boost::graph::stoer_wagner_min_cut` overloads instead. Removal planned for +Boost 1.95. +==== + +[source,cpp] +---- +namespace boost { +template +typename property_traits::value_type +stoer_wagner_min_cut( + const UndirectedGraph& g, WeightMap weights, + ParityMap parities, VertexAssignmentMap assignments, + KeyedUpdatablePriorityQueue& pq, IndexMap index_map); +} +---- + +Identical to overload (1) except for its namespace. Kept in `boost::` for backward compatibility. + +''' + +=== (5) Named parameter version (deprecated) + +[WARNING] +==== +Deprecated: the named parameter interface is deprecated. Use the positional +`boost::graph::stoer_wagner_min_cut` overloads instead. Removal planned for +Boost 1.95. +==== [source,cpp] ---- @@ -128,48 +284,6 @@ weight_type stoer_wagner_min_cut( |=== -''' - -=== (2) Positional version (explicit index map) - -[source,cpp] ----- -template -typename property_traits::value_type -stoer_wagner_min_cut( - const UndirectedGraph& g, WeightMap weights, - ParityMap parities, VertexAssignmentMap assignments, - KeyedUpdatablePriorityQueue& pq, IndexMap index_map); ----- - -Explicit positional form with every working map supplied by the caller. Prefer overload (1) unless you have a reason to pre-allocate the work maps and priority queue. - -''' - -=== (3) Positional version (default index map) - -[source,cpp] ----- -template -typename property_traits::value_type -stoer_wagner_min_cut( - const UndirectedGraph& g, WeightMap weights, - ParityMap parities, VertexAssignmentMap assignments, - KeyedUpdatablePriorityQueue& pq); ----- - -Lives in namespace `boost::graph`. Same as (2) with `index_map = get(vertex_index, g)`; requires the graph to have an interior `vertex_index_t` property. - -== Description - -A _cut_ of a graph _G_ is a partition of the vertices into two, non-empty sets. The _weight_ of such a partition is the number of edges between the two sets if _G_ is unweighted, or the sum of the weights of all edges between the two sets if _G_ is weighted. A _min-cut_ is a cut having the least weight. - -Sometimes a graph has multiple min-cuts, but all have the same weight. The `stoer_wagner_min_cut` function implements the -https://en.wikipedia.org/wiki/Stoer%E2%80%93Wagner_algorithm[Stoer-Wagner algorithm] and determines exactly one of the min-cuts as well as its weight. - == Returns The weight of the min-cut. @@ -179,13 +293,8 @@ The weight of the min-cut. `bad_graph`:: If `num_vertices(g)` is less than 2. `std::invalid_argument`:: If a max-priority queue is given as an argument and it is not empty. -== Example - -The file link:../example/stoer_wagner.cpp[`examples/stoer_wagner.cpp`] contains an example of calculating a min-cut of a weighted, undirected graph and its min-cut weight. - == References * xref:about/bibliography.adoc#mehlhorn-uhrig95[[74\]] Mehlhorn, Kurt and Christian Uhrig (1995). _The minimum cut algorithm of Stoer and Wagner_. * xref:about/bibliography.adoc#stoer-wagner97[[75\]] Stoer, Mechthild and Frank Wagner (1997). _A simple min-cut algorithm_. Journal of the ACM 44 (4), 585-591. * xref:about/bibliography.adoc#zwick08[[76\]] Zwick, Uri (2008). _Global minimum cuts_. - diff --git a/doc/modules/ROOT/pages/algorithms/shortest_paths/r_c_shortest_paths.adoc b/doc/modules/ROOT/pages/algorithms/shortest_paths/r_c_shortest_paths.adoc index 2df511cec..8fa627784 100644 --- a/doc/modules/ROOT/pages/algorithms/shortest_paths/r_c_shortest_paths.adoc +++ b/doc/modules/ROOT/pages/algorithms/shortest_paths/r_c_shortest_paths.adoc @@ -26,12 +26,37 @@ include::example$algorithms/shortest_paths/r_c_shortest.txt[] ---- template +void r_c_shortest_paths( + const Graph& g, + const VertexIndexMap& vertex_index_map, + typename graph_traits::vertex_descriptor s, + typename graph_traits::vertex_descriptor t, + std::vector::edge_descriptor>>& pareto_optimal_solutions, + std::vector& pareto_optimal_resource_containers, + const ResourceContainer& rc, + const ResourceExtensionFunction& ref, + const DominanceFunction& dominance, + LabelAllocator la, + Visitor vis) +---- + +Old interface, to be deprecated in future releases. + +[source,cpp] +---- +template void r_c_shortest_paths( const Graph& g, const VertexIndexMap& vertex_index_map, @@ -39,11 +64,11 @@ void r_c_shortest_paths( typename graph_traits::vertex_descriptor s, typename graph_traits::vertex_descriptor t, std::vector::edge_descriptor>>& pareto_optimal_solutions, - std::vector& pareto_optimal_resource_containers, - const Resource_Container& rc, - const Resource_Extension_Function& ref, - const Dominance_Function& dominance, - Label_Allocator la, + std::vector& pareto_optimal_resource_containers, + const ResourceContainer& rc, + const ResourceExtensionFunction& ref, + const DominanceFunction& dominance, + LabelAllocator la, Visitor vis) ---- @@ -83,32 +108,32 @@ void r_c_shortest_paths( (from `t` to `s`). | OUT -| `std::vector& pareto_optimal_resource_containers` +| `std::vector& pareto_optimal_resource_containers` | A container for storing the Pareto-optimal resource containers corresponding to all Pareto-optimal solutions. | IN -| `const Resource_Container& rc` +| `const ResourceContainer& rc` | An object specifying the initial resource consumptions at vertex `s`. - The type `Resource_Container` must be a model of the ResourceContainer concept. + The type `ResourceContainer` must be a model of the ResourceContainer concept. | IN -| `const Resource_Extension_Function& ref` +| `const ResourceExtensionFunction& ref` | A function object, function pointer, or function specifying how a label is to - be extended along an arc. The type `Resource_Extension_Function` must be a model + be extended along an arc. The type `ResourceExtensionFunction` must be a model of the ResourceExtensionFunction concept. | IN -| `const Dominance_Function& dominance` +| `const DominanceFunction& dominance` | A function object, function pointer, or function specifying a dominance - relation between two labels. The type `Dominance_Function` must be a model of + relation between two labels. The type `DominanceFunction` must be a model of the DominanceFunction concept. | IN -| `Label_Allocator la` +| `LabelAllocator la` | An object specifying a strategy for the memory management of the labels. It must offer the same interface as - `std::allocator>`. + `std::allocator>`. There is a default type `default_r_c_shortest_paths_allocator` for this parameter using the STL standard allocator. If one wants to use a specialized allocator, one can specify an arbitrary type as template parameter for @@ -127,15 +152,40 @@ void r_c_shortest_paths( === (2) One Pareto-optimal solution, with allocator and visitor +[source,cpp] +---- +template +void r_c_shortest_paths( + const Graph& g, + const VertexIndexMap& vertex_index_map, + typename graph_traits::vertex_descriptor s, + typename graph_traits::vertex_descriptor t, + std::vector::edge_descriptor>& pareto_optimal_solution, + ResourceContainer& pareto_optimal_resource_container, + const ResourceContainer& rc, + const ResourceExtensionFunction& ref, + const DominanceFunction& dominance, + LabelAllocator la, + Visitor vis) +---- + +Old interface, to be deprecated in future releases. + [source,cpp] ---- template void r_c_shortest_paths( const Graph& g, @@ -144,11 +194,11 @@ void r_c_shortest_paths( typename graph_traits::vertex_descriptor s, typename graph_traits::vertex_descriptor t, std::vector::edge_descriptor>& pareto_optimal_solution, - Resource_Container& pareto_optimal_resource_container, - const Resource_Container& rc, - const Resource_Extension_Function& ref, - const Dominance_Function& dominance, - Label_Allocator la, + ResourceContainer& pareto_optimal_resource_container, + const ResourceContainer& rc, + const ResourceExtensionFunction& ref, + const DominanceFunction& dominance, + LabelAllocator la, Visitor vis) ---- @@ -188,33 +238,33 @@ void r_c_shortest_paths( (from `t` to `s`). This argument is not modified if there are no solutions. | OUT -| `Resource_Container& pareto_optimal_resource_container` -| A `Resource_Container` object for storing the Pareto-optimal resource +| `ResourceContainer& pareto_optimal_resource_container` +| A `ResourceContainer` object for storing the Pareto-optimal resource container corresponding to the first Pareto-optimal path. This argument is not modified if there are no solutions. | IN -| `const Resource_Container& rc` +| `const ResourceContainer& rc` | An object specifying the initial resource consumptions at vertex `s`. - The type `Resource_Container` must be a model of the ResourceContainer concept. + The type `ResourceContainer` must be a model of the ResourceContainer concept. | IN -| `const Resource_Extension_Function& ref` +| `const ResourceExtensionFunction& ref` | A function object, function pointer, or function specifying how a label is to - be extended along an arc. The type `Resource_Extension_Function` must be a model + be extended along an arc. The type `ResourceExtensionFunction` must be a model of the ResourceExtensionFunction concept. | IN -| `const Dominance_Function& dominance` +| `const DominanceFunction& dominance` | A function object, function pointer, or function specifying a dominance - relation between two labels. The type `Dominance_Function` must be a model of + relation between two labels. The type `DominanceFunction` must be a model of the DominanceFunction concept. | IN -| `Label_Allocator la` +| `LabelAllocator la` | An object specifying a strategy for the memory management of the labels. It must offer the same interface as - `std::allocator>`. + `std::allocator>`. There is a default type `default_r_c_shortest_paths_allocator` for this parameter using the STL standard allocator. @@ -231,14 +281,35 @@ void r_c_shortest_paths( === (3) All Pareto-optimal solutions, default allocator and visitor +[source,cpp] +---- +template +void r_c_shortest_paths( + const Graph& g, + const VertexIndexMap& vertex_index_map, + typename graph_traits::vertex_descriptor s, + typename graph_traits::vertex_descriptor t, + std::vector::edge_descriptor>>& pareto_optimal_solutions, + std::vector& pareto_optimal_resource_containers, + const ResourceContainer& rc, + const ResourceExtensionFunction& ref, + const DominanceFunction& dominance) +---- + +Old interface, to be deprecated in future releases. + [source,cpp] ---- template + class ResourceContainer, + class ResourceExtensionFunction, + class DominanceFunction> void r_c_shortest_paths( const Graph& g, const VertexIndexMap& vertex_index_map, @@ -246,13 +317,13 @@ void r_c_shortest_paths( typename graph_traits::vertex_descriptor s, typename graph_traits::vertex_descriptor t, std::vector::edge_descriptor>>& pareto_optimal_solutions, - std::vector& pareto_optimal_resource_containers, - const Resource_Container& rc, - const Resource_Extension_Function& ref, - const Dominance_Function& dominance) + std::vector& pareto_optimal_resource_containers, + const ResourceContainer& rc, + const ResourceExtensionFunction& ref, + const DominanceFunction& dominance) ---- -[cols="1,2,5"] +[%autowrap, cols="1,2,5"] |=== | Direction | Parameter | Description @@ -288,25 +359,25 @@ void r_c_shortest_paths( (from `t` to `s`). | OUT -| `std::vector& pareto_optimal_resource_containers` +| `std::vector& pareto_optimal_resource_containers` | A container for storing the Pareto-optimal resource containers corresponding to all Pareto-optimal solutions. | IN -| `const Resource_Container& rc` +| `const ResourceContainer& rc` | An object specifying the initial resource consumptions at vertex `s`. - The type `Resource_Container` must be a model of the ResourceContainer concept. + The type `ResourceContainer` must be a model of the ResourceContainer concept. | IN -| `const Resource_Extension_Function& ref` +| `const ResourceExtensionFunction& ref` | A function object, function pointer, or function specifying how a label is to - be extended along an arc. The type `Resource_Extension_Function` must be a model + be extended along an arc. The type `ResourceExtensionFunction` must be a model of the ResourceExtensionFunction concept. | IN -| `const Dominance_Function& dominance` +| `const DominanceFunction& dominance` | A function object, function pointer, or function specifying a dominance - relation between two labels. The type `Dominance_Function` must be a model of + relation between two labels. The type `DominanceFunction` must be a model of the DominanceFunction concept. |=== @@ -319,9 +390,9 @@ void r_c_shortest_paths( template + class ResourceContainer, + class ResourceExtensionFunction, + class DominanceFunction> void r_c_shortest_paths( const Graph& g, const VertexIndexMap& vertex_index_map, @@ -329,10 +400,31 @@ void r_c_shortest_paths( typename graph_traits::vertex_descriptor s, typename graph_traits::vertex_descriptor t, std::vector::edge_descriptor>& pareto_optimal_solution, - Resource_Container& pareto_optimal_resource_container, - const Resource_Container& rc, - const Resource_Extension_Function& ref, - const Dominance_Function& dominance) + ResourceContainer& pareto_optimal_resource_container, + const ResourceContainer& rc, + const ResourceExtensionFunction& ref, + const DominanceFunction& dominance) +---- + +Old interface, to be deprecated in future releases. + +[source,cpp] +---- +template +void r_c_shortest_paths( + const Graph& g, + const VertexIndexMap& vertex_index_map, + typename graph_traits::vertex_descriptor s, + typename graph_traits::vertex_descriptor t, + std::vector::edge_descriptor>& pareto_optimal_solution, + ResourceContainer& pareto_optimal_resource_container, + const ResourceContainer& rc, + const ResourceExtensionFunction& ref, + const DominanceFunction& dominance) ---- [cols="1,2,5"] @@ -371,26 +463,26 @@ void r_c_shortest_paths( (from `t` to `s`). This argument is not modified if there are no solutions. | OUT -| `Resource_Container& pareto_optimal_resource_container` -| A `Resource_Container` object for storing the Pareto-optimal resource +| `ResourceContainer& pareto_optimal_resource_container` +| A `ResourceContainer` object for storing the Pareto-optimal resource container corresponding to the first Pareto-optimal path. This argument is not modified if there are no solutions. | IN -| `const Resource_Container& rc` +| `const ResourceContainer& rc` | An object specifying the initial resource consumptions at vertex `s`. - The type `Resource_Container` must be a model of the ResourceContainer concept. + The type `ResourceContainer` must be a model of the ResourceContainer concept. | IN -| `const Resource_Extension_Function& ref` +| `const ResourceExtensionFunction& ref` | A function object, function pointer, or function specifying how a label is to - be extended along an arc. The type `Resource_Extension_Function` must be a model + be extended along an arc. The type `ResourceExtensionFunction` must be a model of the ResourceExtensionFunction concept. | IN -| `const Dominance_Function& dominance` +| `const DominanceFunction& dominance` | A function object, function pointer, or function specifying a dominance - relation between two labels. The type `Dominance_Function` must be a model of + relation between two labels. The type `DominanceFunction` must be a model of the DominanceFunction concept. |=== @@ -448,7 +540,7 @@ See <> concept. [#Label] == Label -This concept defines the interface for a label in the `r_c_shortest_paths` functions. It is a design decision not to parameterize the functions on the type of label. The type `template struct r_c_shortest_paths_label` is used to model this concept. +This concept defines the interface for a label in the `r_c_shortest_paths` functions. It is a design decision not to parameterize the functions on the type of label. The type `template struct r_c_shortest_paths_label` is used to model this concept. *Valid Expressions* + If `label` is an object of type `r_c_shortest_paths_label`, the following expressions are valid: @@ -485,7 +577,7 @@ Every `r_c_shortest_paths_label` object, except for the first label, has a valid A model of the ResourceExtensionFunction concept is used to specify how a label is to be extended along an arc. *Valid Expressions* + -If `ref` models the ResourceExtensionFunction concept, and if the type `Resource_Container` models the ResourceContainer concept, the following expression is valid: +If `ref` models the ResourceExtensionFunction concept, and if the type `ResourceContainer` models the ResourceContainer concept, the following expression is valid: [cols="1,1"] |=== @@ -493,8 +585,8 @@ a| [source,cpp] ---- bool b = ref( const Graph& g, - Resource_Container& new_cont, - const Resource_Container& old_cont, + ResourceContainer& new_cont, + const ResourceContainer& old_cont, graph_traits::edge_descriptor ed ) ---- @@ -506,13 +598,13 @@ Moreover, a reference to a type modelling the ResourceExtensionFunction concept Hence, a type modelling the ResourceExtensionFunction concept is likely to be a function or a http://www.boost.org/sgi/stl/functors.html[function object]. *Invariants* + -If `ref` models the ResourceExtensionFunction concept, and if the type `Resource_Container` models the ResourceContainer concept, after the call +If `ref` models the ResourceExtensionFunction concept, and if the type `ResourceContainer` models the ResourceContainer concept, after the call [source,cpp] ---- ref( const Graph& g, - Resource_Container& new_cont, - const Resource_Container& old_cont, + ResourceContainer& new_cont, + const ResourceContainer& old_cont, graph_traits::edge_descriptor ) ---- @@ -527,13 +619,13 @@ A model of DominanceFunction is used to specify a dominance relation between two http://www.boost.org/sgi/stl/BinaryPredicate.html[BinaryPredicate] *Valid Expressions* + -If `dominance` models the DominanceFunction concept, and if the type `Resource_Container` models the ResourceContainer concept, the following expression is valid: +If `dominance` models the DominanceFunction concept, and if the type `ResourceContainer` models the ResourceContainer concept, the following expression is valid: [cols="1,1"] |=== a| .... -bool b = dominance(const Resource_Container& rc1, const Resource_Container& rc2) +bool b = dominance(const ResourceContainer& rc1, const ResourceContainer& rc2) .... | `dominance` must return `true` if and only if `rc1` dominates `rc2`. @@ -623,7 +715,7 @@ r_c_shortest_paths( g, === Preconditions * `s` and `t` are valid vertex descriptors for `g`. -* `rc` is within the resource windows at `s`, i.e., it constitutes a feasible `Resource_Container` object at `s` (see <>). +* `rc` is within the resource windows at `s`, i.e., it constitutes a feasible `ResourceContainer` object at `s` (see <>). == Throws @@ -645,7 +737,7 @@ Experience shows that for 'small' resource containers, it may be useful to try a === Allocator and Visitor Defaults -If the third or the fourth overload of the function is used, objects of type `default_r_c_shortest_paths_allocator` and `default_r_c_shortest_paths_visitor` are used as the `Label_Allocator` and `Visitor` parameters respectively. If the first or the second overload is used, one must specify both a `Label_Allocator` and a `Visitor` parameter. If one wants to develop a user-defined type only for `Visitor`, one can use `default_r_c_shortest_paths_allocator` as `Label_Allocator` parameter. If one wants to use only a specialized allocator, one can use `default_r_c_shortest_paths_visitor` as `Visitor` parameter. +If the third or the fourth overload of the function is used, objects of type `default_r_c_shortest_paths_allocator` and `default_r_c_shortest_paths_visitor` are used as the `LabelAllocator` and `Visitor` parameters respectively. If the first or the second overload is used, one must specify both a `LabelAllocator` and a `Visitor` parameter. If one wants to develop a user-defined type only for `Visitor`, one can use `default_r_c_shortest_paths_allocator` as `LabelAllocator` parameter. If one wants to use only a specialized allocator, one can use `default_r_c_shortest_paths_visitor` as `Visitor` parameter. === Utility Function: check_r_c_path @@ -654,16 +746,16 @@ There is a utility function called `check_r_c_path` that can be used for debuggi [source,cpp] ---- template + class ResourceContainer, + class ResourceExtensionFunction> void check_r_c_path( const Graph& g, const std::vector::edge_descriptor>& ed_vec_path, - const Resource_Container& initial_resource_levels, + const ResourceContainer& initial_resource_levels, bool b_result_must_be_equal_to_desired_final_resource_levels, - const Resource_Container& desired_final_resource_levels, - Resource_Container& actual_final_resource_levels, - const Resource_Extension_Function& ref, + const ResourceContainer& desired_final_resource_levels, + ResourceContainer& actual_final_resource_levels, + const ResourceExtensionFunction& ref, bool& b_is_a_path_at_all, bool& b_feasible, bool& b_correctly_extended, diff --git a/doc/modules/ROOT/pages/algorithms/utility/maximum_adjacency_search.adoc b/doc/modules/ROOT/pages/algorithms/utility/maximum_adjacency_search.adoc index b027302ac..842a66203 100644 --- a/doc/modules/ROOT/pages/algorithms/utility/maximum_adjacency_search.adoc +++ b/doc/modules/ROOT/pages/algorithms/utility/maximum_adjacency_search.adoc @@ -6,28 +6,40 @@ Traverses vertices of an undirected graph, always visiting next the vertex with *Complexity:* _O(E + V)_ + *Defined in:* `` -== Example +== Description -[source,cpp] ----- -include::example$algorithms/utility/maximum_adjacency_search.cpp[] ----- +The `maximum_adjacency_search()` function performs a traversal of the +vertices in an undirected graph. The next vertex visited is the vertex +that has the most visited neighbors at any time. In the case of an +unweighted, undirected graph, the number of visited neighbors of the very +last vertex visited in the graph is also the number of edge-disjoint +paths between that vertex and the next-to-last vertex visited. These can +be retrieved from a visitor, an example of which is in the test harness +mas_test.cpp. -[,text] ----- -include::example$algorithms/utility/maximum_adjacency_search.txt[] ----- +The `maximum_adjacency_search()` function invokes user-defined actions at +certain event-points within the algorithm. This provides a mechanism for +adapting the generic MAS algorithm to the many situations in which it can +be used. In the pseudo-code below, the event points for MAS are the +labels on the right. The user-defined actions must be provided in the +form of a visitor object, that is, an object whose type meets the +requirements for the <>. -''' +== Overloads -=== (1) Positional version +=== (1) Fully Positional [source,cpp] ---- -template +namespace boost::graph { +template void maximum_adjacency_search( - const Graph& g, WeightMap weights, MASVisitor vis, - const typename graph_traits::vertex_descriptor start); + const Graph& g, + WeightMap weights, + MASVisitor vis, + typename graph_traits::vertex_descriptor start, + KeyedUpdatablePriorityQueue pq); +} ---- [cols="1,2,5"] @@ -36,7 +48,7 @@ void maximum_adjacency_search( | IN | `const Graph& g` -| A connected, directed graph. The graph type must be a model of +| A connected, undirected graph. The graph type must be a model of xref:concepts/IncidenceGraph.adoc[Incidence Graph] and xref:concepts/VertexListGraph.adoc[Vertex List Graph]. @@ -53,19 +65,118 @@ void maximum_adjacency_search( | IN | `MASVisitor vis` | A visitor object that is invoked inside the algorithm at the event-points - specified by the MAS Visitor concept. The visitor object is passed by - value <<1,[1]>>. + specified by the <>. The visitor object is passed by + value. | IN | `vertex_descriptor start` | This specifies the vertex that the search should originate from. The type is the type of a vertex descriptor for the given graph. +| IN +| `KeyedUpdatablePriorityQueue pq` +| A max priority queue keyed on the reach counts. It must be a model of + xref:concepts/property_types/KeyedUpdatableQueue.adoc[Keyed Updatable Queue] and a + max link:./UpdatableQueue.html#concept%3AUpdatablePriorityQueue[Updatable + Priority Queue]. The value type must be the graph's vertex descriptor and + the key type must be the weight type. It must be empty when passed in. + |=== +==== Example + +[source,cpp] +---- +include::example$algorithms/utility/maximum_adjacency_search.cpp[] +---- + +[,text] +---- +include::example$algorithms/utility/maximum_adjacency_search.txt[] +---- + +''' + +=== (2) Four arguments overload + +Building the priority queue is the cumbersome part, so this form defaults it to a +max `d_ary_heap_indirect` keyed on the reach counts. + +[source,cpp] +---- +namespace boost::graph { +template +void maximum_adjacency_search( + const Graph& g, + WeightMap weights, + MASVisitor vis, + typename graph_traits::vertex_descriptor start); +} +---- + +==== Example + +[source,cpp] +---- +include::example$algorithms/utility/maximum_adjacency_search_default_queue.cpp[] +---- + +[,text] +---- +include::example$algorithms/utility/maximum_adjacency_search_default_queue.txt[] +---- + +''' + +=== (3) Three arguments overload + +The start vertex rarely matters, this form defaults it to `*vertices(g).first`. + +[source,cpp] +---- +namespace boost::graph { +template +void maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis); +} +---- + ''' -=== (2) Named parameter version +=== (4) Six arguments overload (deprecated) + +[WARNING] +==== +Deprecated: the `assignments` map is unused. Use the fully positional or +convenience `boost::graph::maximum_adjacency_search` overloads instead. Removal +planned for Boost 1.95. +==== + +[source,cpp] +---- +namespace boost { +template +void maximum_adjacency_search( + const Graph& g, WeightMap weights, MASVisitor vis, + typename graph_traits::vertex_descriptor start, + VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq); +} +---- + +Identical to the fully positional overload except for the extra +`VertexAssignmentMap assignments` parameter, which is accepted for backward +compatibility but never read. + +''' + +=== (5) Named parameter version (deprecated) + +[WARNING] +==== +Deprecated: the named parameter interface is deprecated. Use the fully +positional or convenience `boost::graph::maximum_adjacency_search` overloads +instead. Removal planned for Boost 1.95. +==== [source,cpp] ---- @@ -81,7 +192,7 @@ void maximum_adjacency_search( | IN | `const Graph& g` -| A connected, directed graph. The graph type must be a model of +| A connected, undirected graph. The graph type must be a model of xref:concepts/IncidenceGraph.adoc[Incidence Graph] and xref:concepts/VertexListGraph.adoc[Vertex List Graph]. @@ -108,8 +219,8 @@ void maximum_adjacency_search( | IN | `visitor(MASVisitor vis)` | A visitor object that is invoked inside the algorithm at the event-points - specified by the MAS Visitor concept. The visitor object is passed by - value <<1,[1]>>. + + specified by the <>. The visitor object is passed by + value. + *Default:* `mas_visitor` | IN @@ -143,7 +254,7 @@ void maximum_adjacency_search( | `max_priority_queue(MaxPriorityQueue& pq)` | `MaxPriorityQueue` must be a model of xref:concepts/property_types/KeyedUpdatableQueue.adoc[Keyed Updatable Queue] and a - max-link:./UpdatableQueue.html#concept%3AUpdatablePriorityQueue[Updatable + max link:./UpdatableQueue.html#concept%3AUpdatablePriorityQueue[Updatable Priority Queue]. The value type must be the graph's vertex descriptor and the key type must be the weight type. + *Default:* A `boost::d_ary_heap_indirect` using a default index-in-heap @@ -175,24 +286,32 @@ void maximum_adjacency_search( |=== -== Description +== Throws -The `maximum_adjacency_search()` function performs a traversal of the -vertices in an undirected graph. The next vertex visited is the vertex -that has the most visited neighbors at any time. In the case of an -unweighted, undirected graph, the number of visited neighbors of the very -last vertex visited in the graph is also the number of edge-disjoint -paths between that vertex and the next-to-last vertex visited. These can -be retrieved from a visitor, an example of which is in the test harness -mas_test.cpp. +`bad_graph`:: If `num_vertices(g)` is less than 2. +`std::invalid_argument`:: If a max-priority queue is given as an argument and it is not empty. -The `maximum_adjacency_search()` function invokes user-defined actions at -certain event-points within the algorithm. This provides a mechanism for -adapting the generic MAS algorithm to the many situations in which it can -be used. In the pseudo-code below, the event points for MAS are the -labels on the right. The user-defined actions must be provided in the -form of a visitor object, that is, an object whose type meets the -requirements for a MAS Visitor. +== Visitor + +The `maximum_adjacency_search()` function invokes user-defined actions at four +event points during the traversal. You supply these actions through a visitor +object whose type models the <>. + +The visitor is taken by value, so the algorithm works on a copy. To keep state, +give the visitor ordinary data members and pass it with `std::ref`. +The algorithm then operates on the referenced object and its +state survives the call. + +[WARNING] +==== +These symbols moved to `namespace boost::graph`. The `boost::` aliases are kept +for backward compatibility but are deprecated. Removal planned for Boost 1.95. + +* `boost::mas_visitor` -> `boost::graph::mas_visitor` +* `boost::make_mas_visitor` -> `boost::graph::make_mas_visitor` +* `boost::default_mas_visitor` -> `boost::graph::default_mas_visitor` +* `boost::MASVisitorConcept` -> `boost::graph::MASVisitorConcept` +==== === Pseudo-Code @@ -208,10 +327,10 @@ MAS(G) reach_count[s] := 1 for each unvisited vertex u in V call MAS-VISIT(G, u) - remove u from the list on unvisited vertices + remove u from unvisited for each out edge from u to t if t has not yet been visited - increment reach_count[t] + reach_count[t] += weight(u, t) end if end for each out edge call MAS-VISIT(G, u) @@ -226,7 +345,7 @@ initialize vertex u . . . -examine vertex u +start vertex u . examine edge (u,t) . @@ -238,34 +357,96 @@ finish vertex u ---- |=== -== Returns -`void` +[#mas-visitor-concept] +=== Visitor Concept -== Throws +The `MASVisitor` template parameter must be a model of the MAS Visitor +concept, which defines the event points at which the algorithm invokes +user-defined actions. -`bad_graph`:: If `num_vertices(g)` is less than 2. -`std::invalid_argument`:: If a max-priority queue is given as an argument and it is not empty. +==== Refinement of + +Copy Constructible (copying a visitor should be a lightweight operation). + +==== Notation + +[cols=",",] +|=== +| `V` | A type that is a model of MAS Visitor. +| `vis` | An object of type `V`. +| `G` | A type that is a model of Graph. +| `g` | An object of type `G`. +| `e` | An object of type `boost::graph_traits::edge_descriptor`. +| `s,u` | An object of type `boost::graph_traits::vertex_descriptor`. +|=== + +==== Valid Expressions + +[cols=",,,",options="header",] +|=== +| Name | Expression | Return Type | Description + +| Initialize Vertex +| `vis.initialize_vertex(s, g)` +| `void` +| Invoked on every vertex of the graph before the start of the search. + +| Start Vertex +| `vis.start_vertex(s, g)` +| `void` +| Invoked on the source vertex once before processing its out-edges. + +| Examine Edge +| `vis.examine_edge(e, g)` +| `void` +| Invoked on every out-edge of each vertex after it is started. + +| Finish Vertex +| `vis.finish_vertex(u, g)` +| `void` +| Invoked on a vertex after all of its out-edges have been examined and the + reach counts of the unvisited targets have been updated. +|=== + +=== Minimal Implementation + +Two ways to write a visitor. + +Inherit from `default_mas_visitor` and shadow only the relevant handlers. The +base supplies a no-op for every other event. + +[source,cpp] +---- +struct my_mas_visitor : boost::graph::default_mas_visitor +{ + template + void examine_edge(Edge e, const Graph& g) + { + // logic here + } +}; +---- + +Or copy the full struct and fill in each handler. All four must be declared. + +[source,cpp] +---- +struct my_mas_visitor +{ + template + void initialize_vertex(Vertex u, const Graph& g) {} + + template + void start_vertex(Vertex u, const Graph& g) {} -== Visitor Event Points - -* *`vis.initialize_vertex(s, g)`* is invoked on every vertex of the - graph before the start of the graph search. -* *`vis.start_vertex(s, g)`* is invoked on the source vertex once - before processing its out edges. -* *`vis.examine_edge(e, g)`* is invoked on every out-edge of each - vertex after it is started. -* *`vis.finish_vertex(u, g)`* is invoked on a vertex after all of its - out edges have been examined and the reach counts of the unvisited - targets have been updated. - -== Notes - -[#1]#[1]# Since the visitor parameter is passed by value, if your -visitor contains state then any changes to the state during the algorithm -will be made to a copy of the visitor object, not the visitor object -passed in. Therefore you may want the visitor to hold this state by -pointer or reference. + template + void examine_edge(Edge e, const Graph& g) {} + + template + void finish_vertex(Vertex u, const Graph& g) {} +}; +---- == References diff --git a/doc/modules/ROOT/pages/extending/stanford_graph.adoc b/doc/modules/ROOT/pages/extending/stanford_graph.adoc new file mode 100644 index 000000000..36d5f83bc --- /dev/null +++ b/doc/modules/ROOT/pages/extending/stanford_graph.adoc @@ -0,0 +1,294 @@ +// Copyright (C) 2001 Andreas Scherer, Jeremy Siek, Lie-Quan Lee, Andrew Lumsdaine +// Copyright (C) 2026 Arnaud Becheler +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + += Using SGB Graphs in BGL + +The SGB ships a set of ready-made graph datasets drawn from real sources, such as road mileage between North American cities, cross-references in Roget's Thesaurus, and character interactions in classic novels. Because the data is fixed and reproducible, these graphs are a convenient basis for benchmarking and testing graph algorithms. + +Each dataset is produced by an SGB generator that returns a native `Graph*`. The BGL wrapper adapts that `Graph*` to the BGL graph concepts, so the generic BGL algorithms run on SGB data directly, with no copy into an `adjacency_list`. That adaptation is what this page documents. It is not a substitute for the full SGB documentation. + +Under the hood, no graph adaptor *class* is involved. SGB's `Graph*` itself becomes a model of xref:concepts/VertexListGraph.adoc[VertexListGraph], with the concept fulfilled by the appropriate non-member functions defined for `Graph*` in ``. + +== Example + +The following program applies Prim's algorithm to the `miles` graph of United States cities, a native SGB `Graph*`, without any adapter or copy. It builds against a working SGB installation, described below. +The `miles` generator reads its data from the SGB installation, so the tree length is fixed. + +[source,cpp] +---- +include::example$extending/sgb_miles_span.cpp[] +---- + +[,text] +---- +include::example$extending/sgb_miles_span.txt[] +---- + +== The Stanford GraphBase + +"The https://www-cs-faculty.stanford.edu/~knuth/sgb.html[Stanford GraphBase] (SGB) is a collection of datasets and computer programs that generate and examine a wide variety of graphs and networks." The SGB was developed and published by https://www-cs-faculty.stanford.edu/~knuth[Donald E. Knuth] in 1993. The fully documented source code is maintained at the https://github.com/ascherer/sgb[ascherer/sgb] repository on GitHub and is described in the book "The Stanford GraphBase, A Platform for Combinatorial Computing," published jointly by ACM Press and Addison-Wesley Publishing Company in 1993. This book contains several chapters with additional information not available in the electronic distribution. + +=== Prerequisites + +The source code of SGB is written in accordance with the rules of the https://www-cs-faculty.stanford.edu/~knuth/lp.html[Literate Programming] paradigm, so you need to make sure that your computer supports the https://www-cs-faculty.stanford.edu/~knuth/cweb.html[CWEB] system. The CWEB sources are available from the https://github.com/ascherer/cweb[ascherer/cweb] repository on GitHub. Bootstrapping CWEB on Unix systems is elementary and documented in the CWEB distribution. + +=== Installing the SGB + +After you have acquired the SGB sources and have installed a working CWEB system (at least the "ctangle" processor is required), you're almost set for compiling the SGB sources. SGB is written in "old-style C," but the Boost Graph Library expects to handle "modern C" and C++. Fortunately, the SGB distribution comes with an appropriate set of patches that convert all the sources from "KR-C" to "ANSI-C," thus allowing for smooth integration of the Stanford GraphBase in the Boost Graph Library. + +The recommended way to obtain a current, buildable SGB is the https://github.com/ascherer/sgb/releases/tag/2025-12-28[2025-12-28 release] of the https://github.com/ascherer/sgb[ascherer/sgb] repository. Check out the `local` branch, which carries the latest modifications of the Stanford GraphBase. Those patches modernize the sources so that they compile with current toolchains, up to C++23 compilers. + +After extracting the SGB archive, but prior to invoking "`make tests`" and "`make install`," you should say "`ln -s PROTOTYPES/*.ch .`" in the root directory where you extracted the SGB files (or you can simply copy the change files next to the proper source files). The Unix `Makefile` coming with SGB conveniently looks for "change files" matching the SGB source files and automatically applies them with the "ctangle" processor. The resulting C files will smoothly run through the compiler. + +=== Using the SGB + +After you have run the installation process of the SGB, you can use the BGL graph interface with the SGB `Graph*` through ``, which is described xref:extending/stanford_graph.adoc#sgb-interface[below]. All you have to do is tell the C++ compiler where to look for the SGB header files and the linker where to find the SGB library file (`libgb.so`, or `libgb.a` for a static build, on Unix). Consult the documentation of your particular compiler about how to do that. Distribution packages typically use a multiarch layout, for example headers under `/usr/include/sgb` and the library under `/usr/lib/x86_64-linux-gnu/sgb`, so you would pass `-I/usr/include/sgb -L/usr/lib/x86_64-linux-gnu/sgb -lgb`. + +=== Technicalities + +*Header file selection*: The two SGB modules `gb_graph` and `gb_io` use the preprocessor switch `SYSV` to select either the header file `` (if `SYSV` is `#define`d) or the header file `` (if `SYSV` is _not_ `#define`d). Some compilers, like `gcc`/`g++`, don't care much (`gcc` "knows" about the "string" functions without referring to ``), but others do. You should be careful to set (or not) `SYSV` according to the needs of your compiler. + +*Preprocessor macros*: The SGB header files make liberal use of the preprocessor _without_ sticking to a particular convention (like all-uppercase names or a particular prefix). At the time of writing, already three of these preprocessor macros collide with the conventions of either C++, g++, or BGL, and are fixed in the BGL wrapper. We can not guarantee that no other preprocessor-induced problems may arise, but we are willing to learn about any such collisions. + +[#sgb-interface] +== The BGL Interface for the SGB + +=== Where Defined + +`` + +The main purpose of this Boost Graph Library (BGL) header file is to `#include` all global definitions for the general stuff of the Stanford GraphBase (SGB) and its various graph generator functions by reading all SGB header files as in section 2 of the "`test_sample`" program. + +On top of the SGB stuff, the BGL `stanford_graph.hpp` header adds and defines appropriate types and functions for using the SGB graphs in the BGL framework. Apart from the improved interface, the SGB library is used "as is" in the context of BGL. + +=== Model Of + +xref:concepts/VertexListGraph.adoc[VertexListGraph] and xref:concepts/PropertyGraph.adoc[PropertyGraph]. The set of property tags that can be used with the SGB graph is described in the <> section below. + +=== Further examples + +Additional example programs apply the same generic framework to other SGB graphs. + +* https://github.com/boostorg/graph/blob/master/example/roget_components.cpp[`example/roget_components.cpp`^] computes the strongly connected components of the `roget` graph of cross-references in Roget's Thesaurus. +* https://github.com/boostorg/graph/blob/master/example/girth.cpp[`example/girth.cpp`^] explores the girth and diameter of Ramanujan graphs, ported from the SGB GIRTH program. +* https://github.com/boostorg/graph/blob/master/example/topo-sort-with-sgb.cpp[`example/topo-sort-with-sgb.cpp`^] runs a topological sort over a small SGB `Graph*` built by hand. + +=== Associated Types + +`graph_traits::vertex_descriptor` + +The type for the vertex descriptors associated with the `Graph*`. We use the type `Vertex*` as the vertex descriptor. + +''' + +`graph_traits::edge_descriptor` + +The type for the edge descriptors associated with the `Graph*`. This is the type `boost::sgb_edge`. In addition to supporting all the required operations of a BGL edge descriptor, the `boost::sgb_edge` class has the following constructor. + +[source,cpp] +---- +sgb_edge::sgb_edge(Arc* arc, Vertex* source) +---- + +''' + +`graph_traits::vertex_iterator` + +The type for the iterators returned by `vertices()`. + +''' + +`graph_traits::out_edge_iterator` + +The type for the iterators returned by `out_edges()`. + +''' + +`graph_traits::adjacency_iterator` + +The type for the iterators returned by `adjacent_vertices()`. + +''' + +`graph_traits::vertices_size_type` + +The type used for dealing with the number of vertices in the graph. + +''' + +`graph_traits::edge_size_type` + +The type used for dealing with the number of edges in the graph. + +''' + +`graph_traits::degree_size_type` + +The type used for dealing with the number of edges incident to a vertex in the graph. + +''' + +`graph_traits::directed_category` + +Provides information about whether the graph is directed or undirected. An SGB `Graph*` is directed so this type is `directed_tag`. + +''' + +`graph_traits::traversal_category` + +An SGB `Graph*` provides traversal of the vertex set, out edges, and adjacent vertices. Therefore the traversal category tag is defined as follows: + +[source,cpp] +---- +struct sgb_traversal_tag : + public virtual vertex_list_graph_tag, + public virtual incidence_graph_tag, + public virtual adjacency_graph_tag { }; +---- + +''' + +`graph_traits::edge_parallel_category` + +This describes whether the graph class allows the insertion of parallel edges (edges with the same source and target). The SGB `Graph*` does not prevent addition of parallel edges, so this type is `allow_parallel_edge_tag`. + +=== Non-Member Functions + +[source,cpp] +---- +std::pair +vertices(Graph* g) +---- + +Returns an iterator-range providing access to the vertex set of graph `g`. + +''' + +[source,cpp] +---- +std::pair +out_edges(vertex_descriptor v, Graph* g) +---- + +Returns an iterator-range providing access to the out-edges of vertex `v` in graph `g`. There is no corresponding `in_edges` function. + +''' + +[source,cpp] +---- +std::pair +adjacent_vertices(vertex_descriptor v, Graph* g) +---- + +Returns an iterator-range providing access to the adjacent vertices of vertex `v` in graph `g`. + +''' + +[source,cpp] +---- +vertex_descriptor +source(edge_descriptor e, Graph* g) +---- + +Returns the source vertex of edge `e`. + +''' + +[source,cpp] +---- +vertex_descriptor +target(edge_descriptor e, Graph* g) +---- + +Returns the target vertex of edge `e`. + +''' + +[source,cpp] +---- +degree_size_type +out_degree(vertex_descriptor v, Graph* g) +---- + +Returns the number of edges leaving vertex `v`. There is no corresponding `in_degree` function. + +''' + +[source,cpp] +---- +vertices_size_type +num_vertices(Graph* g) +---- + +Returns the number of vertices in the graph `g`. + +''' + +[source,cpp] +---- +edge_size_type +num_edges(Graph* g) +---- + +Returns the number of edges in the graph `g`. + +''' + +[source,cpp] +---- +vertex_descriptor +vertex(vertices_size_type n, Graph* g) +---- + +Returns the (0-based) nth vertex in the graph's vertex list. + +''' + +[source,cpp] +---- +template +property_map::type +get(PropertyTag, Graph*& g) + +template +property_map::const_type +get(PropertyTag, const Graph*& g) +---- + +Returns the property map object for the vertex property specified by `PropertyTag`. The `PropertyTag` must be one of those described below. + +[#properties] +=== Vertex and Edge Properties + +The SGB `Vertex` and `Arc` structures provide "utility" fields for storing extra information. We provide BGL wrappers that provide access to these fields through property maps. In addition, vertex index and edge length maps are provided. A property map object can be obtained from a SGB `Graph*` using the `get()` function described in the xref:concepts/PropertyGraph.adoc[PropertyGraph] concept. + +The following list of property tags can be used to specify which utility field you would like a property map for. + +[source,cpp] +---- +// vertex properties +template u_property; +template v_property; +template w_property; +template x_property; +template y_property; +template z_property; + +// edge properties +template a_property; +template b_property; +---- + +The template parameter `T` for these tags is limited to the types in the `util` union declared in the SGB header `gb_graph.h`, which are `Vertex*`, `Arc*`, `Graph*`, `char*`, and `long`. The property maps for the utility fields are models of LvaluePropertyMap. + +The property map for vertex indices can be obtained using the `vertex_index_t` tag, and this property map is a ReadablePropertyMap. A property map for edge lengths can be obtained using the `edge_length_t` tag, and this property map is an LvaluePropertyMap whose value type is `long`. + +Property map objects can be obtained via the `get()` function of the PropertyGraph concept. The type of the property map is given by the xref:traits/property_map.adoc[property_map] traits class. + +''' + +_Original documentation (2001) by Andreas Scherer, Aachen, Jeremy Siek and Lie-Quan Lee, Indiana University, and Andrew Lumsdaine._ diff --git a/doc/package-lock.json b/doc/package-lock.json index 2acbd5aa3..efaccde6f 100644 --- a/doc/package-lock.json +++ b/doc/package-lock.json @@ -1,2194 +1,1998 @@ { - "name": "boost-graph-docs", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "boost-graph-docs", - "devDependencies": { - "@antora/cli": "3.1.14", - "@antora/lunr-extension": "^1.0.0-alpha.13", - "@antora/site-generator": "3.1.14", - "antora": "3.1.14" - } - }, - "node_modules/@antora/asciidoc-loader": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@antora/asciidoc-loader/-/asciidoc-loader-3.1.14.tgz", - "integrity": "sha512-4xxisnoBFrlLNY6f3xZtyyfgm+tBLsqesTcEStfc8jtXUMYJ4b2DWIzo1vULmxvZ7yY5+Q7YqEvS5o6kIWAG0A==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@antora/logger": "3.1.14", - "@antora/user-require-helper": "~3.0", - "@asciidoctor/core": "~2.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/cli": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@antora/cli/-/cli-3.1.14.tgz", - "integrity": "sha512-I6WcygMU2bFInjdURJjkYjo7K5M8B3lBB53v9OO0IcY0LhEY8Wa7IlZ7wVinf5qEjHvaYzRGTZVl6RsJtVt7Sw==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@antora/logger": "3.1.14", - "@antora/playbook-builder": "3.1.14", - "@antora/user-require-helper": "~3.0", - "commander": "~11.1" - }, - "bin": { - "antora": "bin/antora" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/content-aggregator": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@antora/content-aggregator/-/content-aggregator-3.1.14.tgz", - "integrity": "sha512-FVuBgnrGPiktYqK1WHbGF8O8l4m5KHlkxoJumrbacgFo8SKuiRFEo31zalxrCUsv8QM3UBEgX+LdHrve/9CGLg==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@antora/expand-path-helper": "~3.0", - "@antora/logger": "3.1.14", - "@antora/user-require-helper": "~3.0", - "braces": "~3.0", - "cache-directory": "~2.0", - "fast-glob": "~3.3", - "hpagent": "~1.2", - "isomorphic-git": "~1.25", - "js-yaml": "~4.1", - "multi-progress": "~4.0", - "picomatch": "~4.0", - "progress": "~2.0", - "should-proxy": "~1.0", - "simple-get": "~4.0", - "vinyl": "~3.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/content-classifier": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@antora/content-classifier/-/content-classifier-3.1.14.tgz", - "integrity": "sha512-y8Fk+KU1lqD3aawOu3ZFK92YfOZ1k3YBJhLI9QIFM6Ck4STPnf7AwYbhfOtjODlwer5/OhFmfhjUB2hn7onGnA==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@antora/asciidoc-loader": "3.1.14", - "@antora/logger": "3.1.14", - "mime-types": "~2.1", - "vinyl": "~3.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/document-converter": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@antora/document-converter/-/document-converter-3.1.14.tgz", - "integrity": "sha512-f6wFnL+489DI0ZDgoxYWzbxxWqPviRiJ56OHS1NixEfvJ7OpRBDPEbX1xnsIeiyFBgqX4+nY92MsCWKTa+Gf3w==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@antora/asciidoc-loader": "3.1.14" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/expand-path-helper": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@antora/expand-path-helper/-/expand-path-helper-3.0.0.tgz", - "integrity": "sha512-7PdEIhk97v85/CSm3HynCsX14TR6oIVz1s233nNLsiWubE8tTnpPt4sNRJR+hpmIZ6Bx9c6QDp3XIoiyu/WYYA==", - "dev": true, - "license": "MPL-2.0", - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/file-publisher": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@antora/file-publisher/-/file-publisher-3.1.14.tgz", - "integrity": "sha512-fTaAnkyKSOlsxQM1TBFCAmiERA6Q67XleDCD2bMPVgfcENmo0Xfx59KwCHaA92IcRSmMftydlXHPaFxNh0UVsg==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@antora/expand-path-helper": "~3.0", - "@antora/user-require-helper": "~3.0", - "vinyl": "~3.0", - "yazl": "~2.5" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/logger": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@antora/logger/-/logger-3.1.14.tgz", - "integrity": "sha512-kVEeGqZbXR903hPIm+BlN97fLdQ3LoUzE/BOPZ6vRp9m9Mmbnm67Kg7fSYkfTMLB0S2UWpAPFg22RdsU5ZoAzA==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@antora/expand-path-helper": "~3.0", - "pino": "~9.2", - "pino-pretty": "~11.2", - "sonic-boom": "~4.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/lunr-extension": { - "version": "1.0.0-alpha.13", - "resolved": "https://registry.npmjs.org/@antora/lunr-extension/-/lunr-extension-1.0.0-alpha.13.tgz", - "integrity": "sha512-u8n8XLB6elMmXbW0bdeL5jG8UBJi6PSiz1zaMn+wIIIu/bnxotRBW4kEWSge+zTfdF4rEYMcJ9LvkAOamMyuKQ==", - "dev": true, - "license": "MPL-2.0", - "workspaces": [ - "." - ], - "dependencies": { - "htmlparser2": "~9.1", - "lunr": "~2.3", - "lunr-languages": "~1.10" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/navigation-builder": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@antora/navigation-builder/-/navigation-builder-3.1.14.tgz", - "integrity": "sha512-/637YLGD7oUHGSfEfszXkk4ASfIhDAg5Xs9035J1dV07XYRlGqmtUb15rtapbcECpcQFjCyM5jFQYSNNvLrGcQ==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@antora/asciidoc-loader": "3.1.14" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/page-composer": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@antora/page-composer/-/page-composer-3.1.14.tgz", - "integrity": "sha512-RfA+67TxCqUPrQbZdrfjgLpHh8MR2z2du7cyF3HGX4N6DpqEBvz81NHHl3rA3fj6BQZPQbGm2OYAMU6wzJ6Pog==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@antora/logger": "3.1.14", - "handlebars": "~4.7", - "require-from-string": "~2.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/playbook-builder": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@antora/playbook-builder/-/playbook-builder-3.1.14.tgz", - "integrity": "sha512-Ss2r7In00u/n9Da+JOxEqIE8NeRosf+f+agzH3Te09JV/mpgZKxEOE5V/VuP+TNNq4ww1eu5aOS8DiU2PYwj4Q==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@iarna/toml": "~2.2", - "convict": "~6.2", - "js-yaml": "~4.1", - "json5": "~2.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/redirect-producer": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@antora/redirect-producer/-/redirect-producer-3.1.14.tgz", - "integrity": "sha512-5koAwRk1cZrvE/qfOWKXqb3jtxrZbWA5EYHYGFEoato5By3cbC42blH4Bre9/48pjyS6znFpbZhYUBpT7PRhZA==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "vinyl": "~3.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/site-generator": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@antora/site-generator/-/site-generator-3.1.14.tgz", - "integrity": "sha512-hQIUVtM9+xwleYWc4fIRZmiKl2p+ItOJuUm2+Hkdh07BZsySxkMOxxCyZsvTn9rc+4R94CYqDQCYElwFwdB2WA==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@antora/asciidoc-loader": "3.1.14", - "@antora/content-aggregator": "3.1.14", - "@antora/content-classifier": "3.1.14", - "@antora/document-converter": "3.1.14", - "@antora/file-publisher": "3.1.14", - "@antora/logger": "3.1.14", - "@antora/navigation-builder": "3.1.14", - "@antora/page-composer": "3.1.14", - "@antora/playbook-builder": "3.1.14", - "@antora/redirect-producer": "3.1.14", - "@antora/site-mapper": "3.1.14", - "@antora/site-publisher": "3.1.14", - "@antora/ui-loader": "3.1.14", - "@antora/user-require-helper": "~3.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/site-mapper": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@antora/site-mapper/-/site-mapper-3.1.14.tgz", - "integrity": "sha512-3qbETtwadl+fWREjzrBUxPUorMcMiZ+hdkB1El9z7it9KzKh0Yp7Je0+2uTxGX+Lov9uik48dZJ9e/mr5PeaRQ==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@antora/content-classifier": "3.1.14", - "vinyl": "~3.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/site-publisher": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@antora/site-publisher/-/site-publisher-3.1.14.tgz", - "integrity": "sha512-8apyEmgepUc7ms9CTEIPwN3tGtWwLqR6fbLMLs7hibqmOSR880Ut/4GRGb97sqcGQXSHdIyWK2oJKzRl1Akb6Q==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@antora/file-publisher": "3.1.14" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/ui-loader": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@antora/ui-loader/-/ui-loader-3.1.14.tgz", - "integrity": "sha512-LVvTdKQOB44CmJ1JQDu8sJf6rrLZMxPAWWackdg2JtGyGHHpd80/MBcv4BSFk7//cJQ13Oqm/7JCbhD51KAFjg==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@antora/expand-path-helper": "~3.0", - "braces": "~3.0", - "cache-directory": "~2.0", - "fast-glob": "~3.3", - "hpagent": "~1.2", - "js-yaml": "~4.1", - "picomatch": "~4.0", - "should-proxy": "~1.0", - "simple-get": "~4.0", - "vinyl": "~3.0", - "yauzl": "~3.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@antora/user-require-helper": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@antora/user-require-helper/-/user-require-helper-3.0.0.tgz", - "integrity": "sha512-KIXb8WYhnrnwH7Jj21l1w+et9k5GvcgcqvLOwxqWLEd0uVZOiMFdqFjqbVm3M+zcrs1JXWMeh2LLvxBbQs3q/Q==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@antora/expand-path-helper": "~3.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@asciidoctor/core": { - "version": "2.2.9", - "resolved": "https://registry.npmjs.org/@asciidoctor/core/-/core-2.2.9.tgz", - "integrity": "sha512-tIPRHo1T2SFmAm+j77cDsj0RuaszP7xJxsaVTTAF5CwKyTbazw9TnIVlpIWM5yWfIWAWcAZy92RcnPgMJwny1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "asciidoctor-opal-runtime": "0.3.4", - "unxhr": "~1.2" - }, - "engines": { - "node": ">=8.11", - "npm": ">=5.0.0", - "yarn": ">=1.1.0" - } - }, - "node_modules/@iarna/toml": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", - "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", - "dev": true, - "license": "ISC" - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dev": true, - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/antora": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/antora/-/antora-3.1.14.tgz", - "integrity": "sha512-z8HshJsT6pUfdDOUJ15RGtpOM9LmL6JXU5JBshoR/9/xd+1qLmKPkOnUv+HrijAk93r1imxZOdkmIqhLcv8B8A==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "@antora/cli": "3.1.14", - "@antora/site-generator": "3.1.14" - }, - "bin": { - "antora": "bin/antora" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/asciidoctor-opal-runtime": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/asciidoctor-opal-runtime/-/asciidoctor-opal-runtime-0.3.4.tgz", - "integrity": "sha512-zqd6zn1LV+PZ69AP/kEbB00zuPHMIAJY3IX8+aZV+X1qOwatYvKGjsMmdMc5ApfhtkjZ4mYkqiTPJWnEnBiMJg==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-glob": "~3.3", - "unxhr": "~1.2" - }, - "engines": { - "node": ">=8.11" - } - }, - "node_modules/async-lock": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz", - "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/atomic-sleep": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/b4a": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", - "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", - "dev": true, - "license": "Apache-2.0", - "peerDependencies": { - "react-native-b4a": "*" - }, - "peerDependenciesMeta": { - "react-native-b4a": { - "optional": true - } - } - }, - "node_modules/bare-events": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.3.tgz", - "integrity": "sha512-HdUm8EMQBLaJvGUdidNNbqpA1kYkwNcb+MYxkxCLAPJGQzlv9J0C24h8V65Z4c5GLd/JEALDvpFCQgpLJqc0zw==", - "dev": true, - "license": "Apache-2.0", - "peerDependencies": { - "bare-abort-controller": "*" - }, - "peerDependenciesMeta": { - "bare-abort-controller": { - "optional": true - } - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/cache-directory": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cache-directory/-/cache-directory-2.0.0.tgz", - "integrity": "sha512-7YKEapH+2Uikde8hySyfobXBqPKULDyHNl/lhKm7cKf/GJFdG/tU/WpLrOg2y9aUrQrWUilYqawFIiGJPS6gDA==", - "dev": true, - "license": "LGPL-3.0+", - "dependencies": { - "xdg-basedir": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/call-bind": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", - "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "get-intrinsic": "^1.3.0", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/clean-git-ref": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz", - "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - } - }, - "node_modules/convict": { - "version": "6.2.5", - "resolved": "https://registry.npmjs.org/convict/-/convict-6.2.5.tgz", - "integrity": "sha512-JtXpxqDqJ8P0UwEHwhxLzCIXQy97vlYBZR222Sbzb1q1Erex9ASrztJ29SyhWFQjod1AeFBaPzEEC8YvtZMIYg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "lodash.clonedeep": "^4.5.0", - "yargs-parser": "^20.2.7" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/dateformat": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", - "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/diff3": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", - "integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==", - "dev": true, - "license": "MIT" - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", - "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/events-universal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", - "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bare-events": "^2.7.0" - } - }, - "node_modules/fast-copy": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", - "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-fifo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-redact": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", - "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "dev": true, - "license": "MIT" - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/handlebars": { - "version": "4.7.9", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", - "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", - "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/help-me": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", - "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", - "dev": true, - "license": "MIT" - }, - "node_modules/hpagent": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", - "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/htmlparser2": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", - "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.1.0", - "entities": "^4.5.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, - "node_modules/isomorphic-git": { - "version": "1.25.10", - "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.25.10.tgz", - "integrity": "sha512-IxGiaKBwAdcgBXwIcxJU6rHLk+NrzYaaPKXXQffcA0GW3IUrQXdUPDXDo+hkGVcYruuz/7JlGBiuaeTCgIgivQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "async-lock": "^1.4.1", - "clean-git-ref": "^2.0.1", - "crc-32": "^1.2.0", - "diff3": "0.0.3", - "ignore": "^5.1.4", - "minimisted": "^2.0.0", - "pako": "^1.0.10", - "pify": "^4.0.1", - "readable-stream": "^3.4.0", - "sha.js": "^2.4.9", - "simple-get": "^4.0.1" - }, - "bin": { - "isogit": "cli.cjs" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/joycon": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/lunr-languages": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.10.0.tgz", - "integrity": "sha512-BBjKKcwrieJlzwwc9M5H/MRXGJ2qyOSDx/NXYiwkuKjiLOOoouh0WsDzeqcLoUWcX31y7i8sb8IgsZKObdUCkw==", - "dev": true, - "license": "MPL-1.1" - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minimisted": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz", - "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5" - } - }, - "node_modules/multi-progress": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/multi-progress/-/multi-progress-4.0.0.tgz", - "integrity": "sha512-9zcjyOou3FFCKPXsmkbC3ethv51SFPoA4dJD6TscIp2pUmy26kBDZW6h9XofPELrzseSkuD7r0V+emGEeo39Pg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "progress": "^2.0.0" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "license": "MIT" - }, - "node_modules/on-exit-leak-free": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", - "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true, - "license": "(MIT AND Zlib)" - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true, - "license": "MIT" - }, - "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pino": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-9.2.0.tgz", - "integrity": "sha512-g3/hpwfujK5a4oVbaefoJxezLzsDgLcNJeITvC6yrfwYeT9la+edCK42j5QpEQSQCZgTKapXvnQIdgZwvRaZug==", - "dev": true, - "license": "MIT", - "dependencies": { - "atomic-sleep": "^1.0.0", - "fast-redact": "^3.1.1", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^1.2.0", - "pino-std-serializers": "^7.0.0", - "process-warning": "^3.0.0", - "quick-format-unescaped": "^4.0.3", - "real-require": "^0.2.0", - "safe-stable-stringify": "^2.3.1", - "sonic-boom": "^4.0.1", - "thread-stream": "^3.0.0" - }, - "bin": { - "pino": "bin.js" - } - }, - "node_modules/pino-abstract-transport": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", - "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "readable-stream": "^4.0.0", - "split2": "^4.0.0" - } - }, - "node_modules/pino-abstract-transport/node_modules/readable-stream": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", - "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", - "dev": true, - "license": "MIT", - "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/pino-pretty": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-11.2.2.tgz", - "integrity": "sha512-2FnyGir8nAJAqD3srROdrF1J5BIcMT4nwj7hHSc60El6Uxlym00UbCCd8pYIterstVBFlMyF1yFV8XdGIPbj4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "colorette": "^2.0.7", - "dateformat": "^4.6.3", - "fast-copy": "^3.0.2", - "fast-safe-stringify": "^2.1.1", - "help-me": "^5.0.0", - "joycon": "^3.1.1", - "minimist": "^1.2.6", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^1.0.0", - "pump": "^3.0.0", - "readable-stream": "^4.0.0", - "secure-json-parse": "^2.4.0", - "sonic-boom": "^4.0.1", - "strip-json-comments": "^3.1.1" - }, - "bin": { - "pino-pretty": "bin.js" - } - }, - "node_modules/pino-pretty/node_modules/readable-stream": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", - "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", - "dev": true, - "license": "MIT", - "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/pino-std-serializers": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", - "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", - "dev": true, - "license": "MIT" - }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/process-warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", - "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/pump": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/quick-format-unescaped": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", - "dev": true, - "license": "MIT" - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/real-require": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", - "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", - "dev": true, - "license": "ISC" - }, - "node_modules/replace-ext": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", - "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safe-stable-stringify": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/secure-json-parse": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", - "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/sha.js": { - "version": "2.4.12", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", - "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", - "dev": true, - "license": "(MIT AND BSD-3-Clause)", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.0" - }, - "bin": { - "sha.js": "bin.js" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/should-proxy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/should-proxy/-/should-proxy-1.0.4.tgz", - "integrity": "sha512-RPQhIndEIVUCjkfkQ6rs6sOR6pkxJWCNdxtfG5pP0RVgUYbK5911kLTF0TNcCC0G3YCGd492rMollFT2aTd9iQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" + "name": "doc", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "doc", + "dependencies": { + "@cppalliance/antora-downloads-extension": "^0.0.2" + }, + "devDependencies": { + "@antora/cli": ">=3.1.14", + "@antora/site-generator": ">=3.1.14", + "antora": ">=3.1.14" + } + }, + "node_modules/@antora/asciidoc-loader": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@antora/asciidoc-loader/-/asciidoc-loader-3.1.14.tgz", + "integrity": "sha512-4xxisnoBFrlLNY6f3xZtyyfgm+tBLsqesTcEStfc8jtXUMYJ4b2DWIzo1vULmxvZ7yY5+Q7YqEvS5o6kIWAG0A==", + "dev": true, + "dependencies": { + "@antora/logger": "3.1.14", + "@antora/user-require-helper": "~3.0", + "@asciidoctor/core": "~2.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/cli": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@antora/cli/-/cli-3.1.14.tgz", + "integrity": "sha512-I6WcygMU2bFInjdURJjkYjo7K5M8B3lBB53v9OO0IcY0LhEY8Wa7IlZ7wVinf5qEjHvaYzRGTZVl6RsJtVt7Sw==", + "dev": true, + "dependencies": { + "@antora/logger": "3.1.14", + "@antora/playbook-builder": "3.1.14", + "@antora/user-require-helper": "~3.0", + "commander": "~11.1" + }, + "bin": { + "antora": "bin/antora" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/content-aggregator": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@antora/content-aggregator/-/content-aggregator-3.1.14.tgz", + "integrity": "sha512-FVuBgnrGPiktYqK1WHbGF8O8l4m5KHlkxoJumrbacgFo8SKuiRFEo31zalxrCUsv8QM3UBEgX+LdHrve/9CGLg==", + "dev": true, + "dependencies": { + "@antora/expand-path-helper": "~3.0", + "@antora/logger": "3.1.14", + "@antora/user-require-helper": "~3.0", + "braces": "~3.0", + "cache-directory": "~2.0", + "fast-glob": "~3.3", + "hpagent": "~1.2", + "isomorphic-git": "~1.25", + "js-yaml": "~4.1", + "multi-progress": "~4.0", + "picomatch": "~4.0", + "progress": "~2.0", + "should-proxy": "~1.0", + "simple-get": "~4.0", + "vinyl": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/content-classifier": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@antora/content-classifier/-/content-classifier-3.1.14.tgz", + "integrity": "sha512-y8Fk+KU1lqD3aawOu3ZFK92YfOZ1k3YBJhLI9QIFM6Ck4STPnf7AwYbhfOtjODlwer5/OhFmfhjUB2hn7onGnA==", + "dev": true, + "dependencies": { + "@antora/asciidoc-loader": "3.1.14", + "@antora/logger": "3.1.14", + "mime-types": "~2.1", + "vinyl": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/document-converter": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@antora/document-converter/-/document-converter-3.1.14.tgz", + "integrity": "sha512-f6wFnL+489DI0ZDgoxYWzbxxWqPviRiJ56OHS1NixEfvJ7OpRBDPEbX1xnsIeiyFBgqX4+nY92MsCWKTa+Gf3w==", + "dev": true, + "dependencies": { + "@antora/asciidoc-loader": "3.1.14" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/expand-path-helper": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@antora/expand-path-helper/-/expand-path-helper-3.0.0.tgz", + "integrity": "sha512-7PdEIhk97v85/CSm3HynCsX14TR6oIVz1s233nNLsiWubE8tTnpPt4sNRJR+hpmIZ6Bx9c6QDp3XIoiyu/WYYA==", + "dev": true, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/file-publisher": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@antora/file-publisher/-/file-publisher-3.1.14.tgz", + "integrity": "sha512-fTaAnkyKSOlsxQM1TBFCAmiERA6Q67XleDCD2bMPVgfcENmo0Xfx59KwCHaA92IcRSmMftydlXHPaFxNh0UVsg==", + "dev": true, + "dependencies": { + "@antora/expand-path-helper": "~3.0", + "@antora/user-require-helper": "~3.0", + "vinyl": "~3.0", + "yazl": "~2.5" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/logger": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@antora/logger/-/logger-3.1.14.tgz", + "integrity": "sha512-kVEeGqZbXR903hPIm+BlN97fLdQ3LoUzE/BOPZ6vRp9m9Mmbnm67Kg7fSYkfTMLB0S2UWpAPFg22RdsU5ZoAzA==", + "dev": true, + "dependencies": { + "@antora/expand-path-helper": "~3.0", + "pino": "~9.2", + "pino-pretty": "~11.2", + "sonic-boom": "~4.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/navigation-builder": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@antora/navigation-builder/-/navigation-builder-3.1.14.tgz", + "integrity": "sha512-/637YLGD7oUHGSfEfszXkk4ASfIhDAg5Xs9035J1dV07XYRlGqmtUb15rtapbcECpcQFjCyM5jFQYSNNvLrGcQ==", + "dev": true, + "dependencies": { + "@antora/asciidoc-loader": "3.1.14" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/page-composer": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@antora/page-composer/-/page-composer-3.1.14.tgz", + "integrity": "sha512-RfA+67TxCqUPrQbZdrfjgLpHh8MR2z2du7cyF3HGX4N6DpqEBvz81NHHl3rA3fj6BQZPQbGm2OYAMU6wzJ6Pog==", + "dev": true, + "dependencies": { + "@antora/logger": "3.1.14", + "handlebars": "~4.7", + "require-from-string": "~2.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/playbook-builder": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@antora/playbook-builder/-/playbook-builder-3.1.14.tgz", + "integrity": "sha512-Ss2r7In00u/n9Da+JOxEqIE8NeRosf+f+agzH3Te09JV/mpgZKxEOE5V/VuP+TNNq4ww1eu5aOS8DiU2PYwj4Q==", + "dev": true, + "dependencies": { + "@iarna/toml": "~2.2", + "convict": "~6.2", + "js-yaml": "~4.1", + "json5": "~2.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/redirect-producer": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@antora/redirect-producer/-/redirect-producer-3.1.14.tgz", + "integrity": "sha512-5koAwRk1cZrvE/qfOWKXqb3jtxrZbWA5EYHYGFEoato5By3cbC42blH4Bre9/48pjyS6znFpbZhYUBpT7PRhZA==", + "dev": true, + "dependencies": { + "vinyl": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/site-generator": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@antora/site-generator/-/site-generator-3.1.14.tgz", + "integrity": "sha512-hQIUVtM9+xwleYWc4fIRZmiKl2p+ItOJuUm2+Hkdh07BZsySxkMOxxCyZsvTn9rc+4R94CYqDQCYElwFwdB2WA==", + "dev": true, + "dependencies": { + "@antora/asciidoc-loader": "3.1.14", + "@antora/content-aggregator": "3.1.14", + "@antora/content-classifier": "3.1.14", + "@antora/document-converter": "3.1.14", + "@antora/file-publisher": "3.1.14", + "@antora/logger": "3.1.14", + "@antora/navigation-builder": "3.1.14", + "@antora/page-composer": "3.1.14", + "@antora/playbook-builder": "3.1.14", + "@antora/redirect-producer": "3.1.14", + "@antora/site-mapper": "3.1.14", + "@antora/site-publisher": "3.1.14", + "@antora/ui-loader": "3.1.14", + "@antora/user-require-helper": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/site-mapper": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@antora/site-mapper/-/site-mapper-3.1.14.tgz", + "integrity": "sha512-3qbETtwadl+fWREjzrBUxPUorMcMiZ+hdkB1El9z7it9KzKh0Yp7Je0+2uTxGX+Lov9uik48dZJ9e/mr5PeaRQ==", + "dev": true, + "dependencies": { + "@antora/content-classifier": "3.1.14", + "vinyl": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/site-publisher": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@antora/site-publisher/-/site-publisher-3.1.14.tgz", + "integrity": "sha512-8apyEmgepUc7ms9CTEIPwN3tGtWwLqR6fbLMLs7hibqmOSR880Ut/4GRGb97sqcGQXSHdIyWK2oJKzRl1Akb6Q==", + "dev": true, + "dependencies": { + "@antora/file-publisher": "3.1.14" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/ui-loader": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@antora/ui-loader/-/ui-loader-3.1.14.tgz", + "integrity": "sha512-LVvTdKQOB44CmJ1JQDu8sJf6rrLZMxPAWWackdg2JtGyGHHpd80/MBcv4BSFk7//cJQ13Oqm/7JCbhD51KAFjg==", + "dev": true, + "dependencies": { + "@antora/expand-path-helper": "~3.0", + "braces": "~3.0", + "cache-directory": "~2.0", + "fast-glob": "~3.3", + "hpagent": "~1.2", + "js-yaml": "~4.1", + "picomatch": "~4.0", + "should-proxy": "~1.0", + "simple-get": "~4.0", + "vinyl": "~3.0", + "yauzl": "~3.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/user-require-helper": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@antora/user-require-helper/-/user-require-helper-3.0.0.tgz", + "integrity": "sha512-KIXb8WYhnrnwH7Jj21l1w+et9k5GvcgcqvLOwxqWLEd0uVZOiMFdqFjqbVm3M+zcrs1JXWMeh2LLvxBbQs3q/Q==", + "dev": true, + "dependencies": { + "@antora/expand-path-helper": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@asciidoctor/core": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@asciidoctor/core/-/core-2.2.8.tgz", + "integrity": "sha512-oozXk7ZO1RAd/KLFLkKOhqTcG4GO3CV44WwOFg2gMcCsqCUTarvMT7xERIoWW2WurKbB0/ce+98r01p8xPOlBw==", + "dev": true, + "dependencies": { + "asciidoctor-opal-runtime": "0.3.3", + "unxhr": "1.0.1" + }, + "engines": { + "node": ">=8.11", + "npm": ">=5.0.0", + "yarn": ">=1.1.0" + } + }, + "node_modules/@cppalliance/antora-downloads-extension": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@cppalliance/antora-downloads-extension/-/antora-downloads-extension-0.0.2.tgz", + "integrity": "sha512-2wXahlvRz9J75ZSfzDeP4XpIZiqIm+w/YjmCWJxFPp6oWgP7e8f6ps7HqdtHNGxnK5mG38OjiCFdHjmHYfgbDA==", + "license": "BSL-1.0" + }, + "node_modules/@iarna/toml": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", + "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/antora": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/antora/-/antora-3.1.14.tgz", + "integrity": "sha512-z8HshJsT6pUfdDOUJ15RGtpOM9LmL6JXU5JBshoR/9/xd+1qLmKPkOnUv+HrijAk93r1imxZOdkmIqhLcv8B8A==", + "dev": true, + "dependencies": { + "@antora/cli": "3.1.14", + "@antora/site-generator": "3.1.14" + }, + "bin": { + "antora": "bin/antora" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/asciidoctor-opal-runtime": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/asciidoctor-opal-runtime/-/asciidoctor-opal-runtime-0.3.3.tgz", + "integrity": "sha512-/CEVNiOia8E5BMO9FLooo+Kv18K4+4JBFRJp8vUy/N5dMRAg+fRNV4HA+o6aoSC79jVU/aT5XvUpxSxSsTS8FQ==", + "dev": true, + "dependencies": { + "glob": "7.1.3", + "unxhr": "1.0.1" + }, + "engines": { + "node": ">=8.11" + } + }, + "node_modules/async-lock": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz", + "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==", + "dev": true + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/b4a": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", + "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", + "dev": true, + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/bare-events": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.0.tgz", + "integrity": "sha512-AOhh6Bg5QmFIXdViHbMc2tLDsBIRxdkIaIddPslJF9Z5De3APBScuqGP2uThXnIpqFrgoxMNC6km7uXNIMLHXA==", + "dev": true, + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/brace-expansion": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/cache-directory": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cache-directory/-/cache-directory-2.0.0.tgz", + "integrity": "sha512-7YKEapH+2Uikde8hySyfobXBqPKULDyHNl/lhKm7cKf/GJFdG/tU/WpLrOg2y9aUrQrWUilYqawFIiGJPS6gDA==", + "dev": true, + "dependencies": { + "xdg-basedir": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/clean-git-ref": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz", + "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==", + "dev": true + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convict": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/convict/-/convict-6.2.5.tgz", + "integrity": "sha512-JtXpxqDqJ8P0UwEHwhxLzCIXQy97vlYBZR222Sbzb1q1Erex9ASrztJ29SyhWFQjod1AeFBaPzEEC8YvtZMIYg==", + "dev": true, + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "yargs-parser": "^20.2.7" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/diff3": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", + "integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==", + "dev": true + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "dev": true, + "dependencies": { + "bare-events": "^2.7.0" + } + }, + "node_modules/fast-copy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", + "dev": true + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "dev": true + }, + "node_modules/hpagent": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", + "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/isomorphic-git": { + "version": "1.25.10", + "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.25.10.tgz", + "integrity": "sha512-IxGiaKBwAdcgBXwIcxJU6rHLk+NrzYaaPKXXQffcA0GW3IUrQXdUPDXDo+hkGVcYruuz/7JlGBiuaeTCgIgivQ==", + "dev": true, + "dependencies": { + "async-lock": "^1.4.1", + "clean-git-ref": "^2.0.1", + "crc-32": "^1.2.0", + "diff3": "0.0.3", + "ignore": "^5.1.4", + "minimisted": "^2.0.0", + "pako": "^1.0.10", + "pify": "^4.0.1", + "readable-stream": "^3.4.0", + "sha.js": "^2.4.9", + "simple-get": "^4.0.1" + }, + "bin": { + "isogit": "cli.cjs" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minimisted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz", + "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + } + }, + "node_modules/multi-progress": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/multi-progress/-/multi-progress-4.0.0.tgz", + "integrity": "sha512-9zcjyOou3FFCKPXsmkbC3ethv51SFPoA4dJD6TscIp2pUmy26kBDZW6h9XofPELrzseSkuD7r0V+emGEeo39Pg==", + "dev": true, + "peerDependencies": { + "progress": "^2.0.0" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pino": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.2.0.tgz", + "integrity": "sha512-g3/hpwfujK5a4oVbaefoJxezLzsDgLcNJeITvC6yrfwYeT9la+edCK42j5QpEQSQCZgTKapXvnQIdgZwvRaZug==", + "dev": true, + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.2.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^3.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", + "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", + "dev": true, + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "node_modules/pino-abstract-transport/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-11.2.2.tgz", + "integrity": "sha512-2FnyGir8nAJAqD3srROdrF1J5BIcMT4nwj7hHSc60El6Uxlym00UbCCd8pYIterstVBFlMyF1yFV8XdGIPbj4A==", + "dev": true, + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^3.0.2", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.0.0", + "pump": "^3.0.0", + "readable-stream": "^4.0.0", + "secure-json-parse": "^2.4.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-pretty/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", + "dev": true + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "dev": true + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "dev": true + }, + "node_modules/replace-ext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", + "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", + "dev": true + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/should-proxy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/should-proxy/-/should-proxy-1.0.4.tgz", + "integrity": "sha512-RPQhIndEIVUCjkfkQ6rs6sOR6pkxJWCNdxtfG5pP0RVgUYbK5911kLTF0TNcCC0G3YCGd492rMollFT2aTd9iQ==", + "dev": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/sonic-boom": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.0.1.tgz", + "integrity": "sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==", + "dev": true, + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/streamx": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", + "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", + "dev": true, + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "dev": true, + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/thread-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "dev": true, + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "dev": true, + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unxhr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unxhr/-/unxhr-1.0.1.tgz", + "integrity": "sha512-MAhukhVHyaLGDjyDYhy8gVjWJyhTECCdNsLwlMoGFoNJ3o79fpQhtQuzmAE4IxCMDwraF4cW8ZjpAV0m9CRQbg==", + "dev": true, + "engines": { + "node": ">=8.11" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/vinyl": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.1.tgz", + "integrity": "sha512-0QwqXteBNXgnLCdWdvPQBX6FXRHtIH3VhJPTd5Lwn28tJXc34YqSCWUmkOvtJHBmB3gGoPtrOKk3Ts8/kEZ9aA==", + "dev": true, + "dependencies": { + "clone": "^2.1.2", + "remove-trailing-separator": "^1.1.0", + "replace-ext": "^2.0.0", + "teex": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha512-1Dly4xqlulvPD3fZUQJLY+FUIeqN3N2MM3uqe4rCJftAvOjFa3jFGfctOgluGx4ahPbUCsZkmJILiP0Vi4T6lQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yauzl": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.1.3.tgz", + "integrity": "sha512-JCCdmlJJWv7L0q/KylOekyRaUrdEoUxWkWVcgorosTROCFWiS9p2NNPE9Yb91ak7b1N5SxAZEliWpspbZccivw==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "pend": "~1.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3" + } } - ], - "license": "MIT", - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/sonic-boom": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.0.1.tgz", - "integrity": "sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "atomic-sleep": "^1.0.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/streamx": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz", - "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==", - "dev": true, - "license": "MIT", - "dependencies": { - "events-universal": "^1.0.0", - "fast-fifo": "^1.3.2", - "text-decoder": "^1.1.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/teex": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", - "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "streamx": "^2.12.5" - } - }, - "node_modules/text-decoder": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", - "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "b4a": "^1.6.4" - } - }, - "node_modules/thread-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", - "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", - "dev": true, - "license": "MIT", - "dependencies": { - "real-require": "^0.2.0" - } - }, - "node_modules/to-buffer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", - "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "isarray": "^2.0.5", - "safe-buffer": "^5.2.1", - "typed-array-buffer": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/unxhr": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unxhr/-/unxhr-1.2.0.tgz", - "integrity": "sha512-6cGpm8NFXPD9QbSNx0cD2giy7teZ6xOkCUH3U89WKVkL9N9rBrWjlCwhR94Re18ZlAop4MOc3WU1M3Hv/bgpIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.11" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/vinyl": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.1.tgz", - "integrity": "sha512-0QwqXteBNXgnLCdWdvPQBX6FXRHtIH3VhJPTd5Lwn28tJXc34YqSCWUmkOvtJHBmB3gGoPtrOKk3Ts8/kEZ9aA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clone": "^2.1.2", - "remove-trailing-separator": "^1.1.0", - "replace-ext": "^2.0.0", - "teex": "^1.0.1" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.20", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", - "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/xdg-basedir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha512-1Dly4xqlulvPD3fZUQJLY+FUIeqN3N2MM3uqe4rCJftAvOjFa3jFGfctOgluGx4ahPbUCsZkmJILiP0Vi4T6lQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yauzl": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.1.3.tgz", - "integrity": "sha512-JCCdmlJJWv7L0q/KylOekyRaUrdEoUxWkWVcgorosTROCFWiS9p2NNPE9Yb91ak7b1N5SxAZEliWpspbZccivw==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "pend": "~1.2.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3" - } } - } } diff --git a/doc/package.json b/doc/package.json index 200c7f12e..a7c753eee 100644 --- a/doc/package.json +++ b/doc/package.json @@ -1,11 +1,10 @@ { - "name": "boost-graph-docs", - "private": true, - "description": "Build dependencies for the Boost.Graph Antora documentation site. Consumed by boostorg/release-tools via doc/build_antora.sh.", - "devDependencies": { - "@antora/cli": "3.1.14", - "@antora/site-generator": "3.1.14", - "antora": "3.1.14", - "@antora/lunr-extension": "^1.0.0-alpha.13" + "devDependencies": { + "@antora/cli": ">=3.1.14", + "@antora/site-generator": ">=3.1.14", + "antora": ">=3.1.14" + }, + "dependencies": { + "@cppalliance/antora-downloads-extension": "^0.0.2" + } } -} diff --git a/doc/playbook.yml b/doc/playbook.yml deleted file mode 100644 index 2b8a0720e..000000000 --- a/doc/playbook.yml +++ /dev/null @@ -1,30 +0,0 @@ -output: - dir: ./build/site - -site: - title: Boost.Graph Documentation - start_page: graph::index.adoc - -antora: - extensions: - - require: '@antora/lunr-extension' - index_latest_only: true - -content: - sources: - - url: .. - start_path: doc - branches: HEAD - edit_url: 'https://github.com/boostorg/graph/edit/develop/{path}' - -asciidoc: - attributes: - source-highlighter: highlight.js - # Enable the cppalliance theme's right-rail floating TOC on every page. - page-toc: '' - -ui: - bundle: - url: https://github.com/boostorg/website-v2-docs/releases/download/ui-master/ui-bundle.zip - snapshot: true - supplemental_files: ./supplemental-ui diff --git a/doc/supplemental-ui/partials/header-content.hbs b/doc/supplemental-ui/partials/header-content.hbs deleted file mode 100644 index 1dfadfc3f..000000000 --- a/doc/supplemental-ui/partials/header-content.hbs +++ /dev/null @@ -1,44 +0,0 @@ -{{!-- - Overrides the cppalliance bundle's header-content partial. - - Adds a site-wide banner above the existing nav-bearing #header div, linking - to the previous (pre-rewrite) Boost.Graph documentation. The original - partial body is preserved verbatim below. ---}} - - - -
- This documentation is being rewritten. If something looks off, please cross-check with the - Boost 1.91.0 Boost.Graph docs - and open an issue. -
- - diff --git a/doc/supplemental-ui/partials/nav-tree.hbs b/doc/supplemental-ui/partials/nav-tree.hbs deleted file mode 100644 index 1602217fb..000000000 --- a/doc/supplemental-ui/partials/nav-tree.hbs +++ /dev/null @@ -1,89 +0,0 @@ -{{!-- - Overrides the cppalliance bundle's nav-tree partial. - - Fixes vs upstream: - 1. Nests the recursive call inside the parent
  • , so child
      s - are true descendants of their parent item. - 2. Adds `class="nav-item"` to each
    • , so the bundle's collapse rule - (`.nav-item:not(.is-active) > .nav-list { display: none }`) applies. - 3. Emits a `{{/if}} - {{#if ./url}} - {{{./content}}} - {{else}} - {{{./content}}} - {{/if}} - - {{> nav-tree navigation=./items level=(increment ../level)}} -
    • - {{else}} - {{> nav-tree navigation=./items level=(increment ../level)}} - {{/if}} - {{/each}} -
    -{{/if}} diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 1adf5c853..ed34f78d7 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -133,6 +133,7 @@ exe push-relable : push-relabel-eg.cpp ; run put-get-helper-eg.cpp ; run quick_tour.cpp ; run quick-tour.cpp ; +run r_c_shortest_paths_example_old.cpp ; run r_c_shortest_paths_example.cpp ; run read_graphviz.cpp /boost/graph//boost_graph ; exe read_write_dimacs : read_write_dimacs-eg.cpp ; diff --git a/example/astar-cities.cpp b/example/astar-cities.cpp index 42d0d016a..1d79eb78a 100644 --- a/example/astar-cities.cpp +++ b/example/astar-cities.cpp @@ -116,7 +116,7 @@ class astar_goal_visitor : public boost::default_astar_visitor Vertex m_goal; }; -int main(int argc, char** argv) +int main() { // specify some types diff --git a/example/bipartite_example.cpp b/example/bipartite_example.cpp index 9c2c78c0c..b6418bad1 100644 --- a/example/bipartite_example.cpp +++ b/example/bipartite_example.cpp @@ -74,7 +74,7 @@ template < typename Graph > void print_bipartite(const Graph& g) } } -int main(int argc, char** argv) +int main() { using vector_graph_t = adjacency_list< vecS, vecS, undirectedS >; using E = std::pair< int, int >; diff --git a/example/bron_kerbosch_clique_number.cpp b/example/bron_kerbosch_clique_number.cpp index f21fdcf2d..407e48d8d 100644 --- a/example/bron_kerbosch_clique_number.cpp +++ b/example/bron_kerbosch_clique_number.cpp @@ -22,7 +22,7 @@ using Graph = undirected_graph<>; using Vertex = graph_traits< Graph >::vertex_descriptor; using Edge = graph_traits< Graph >::edge_descriptor; -int main(int argc, char* argv[]) +int main() { // Create the graph and read it from standard input. Graph g; diff --git a/example/bron_kerbosch_print_cliques.cpp b/example/bron_kerbosch_print_cliques.cpp index f656ffba9..42b3dfb16 100644 --- a/example/bron_kerbosch_print_cliques.cpp +++ b/example/bron_kerbosch_print_cliques.cpp @@ -50,7 +50,7 @@ using Edge = graph_traits< Graph >::edge_descriptor; // each vertex. This is used during graph creation. using NameMap = property_map< Graph, string Actor::* >::type; -int main(int argc, char* argv[]) +int main() { // Create the graph and and its name map accessor. Graph g; diff --git a/example/canonical_ordering.cpp b/example/canonical_ordering.cpp index 87d99011a..3416e82af 100644 --- a/example/canonical_ordering.cpp +++ b/example/canonical_ordering.cpp @@ -18,7 +18,7 @@ using namespace boost; -int main(int argc, char** argv) +int main() { using graph = adjacency_list< vecS, vecS, undirectedS, diff --git a/example/closeness_centrality.cpp b/example/closeness_centrality.cpp index 4181448cb..759368506 100644 --- a/example/closeness_centrality.cpp +++ b/example/closeness_centrality.cpp @@ -49,7 +49,7 @@ using ClosenessProperty = boost::exterior_vertex_property< Graph, float >; using ClosenessContainer = ClosenessProperty::container_type; using ClosenessMap = ClosenessProperty::map_type; -int main(int argc, char* argv[]) +int main() { // Create the graph and a property map that provides access to[ // tha actor names. diff --git a/example/clustering_coefficient.cpp b/example/clustering_coefficient.cpp index 4b64e1f5f..6aed5fdde 100644 --- a/example/clustering_coefficient.cpp +++ b/example/clustering_coefficient.cpp @@ -37,7 +37,7 @@ using ClusteringProperty = exterior_vertex_property< Graph, float >; using ClusteringContainer = ClusteringProperty::container_type; using ClusteringMap = ClusteringProperty::map_type; -int main(int argc, char* argv[]) +int main() { // Create the graph and a name map that provides access to // then actor names. diff --git a/example/cycle_ratio_example.cpp b/example/cycle_ratio_example.cpp index c7a295f38..311b1b377 100644 --- a/example/cycle_ratio_example.cpp +++ b/example/cycle_ratio_example.cpp @@ -38,7 +38,7 @@ template < typename TG > void gen_rand_graph(TG& g, size_t nV, size_t nE) randomize_property< edge_weight2_t >(g, ew2rg); } -int main(int argc, char* argv[]) +int main() { using std::cout; using std::endl; diff --git a/example/degree_centrality.cpp b/example/degree_centrality.cpp index cd249bfac..57b84192a 100644 --- a/example/degree_centrality.cpp +++ b/example/degree_centrality.cpp @@ -38,7 +38,7 @@ using CentralityProperty = exterior_vertex_property< Graph, unsigned >; using CentralityContainer = CentralityProperty::container_type; using CentralityMap = CentralityProperty::map_type; -int main(int argc, char* argv[]) +int main() { // Create the graph and a property map that provides access // to the actor names. diff --git a/example/eccentricity.cpp b/example/eccentricity.cpp index 8577ca2c9..fdbc3f3b5 100644 --- a/example/eccentricity.cpp +++ b/example/eccentricity.cpp @@ -48,7 +48,7 @@ using EccentricityProperty = boost::exterior_vertex_property< Graph, int >; using EccentricityContainer = EccentricityProperty::container_type; using EccentricityMap = EccentricityProperty::map_type; -int main(int argc, char* argv[]) +int main() { // Create the graph and a name map that provides access to // then actor names. diff --git a/example/girth.cpp b/example/girth.cpp index 0a031e1e9..2e6fc7b4c 100644 --- a/example/girth.cpp +++ b/example/girth.cpp @@ -21,21 +21,21 @@ Choose a branching factor, p: 2 Ok, now choose the cube root of graph size, q: 17 Starting at any given vertex, there are - 3 vertices at distance 1, - 6 vertices at distance 2, - 12 vertices at distance 3, - 24 vertices at distance 4, - 46 vertices at distance 5, - 90 vertices at distance 6, - 169 vertices at distance 7, - 290 vertices at distance 8, - 497 vertices at distance 9, - 634 vertices at distance 10, - 521 vertices at distance 11, - 138 vertices at distance 12, - 13 vertices at distance 13, - 3 vertices at distance 14, - 1 vertices at distance 15. + 3 vertices at distance 1, + 6 vertices at distance 2, + 12 vertices at distance 3, + 24 vertices at distance 4, + 46 vertices at distance 5, + 90 vertices at distance 6, + 169 vertices at distance 7, + 290 vertices at distance 8, + 497 vertices at distance 9, + 634 vertices at distance 10, + 521 vertices at distance 11, + 138 vertices at distance 12, + 13 vertices at distance 13, + 3 vertices at distance 14, + 1 vertices at distance 15. So the diameter is 15, and the girth is 9. */ @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -124,8 +125,18 @@ int main() g = raman(p, q, 0L, 0L); if (g == 0) { - std::cerr << " Sorry, I couldn't make that graph (error code " - << panic_code << ")" << std::endl; + std::cerr << " Sorry, I couldn't make that graph (" << + ( + panic_code == very_bad_specs ? "q is out of range" : + panic_code == very_bad_specs + 1 ? "p is out of range" : + panic_code == bad_specs + 5 ? "q is too big" : + panic_code == bad_specs + 6 ? "p is too big" : + panic_code == bad_specs + 1 ? "q isn't prime" : + panic_code == bad_specs + 7 ? "p isn't prime" : + panic_code == bad_specs + 3 ? "p is a multiple of q" : + panic_code == bad_specs + 2 ? "q isn't compatible with p=2" : + "not enough memory" + ) << ")" << std::endl; continue; } distance_list.clear(); @@ -151,7 +162,7 @@ int main() std::cout << "Starting at any given vertex, there are" << std::endl; for (long d = 1; distance_list[d] != 0; ++d) - std::cout << distance_list[d] << " vertices at distance " << d + std::cout << std::setw(8) << distance_list[d] << " vertices at distance " << d << (distance_list[d + 1] != 0 ? "," : ".") << std::endl; std::cout << "So the diameter is " << k - 1 << ", and the girth is " diff --git a/example/graph-thingie.cpp b/example/graph-thingie.cpp index 71eaa7809..3b3c665dd 100644 --- a/example/graph-thingie.cpp +++ b/example/graph-thingie.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include @@ -95,7 +95,8 @@ int main() cout << "graph " << get("name", dp, &graph) << " (" << get("identifier", dp, &graph) << ")\n\n"; - BOOST_FOREACH (graph_t::vertex_descriptor v, vertices(graph)) + for (graph_t::vertex_descriptor v : + boost::make_iterator_range(vertices(graph))) { cout << "vertex " << get("node_id", dp, v) << " (" << get("label", dp, v) << ")\n"; diff --git a/example/grid_graph_example.cpp b/example/grid_graph_example.cpp index bd3c251b5..f4c99ef6b 100644 --- a/example/grid_graph_example.cpp +++ b/example/grid_graph_example.cpp @@ -24,7 +24,7 @@ void print_vertex(Traits::vertex_descriptor vertex_to_print) << vertex_to_print[2] << ")" << std::endl; } -int main(int argc, char* argv[]) +int main() { // Define a 3x5x7 grid_graph where the second dimension doesn't wrap diff --git a/example/grid_graph_properties.cpp b/example/grid_graph_properties.cpp index a41968e5e..38cb75cac 100644 --- a/example/grid_graph_properties.cpp +++ b/example/grid_graph_properties.cpp @@ -11,7 +11,7 @@ #include #include -int main(int argc, char* argv[]) +int main() { // A 2D grid graph using GraphType = boost::grid_graph< 2 >; diff --git a/example/inclusive_mean_geodesic.cpp b/example/inclusive_mean_geodesic.cpp index 773b031c0..4c9275eb1 100644 --- a/example/inclusive_mean_geodesic.cpp +++ b/example/inclusive_mean_geodesic.cpp @@ -84,7 +84,7 @@ using GeodesicMap = GeodesicProperty::map_type; static float exclusive_geodesics(const Graph&, DistanceMatrixMap, GeodesicMap); static float inclusive_geodesics(const Graph&, DistanceMatrixMap, GeodesicMap); -int main(int argc, char* argv[]) +int main() { // Create the graph, a name map that providse abstract access // to the web page names, and the weight map as an accessor to diff --git a/example/incremental-components-eg.cpp b/example/incremental-components-eg.cpp index 54561ea96..dd7bae6d0 100644 --- a/example/incremental-components-eg.cpp +++ b/example/incremental-components-eg.cpp @@ -11,14 +11,14 @@ #include #include -#include #include #include #include +#include using namespace boost; -int main(int argc, char* argv[]) +int main() { using Graph = adjacency_list< vecS, vecS, undirectedS >; using Vertex = graph_traits< Graph >::vertex_descriptor; @@ -53,7 +53,7 @@ int main(int argc, char* argv[]) ds.union_set(4, 0); ds.union_set(2, 5); - BOOST_FOREACH (Vertex current_vertex, vertices(graph)) + for (Vertex current_vertex : boost::make_iterator_range(vertices(graph))) { std::cout << "representative[" << current_vertex << "] = " << ds.find_set(current_vertex) << std::endl; @@ -69,12 +69,13 @@ int main(int argc, char* argv[]) Components components(parent.begin(), parent.end()); // Iterate through the component indices - BOOST_FOREACH (VertexIndex component_index, components) + for (VertexIndex component_index : components) { std::cout << "component " << component_index << " contains: "; // Iterate through the child vertex indices for [component_index] - BOOST_FOREACH (VertexIndex child_index, components[component_index]) + for (VertexIndex child_index : + boost::make_iterator_range(components[component_index])) { std::cout << child_index << " "; } diff --git a/example/incremental_components.cpp b/example/incremental_components.cpp index f22692696..c1d6cc82b 100644 --- a/example/incremental_components.cpp +++ b/example/incremental_components.cpp @@ -10,11 +10,11 @@ #include #include -#include #include #include #include #include +#include /* @@ -47,7 +47,7 @@ using namespace boost; -int main(int argc, char* argv[]) +int main() { using Graph = adjacency_list< vecS, vecS, undirectedS >; using Vertex = graph_traits< Graph >::vertex_descriptor; @@ -86,7 +86,7 @@ int main(int argc, char* argv[]) print_graph(graph, get(boost::vertex_index, graph)); std::cout << std::endl; - BOOST_FOREACH (Vertex current_vertex, vertices(graph)) + for (Vertex current_vertex : boost::make_iterator_range(vertices(graph))) { std::cout << "representative[" << current_vertex << "] = " << ds.find_set(current_vertex) << std::endl; @@ -103,12 +103,13 @@ int main(int argc, char* argv[]) Components components(parent.begin(), parent.end()); // Iterate through the component indices - BOOST_FOREACH (VertexIndex current_index, components) + for (VertexIndex current_index : components) { std::cout << "component " << current_index << " contains: "; // Iterate through the child vertex indices for [current_index] - BOOST_FOREACH (VertexIndex child_index, components[current_index]) + for (VertexIndex child_index : + boost::make_iterator_range(components[current_index])) { std::cout << child_index << " "; } diff --git a/example/influence_prestige.cpp b/example/influence_prestige.cpp index c06a3134b..020859bd5 100644 --- a/example/influence_prestige.cpp +++ b/example/influence_prestige.cpp @@ -39,7 +39,7 @@ using CentralityProperty = exterior_vertex_property< Graph, unsigned >; using CentralityContainer = CentralityProperty::container_type; using CentralityMap = CentralityProperty::map_type; -int main(int argc, char* argv[]) +int main() { // Create the graph and a property map that provides // access to the actor names. diff --git a/example/kuratowski_subgraph.cpp b/example/kuratowski_subgraph.cpp index 6fe19234c..484b6669f 100644 --- a/example/kuratowski_subgraph.cpp +++ b/example/kuratowski_subgraph.cpp @@ -18,7 +18,7 @@ using namespace boost; -int main(int argc, char** argv) +int main() { using graph = adjacency_list< vecS, vecS, undirectedS, diff --git a/example/make_biconnected_planar.cpp b/example/make_biconnected_planar.cpp index dfbf1808d..bdd5d1424 100644 --- a/example/make_biconnected_planar.cpp +++ b/example/make_biconnected_planar.cpp @@ -19,7 +19,7 @@ using namespace boost; -int main(int argc, char** argv) +int main() { using graph = adjacency_list< vecS, vecS, undirectedS, diff --git a/example/make_connected.cpp b/example/make_connected.cpp index afa1edcfe..e259e9739 100644 --- a/example/make_connected.cpp +++ b/example/make_connected.cpp @@ -17,7 +17,7 @@ using namespace boost; -int main(int argc, char** argv) +int main() { using graph = adjacency_list< vecS, vecS, undirectedS, diff --git a/example/make_maximal_planar.cpp b/example/make_maximal_planar.cpp index b160dfd8f..27021c944 100644 --- a/example/make_maximal_planar.cpp +++ b/example/make_maximal_planar.cpp @@ -34,7 +34,7 @@ struct face_counter : public planar_face_traversal_visitor int count; }; -int main(int argc, char** argv) +int main() { using graph = adjacency_list< vecS, vecS, undirectedS, diff --git a/example/mcgregor_subgraphs_example.cpp b/example/mcgregor_subgraphs_example.cpp index 98f82d00e..b6565ecc0 100644 --- a/example/mcgregor_subgraphs_example.cpp +++ b/example/mcgregor_subgraphs_example.cpp @@ -71,7 +71,7 @@ template < typename Graph > struct example_callback VertexSizeFirst m_max_subgraph_size; }; -int main(int argc, char* argv[]) +int main() { // Using a vecS graph here so that we don't have to mess around with diff --git a/example/mean_geodesic.cpp b/example/mean_geodesic.cpp index a99a21cb4..4192e7fbc 100644 --- a/example/mean_geodesic.cpp +++ b/example/mean_geodesic.cpp @@ -48,7 +48,7 @@ using GeodesicProperty = exterior_vertex_property< Graph, float >; using GeodesicContainer = GeodesicProperty::container_type; using GeodesicMap = GeodesicProperty::map_type; -int main(int argc, char* argv[]) +int main() { // Create the graph and a property map that provides access // to the actor names. diff --git a/example/miles_span.cpp b/example/miles_span.cpp index b647ae61e..513e8df7e 100644 --- a/example/miles_span.cpp +++ b/example/miles_span.cpp @@ -31,7 +31,7 @@ struct total_length_visitor : public boost::dijkstra_visitor<> } template < class Vertex, class Graph > inline void finish_vertex(Vertex s, Graph& g) - { + { (void)g; _total_length += boost::get(_distance, s); } D& _total_length; @@ -105,6 +105,7 @@ int main(int argc, char* argv[]) auto d = get(z_property< long >(), g); // Use the "w" property for parent auto p = get(w_property< Vertex* >(), g); + using Distance = property_map< Graph*, z_property< long > >::type; total_length_visitor< Distance > length_vis(sp_length, d); prim_minimum_spanning_tree(g, p, diff --git a/example/minimum_degree_ordering.cpp b/example/minimum_degree_ordering.cpp index 19259bba9..55fa64521 100644 --- a/example/minimum_degree_ordering.cpp +++ b/example/minimum_degree_ordering.cpp @@ -48,17 +48,17 @@ struct harwell_boeing // Never called: // readHB_info(filename, &M, &N, &nonzeros, &Type, &Nrhs); colptr = (int*)malloc((N + 1) * sizeof(int)); - if (colptr == NULL) + if (colptr == nullptr) terminate("Insufficient memory for colptr.\n"); rowind = (int*)malloc(nonzeros * sizeof(int)); - if (rowind == NULL) + if (rowind == nullptr) terminate("Insufficient memory for rowind.\n"); if (Type[0] == 'C') { isComplex = true; val = (double*)malloc(nonzeros * sizeof(double) * 2); - if (val == NULL) + if (val == nullptr) terminate("Insufficient memory for val.\n"); } else @@ -66,7 +66,7 @@ struct harwell_boeing if (Type[0] != 'P') { val = (double*)malloc(nonzeros * sizeof(double)); - if (val == NULL) + if (val == nullptr) terminate("Insufficient memory for val.\n"); } } diff --git a/example/planar_face_traversal.cpp b/example/planar_face_traversal.cpp index 90ba2a31e..de85ad07e 100644 --- a/example/planar_face_traversal.cpp +++ b/example/planar_face_traversal.cpp @@ -40,7 +40,7 @@ struct edge_output_visitor : public output_visitor template < typename Edge > void next_edge(Edge e) { std::cout << e << " "; } }; -int main(int argc, char** argv) +int main() { using graph = adjacency_list< vecS, vecS, undirectedS, diff --git a/example/r_c_shortest_paths_example.cpp b/example/r_c_shortest_paths_example.cpp index 77326bb7c..0b351ba0a 100644 --- a/example/r_c_shortest_paths_example.cpp +++ b/example/r_c_shortest_paths_example.cpp @@ -155,7 +155,7 @@ class ref_spptw spp_spptw_res_cont& new_cont, const spp_spptw_res_cont& old_cont, graph_traits< SPPRC_Example_Graph >::edge_descriptor ed) const { - const SPPRC_Example_Graph_Arc_Prop& arc_prop = get(edge_bundle, g)[ed]; + const SPPRC_Example_Graph_Arc_Prop arc_prop = get(edge_bundle, g)[ed]; const SPPRC_Example_Graph_Vert_Prop& vert_prop = get(vertex_bundle, g)[target(ed, g)]; new_cont.cost = old_cont.cost + arc_prop.cost; @@ -249,7 +249,7 @@ int main() std::vector< spp_no_rc_res_cont > pareto_opt_rcs_no_rc; r_c_shortest_paths(g, get(&SPPRC_Example_Graph_Vert_Prop::num, g), - get(&SPPRC_Example_Graph_Arc_Prop::num, g), s, t, opt_solutions, + s, t, opt_solutions, pareto_opt_rcs_no_rc, spp_no_rc_res_cont(0), ref_no_res_cont(), dominance_no_res_cont(), std::allocator< r_c_shortest_paths_label< SPPRC_Example_Graph, @@ -278,7 +278,7 @@ int main() std::vector< spp_spptw_res_cont > pareto_opt_rcs_spptw; r_c_shortest_paths(g, get(&SPPRC_Example_Graph_Vert_Prop::num, g), - get(&SPPRC_Example_Graph_Arc_Prop::num, g), s, t, opt_solutions_spptw, + s, t, opt_solutions_spptw, pareto_opt_rcs_spptw, spp_spptw_res_cont(0, 0), ref_spptw(), dominance_spptw(), std::allocator< r_c_shortest_paths_label< SPPRC_Example_Graph, diff --git a/example/r_c_shortest_paths_example_old.cpp b/example/r_c_shortest_paths_example_old.cpp new file mode 100644 index 000000000..f5667819e --- /dev/null +++ b/example/r_c_shortest_paths_example_old.cpp @@ -0,0 +1,332 @@ +// Copyright Michael Drexl 2005, 2006. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://boost.org/LICENSE_1_0.txt) +#define BOOST_ALLOW_DEPRECATED_SYMBOLS + +// Example use of the resource-constrained shortest paths algorithm. +#include + +#ifdef BOOST_MSVC +#pragma warning(disable : 4267) +#endif + +#include + +#include +#include + +using namespace boost; + +struct SPPRC_Example_Graph_Vert_Prop +{ + SPPRC_Example_Graph_Vert_Prop(int n = 0, int e = 0, int l = 0) + : num(n), eat(e), lat(l) + { + } + int num; + // earliest arrival time + int eat; + // latest arrival time + int lat; +}; + +struct SPPRC_Example_Graph_Arc_Prop +{ + SPPRC_Example_Graph_Arc_Prop(int n = 0, int c = 0, int t = 0) + : num(n), cost(c), time(t) + { + } + int num; + // traversal cost + int cost; + // traversal time + int time; +}; + +using SPPRC_Example_Graph = adjacency_list< vecS, vecS, directedS, + SPPRC_Example_Graph_Vert_Prop, SPPRC_Example_Graph_Arc_Prop >; + +// data structures for spp without resource constraints: +// ResourceContainer model +struct spp_no_rc_res_cont +{ + spp_no_rc_res_cont(int c = 0) : cost(c) {}; + spp_no_rc_res_cont& operator=(const spp_no_rc_res_cont& other) + { + if (this == &other) + return *this; + this->~spp_no_rc_res_cont(); + new (this) spp_no_rc_res_cont(other); + return *this; + } + int cost; +}; + +bool operator==( + const spp_no_rc_res_cont& res_cont_1, const spp_no_rc_res_cont& res_cont_2) +{ + return (res_cont_1.cost == res_cont_2.cost); +} + +bool operator<( + const spp_no_rc_res_cont& res_cont_1, const spp_no_rc_res_cont& res_cont_2) +{ + return (res_cont_1.cost < res_cont_2.cost); +} + +// ResourceExtensionFunction model +class ref_no_res_cont +{ +public: + inline bool operator()(const SPPRC_Example_Graph& g, + spp_no_rc_res_cont& new_cont, const spp_no_rc_res_cont& old_cont, + graph_traits< SPPRC_Example_Graph >::edge_descriptor ed) const + { + new_cont.cost = old_cont.cost + g[ed].cost; + return true; + } +}; + +// DominanceFunction model +class dominance_no_res_cont +{ +public: + inline bool operator()(const spp_no_rc_res_cont& res_cont_1, + const spp_no_rc_res_cont& res_cont_2) const + { + // must be "<=" here!!! + // must NOT be "<"!!! + return res_cont_1.cost <= res_cont_2.cost; + // this is not a contradiction to the documentation + // the documentation says: + // "A label $l_1$ dominates a label $l_2$ if and only if both are + // resident at the same vertex, and if, for each resource, the resource + // consumption of $l_1$ is less than or equal to the resource + // consumption of $l_2$, and if there is at least one resource where + // $l_1$ has a lower resource consumption than $l_2$." one can think of + // a new label with a resource consumption equal to that of an old label + // as being dominated by that old label, because the new one will have a + // higher number and is created at a later point in time, so one can + // implicitly use the number or the creation time as a resource for + // tie-breaking + } +}; +// end data structures for spp without resource constraints: + +// data structures for shortest path problem with time windows (spptw) +// ResourceContainer model +struct spp_spptw_res_cont +{ + spp_spptw_res_cont(int c = 0, int t = 0) : cost(c), time(t) {} + spp_spptw_res_cont& operator=(const spp_spptw_res_cont& other) + { + if (this == &other) + return *this; + this->~spp_spptw_res_cont(); + new (this) spp_spptw_res_cont(other); + return *this; + } + int cost; + int time; +}; + +bool operator==( + const spp_spptw_res_cont& res_cont_1, const spp_spptw_res_cont& res_cont_2) +{ + return (res_cont_1.cost == res_cont_2.cost + && res_cont_1.time == res_cont_2.time); +} + +bool operator<( + const spp_spptw_res_cont& res_cont_1, const spp_spptw_res_cont& res_cont_2) +{ + if (res_cont_1.cost > res_cont_2.cost) + return false; + if (res_cont_1.cost == res_cont_2.cost) + return res_cont_1.time < res_cont_2.time; + return true; +} + +// ResourceExtensionFunction model +class ref_spptw +{ +public: + inline bool operator()(const SPPRC_Example_Graph& g, + spp_spptw_res_cont& new_cont, const spp_spptw_res_cont& old_cont, + graph_traits< SPPRC_Example_Graph >::edge_descriptor ed) const + { + const SPPRC_Example_Graph_Arc_Prop& arc_prop = get(edge_bundle, g)[ed]; + const SPPRC_Example_Graph_Vert_Prop& vert_prop + = get(vertex_bundle, g)[target(ed, g)]; + new_cont.cost = old_cont.cost + arc_prop.cost; + int& i_time = new_cont.time; + i_time = old_cont.time + arc_prop.time; + i_time < vert_prop.eat ? i_time = vert_prop.eat : 0; + return i_time <= vert_prop.lat ? true : false; + } +}; + +// DominanceFunction model +class dominance_spptw +{ +public: + inline bool operator()(const spp_spptw_res_cont& res_cont_1, + const spp_spptw_res_cont& res_cont_2) const + { + // must be "<=" here!!! + // must NOT be "<"!!! + return res_cont_1.cost <= res_cont_2.cost + && res_cont_1.time <= res_cont_2.time; + // this is not a contradiction to the documentation + // the documentation says: + // "A label $l_1$ dominates a label $l_2$ if and only if both are + // resident at the same vertex, and if, for each resource, the resource + // consumption of $l_1$ is less than or equal to the resource + // consumption of $l_2$, and if there is at least one resource where + // $l_1$ has a lower resource consumption than $l_2$." one can think of + // a new label with a resource consumption equal to that of an old label + // as being dominated by that old label, because the new one will have a + // higher number and is created at a later point in time, so one can + // implicitly use the number or the creation time as a resource for + // tie-breaking + } +}; +// end data structures for shortest path problem with time windows (spptw) + +// example graph structure and cost from +// http://www.boost.org/libs/graph/example/dijkstra-example.cpp +enum nodes +{ + A, + B, + C, + D, + E +}; +char name[] = "ABCDE"; + +int main() +{ + SPPRC_Example_Graph g; + + add_vertex(SPPRC_Example_Graph_Vert_Prop(A, 0, 0), g); + add_vertex(SPPRC_Example_Graph_Vert_Prop(B, 5, 20), g); + add_vertex(SPPRC_Example_Graph_Vert_Prop(C, 6, 10), g); + add_vertex(SPPRC_Example_Graph_Vert_Prop(D, 3, 12), g); + add_vertex(SPPRC_Example_Graph_Vert_Prop(E, 0, 100), g); + + add_edge(A, C, SPPRC_Example_Graph_Arc_Prop(0, 1, 5), g); + add_edge(B, B, SPPRC_Example_Graph_Arc_Prop(1, 2, 5), g); + add_edge(B, D, SPPRC_Example_Graph_Arc_Prop(2, 1, 2), g); + add_edge(B, E, SPPRC_Example_Graph_Arc_Prop(3, 2, 7), g); + add_edge(C, B, SPPRC_Example_Graph_Arc_Prop(4, 7, 3), g); + add_edge(C, D, SPPRC_Example_Graph_Arc_Prop(5, 3, 8), g); + add_edge(D, E, SPPRC_Example_Graph_Arc_Prop(6, 1, 3), g); + add_edge(E, A, SPPRC_Example_Graph_Arc_Prop(7, 1, 5), g); + add_edge(E, B, SPPRC_Example_Graph_Arc_Prop(8, 1, 4), g); + + // the unique shortest path from A to E in the dijkstra-example.cpp is + // A -> C -> D -> E + // its length is 5 + // the following code also yields this result + + // with the above time windows, this path is infeasible + // now, there are two shortest paths that are also feasible with respect to + // the vertex time windows: + // A -> C -> B -> D -> E and + // A -> C -> B -> E + // however, the latter has a longer total travel time and is therefore not + // pareto-optimal, i.e., it is dominated by the former path + // therefore, the code below returns only the former path + + // spp without resource constraints + graph_traits< SPPRC_Example_Graph >::vertex_descriptor s = A; + graph_traits< SPPRC_Example_Graph >::vertex_descriptor t = E; + + std::vector< + std::vector< graph_traits< SPPRC_Example_Graph >::edge_descriptor > > + opt_solutions; + std::vector< spp_no_rc_res_cont > pareto_opt_rcs_no_rc; + + r_c_shortest_paths(g, get(&SPPRC_Example_Graph_Vert_Prop::num, g), + get(&SPPRC_Example_Graph_Arc_Prop::num, g), s, t, opt_solutions, + pareto_opt_rcs_no_rc, spp_no_rc_res_cont(0), ref_no_res_cont(), + dominance_no_res_cont(), + std::allocator< r_c_shortest_paths_label< SPPRC_Example_Graph, + spp_no_rc_res_cont > >(), + default_r_c_shortest_paths_visitor()); + + std::cout << "SPP without resource constraints:" << std::endl; + std::cout << "Number of optimal solutions: "; + std::cout << static_cast< int >(opt_solutions.size()) << std::endl; + for (int i = 0; i < static_cast< int >(opt_solutions.size()); ++i) + { + std::cout << "The " << i << "th shortest path from A to E is: "; + std::cout << std::endl; + for (int j = static_cast< int >(opt_solutions[i].size()) - 1; j >= 0; + --j) + std::cout << name[source(opt_solutions[i][j], g)] << std::endl; + std::cout << "E" << std::endl; + std::cout << "Length: " << pareto_opt_rcs_no_rc[i].cost << std::endl; + } + std::cout << std::endl; + + // spptw + std::vector< + std::vector< graph_traits< SPPRC_Example_Graph >::edge_descriptor > > + opt_solutions_spptw; + std::vector< spp_spptw_res_cont > pareto_opt_rcs_spptw; + + r_c_shortest_paths(g, get(&SPPRC_Example_Graph_Vert_Prop::num, g), + get(&SPPRC_Example_Graph_Arc_Prop::num, g), s, t, opt_solutions_spptw, + pareto_opt_rcs_spptw, spp_spptw_res_cont(0, 0), ref_spptw(), + dominance_spptw(), + std::allocator< r_c_shortest_paths_label< SPPRC_Example_Graph, + spp_spptw_res_cont > >(), + default_r_c_shortest_paths_visitor()); + + std::cout << "SPP with time windows:" << std::endl; + std::cout << "Number of optimal solutions: "; + std::cout << static_cast< int >(opt_solutions_spptw.size()) << std::endl; + for (int i = 0; i < static_cast< int >(opt_solutions_spptw.size()); ++i) + { + std::cout << "The " << i << "th shortest path from A to E is: "; + std::cout << std::endl; + for (int j = static_cast< int >(opt_solutions_spptw[i].size()) - 1; + j >= 0; --j) + std::cout << name[source(opt_solutions_spptw[i][j], g)] + << std::endl; + std::cout << "E" << std::endl; + std::cout << "Length: " << pareto_opt_rcs_spptw[i].cost << std::endl; + std::cout << "Time: " << pareto_opt_rcs_spptw[i].time << std::endl; + } + + // utility function check_r_c_path example + std::cout << std::endl; + bool b_is_a_path_at_all = false; + bool b_feasible = false; + bool b_correctly_extended = false; + spp_spptw_res_cont actual_final_resource_levels(0, 0); + graph_traits< SPPRC_Example_Graph >::edge_descriptor ed_last_extended_arc; + check_r_c_path(g, opt_solutions_spptw[0], spp_spptw_res_cont(0, 0), true, + pareto_opt_rcs_spptw[0], actual_final_resource_levels, ref_spptw(), + b_is_a_path_at_all, b_feasible, b_correctly_extended, + ed_last_extended_arc); + if (!b_is_a_path_at_all) + std::cout << "Not a path." << std::endl; + if (!b_feasible) + std::cout << "Not a feasible path." << std::endl; + if (!b_correctly_extended) + std::cout << "Not correctly extended." << std::endl; + if (b_is_a_path_at_all && b_feasible && b_correctly_extended) + { + std::cout << "Actual final resource levels:" << std::endl; + std::cout << "Length: " << actual_final_resource_levels.cost + << std::endl; + std::cout << "Time: " << actual_final_resource_levels.time << std::endl; + std::cout << "OK." << std::endl; + } + + return 0; +} diff --git a/example/roget_components.cpp b/example/roget_components.cpp index d3c12c431..3ff47b745 100644 --- a/example/roget_components.cpp +++ b/example/roget_components.cpp @@ -25,7 +25,8 @@ int main(int argc, char* argv[]) unsigned long p = 0; long s = 0; char* filename = NULL; - int c, i; + int c; + unsigned int i; while (--argc) { diff --git a/example/scaled_closeness_centrality.cpp b/example/scaled_closeness_centrality.cpp index ae20c4264..a3ad245d3 100644 --- a/example/scaled_closeness_centrality.cpp +++ b/example/scaled_closeness_centrality.cpp @@ -75,7 +75,7 @@ using ClosenessProperty = boost::exterior_vertex_property< Graph, float >; using ClosenessContainer = ClosenessProperty::container_type; using ClosenessMap = ClosenessProperty::map_type; -int main(int argc, char* argv[]) +int main() { // Create the graph and a property map that provides access // to the actor names. diff --git a/example/simple_planarity_test.cpp b/example/simple_planarity_test.cpp index 3d345b820..a4b45d59b 100644 --- a/example/simple_planarity_test.cpp +++ b/example/simple_planarity_test.cpp @@ -9,7 +9,7 @@ #include #include -int main(int argc, char** argv) +int main() { // This program illustrates a simple use of boyer_myrvold_planar_embedding diff --git a/example/stoer_wagner.cpp b/example/stoer_wagner.cpp index 567628351..be1320626 100644 --- a/example/stoer_wagner.cpp +++ b/example/stoer_wagner.cpp @@ -56,8 +56,8 @@ int main() // run the Stoer-Wagner algorithm to obtain the min-cut weight. `parities` // is also filled in. - int w = boost::stoer_wagner_min_cut( - g, get(boost::edge_weight, g), boost::parity_map(parities)); + int w = boost::graph::stoer_wagner_min_cut( + g, get(boost::edge_weight, g), parities); cout << "The min-cut weight of G is " << w << ".\n" << endl; assert(w == 7); diff --git a/example/straight_line_drawing.cpp b/example/straight_line_drawing.cpp index a425738a9..7c80373de 100644 --- a/example/straight_line_drawing.cpp +++ b/example/straight_line_drawing.cpp @@ -26,7 +26,7 @@ struct coord_t std::size_t y; }; -int main(int argc, char** argv) +int main() { using graph = adjacency_list< vecS, vecS, undirectedS, property< vertex_index_t, int > >; diff --git a/example/tiernan_girth_circumference.cpp b/example/tiernan_girth_circumference.cpp index 81ab70ab8..df8e7cdb6 100644 --- a/example/tiernan_girth_circumference.cpp +++ b/example/tiernan_girth_circumference.cpp @@ -20,7 +20,7 @@ using Graph = directed_graph<>; using Vertex = graph_traits< Graph >::vertex_descriptor; using Edge = graph_traits< Graph >::edge_descriptor; -int main(int argc, char* argv[]) +int main() { // Create the graph and read it from standard input. Graph g; diff --git a/example/tiernan_print_cycles.cpp b/example/tiernan_print_cycles.cpp index a0f110236..87e29b607 100644 --- a/example/tiernan_print_cycles.cpp +++ b/example/tiernan_print_cycles.cpp @@ -46,7 +46,7 @@ using Graph = directed_graph<>; using Vertex = graph_traits< Graph >::vertex_descriptor; using Edge = graph_traits< Graph >::edge_descriptor; -int main(int argc, char* argv[]) +int main() { // Create the graph and read it from standard input. Graph g; diff --git a/example/topo-sort-with-sgb.cpp b/example/topo-sort-with-sgb.cpp index a060792a6..cb2aa21b9 100644 --- a/example/topo-sort-with-sgb.cpp +++ b/example/topo-sort-with-sgb.cpp @@ -21,7 +21,6 @@ int main() = { "pick up kids from school", "buy groceries (and snacks)", "get cash at ATM", "drop off kids at soccer practice", "cook dinner", "pick up kids from soccer", "eat dinner" }; - const int n_tasks = sizeof(tasks) / sizeof(char*); gb_new_arc(sgb_g->vertices + 0, sgb_g->vertices + 3, 0); gb_new_arc(sgb_g->vertices + 1, sgb_g->vertices + 3, 0); diff --git a/example/two_graphs_common_spanning_trees.cpp b/example/two_graphs_common_spanning_trees.cpp index ebe2f05b9..8f5123302 100644 --- a/example/two_graphs_common_spanning_trees.cpp +++ b/example/two_graphs_common_spanning_trees.cpp @@ -32,7 +32,7 @@ using vertex_iterator = boost::graph_traits< Graph >::vertex_iterator; using edge_iterator = boost::graph_traits< Graph >::edge_iterator; -int main(int argc, char** argv) +int main() { Graph iG, vG; vector< edge_descriptor > iG_o = { boost::add_edge(0, 1, iG).first, diff --git a/example/weighted_matching_example.cpp b/example/weighted_matching_example.cpp index b716e6ef6..e6a2023d5 100644 --- a/example/weighted_matching_example.cpp +++ b/example/weighted_matching_example.cpp @@ -20,7 +20,7 @@ using EdgeProperty using my_graph = adjacency_list< vecS, vecS, undirectedS, no_property, EdgeProperty >; -int main(int argc, const char* argv[]) +int main() { graph_traits< my_graph >::vertex_iterator vi, vi_end; const int n_vertices = 18; diff --git a/include/boost/graph/adj_list_serialize.hpp b/include/boost/graph/adj_list_serialize.hpp index c9abfb32c..c1bdeebf9 100644 --- a/include/boost/graph/adj_list_serialize.hpp +++ b/include/boost/graph/adj_list_serialize.hpp @@ -17,9 +17,8 @@ #include #include -#include -#include -#include +#include +#include namespace boost { @@ -29,13 +28,16 @@ namespace serialization // Turn off tracking for adjacency_list. It's not polymorphic, and we // need to do this to enable saving of non-const adjacency lists. + // Specializing tracking_level_impl (not tracking_level) avoids including + // . boost::integral_constant carries the + // integral_c_tag the archive expects. + template < class T > struct tracking_level_impl; template < class OEL, class VL, class D, class VP, class EP, class GP, class EL > - struct tracking_level< boost::adjacency_list< OEL, VL, D, VP, EP, GP, EL > > + struct tracking_level_impl< + const boost::adjacency_list< OEL, VL, D, VP, EP, GP, EL > > + : boost::integral_constant< int, 0 /* track_never */ > { - typedef mpl::integral_c_tag tag; - typedef mpl::int_< track_never > type; - BOOST_STATIC_CONSTANT(int, value = tracking_level::type::value); }; template < class Archive, class OEL, class VL, class D, class VP, class EP, @@ -50,8 +52,8 @@ namespace serialization const auto V = num_vertices(graph); const auto E = num_edges(graph); - ar << BOOST_SERIALIZATION_NVP(V); - ar << BOOST_SERIALIZATION_NVP(E); + ar << BOOST_NVP(V); + ar << BOOST_NVP(E); // assign indices to vertices std::unordered_map< Vertex, Vertex > indices(V); @@ -59,20 +61,20 @@ namespace serialization BGL_FORALL_VERTICES_T(v, graph, Graph) { indices[v] = num++; - ar << serialization::make_nvp( + ar << boost::make_nvp( "vertex_property", get(vertex_all_t(), graph, v)); } // write edges BGL_FORALL_EDGES_T(e, graph, Graph) { - ar << serialization::make_nvp("u", indices[source(e, graph)]); - ar << serialization::make_nvp("v", indices[target(e, graph)]); - ar << serialization::make_nvp( + ar << boost::make_nvp("u", indices[source(e, graph)]); + ar << boost::make_nvp("v", indices[target(e, graph)]); + ar << boost::make_nvp( "edge_property", get(edge_all_t(), graph, e)); } - ar << serialization::make_nvp( + ar << boost::make_nvp( "graph_property", get_property(graph, graph_all_t())); } @@ -89,10 +91,10 @@ namespace serialization using VertexSizeType = typename graph_traits< Graph >::vertices_size_type; VertexSizeType V; - ar >> BOOST_SERIALIZATION_NVP(V); + ar >> BOOST_NVP(V); VertexSizeType E; - ar >> BOOST_SERIALIZATION_NVP(E); + ar >> BOOST_NVP(E); std::vector< Vertex > verts(V); size_t i = 0; @@ -100,7 +102,7 @@ namespace serialization { const auto v = add_vertex(graph); verts[i++] = v; - ar >> serialization::make_nvp( + ar >> boost::make_nvp( "vertex_property", get(vertex_all_t(), graph, v)); } @@ -108,16 +110,16 @@ namespace serialization { Vertex u; Vertex v; - ar >> BOOST_SERIALIZATION_NVP(u); - ar >> BOOST_SERIALIZATION_NVP(v); + ar >> BOOST_NVP(u); + ar >> BOOST_NVP(v); Edge e; bool inserted; boost::tie(e, inserted) = add_edge(verts[u], verts[v], graph); - ar >> serialization::make_nvp( + ar >> boost::make_nvp( "edge_property", get(edge_all_t(), graph, e)); } - ar >> serialization::make_nvp( + ar >> boost::make_nvp( "graph_property", get_property(graph, graph_all_t())); } @@ -127,7 +129,7 @@ namespace serialization boost::adjacency_list< OEL, VL, D, VP, EP, GP, EL >& graph, const unsigned int file_version) { - boost::serialization::split_free(ar, graph, file_version); + boost::core::split_free(ar, graph, file_version); } } // serialization diff --git a/include/boost/graph/adjacency_list.hpp b/include/boost/graph/adjacency_list.hpp index 113143a7f..7d78288db 100644 --- a/include/boost/graph/adjacency_list.hpp +++ b/include/boost/graph/adjacency_list.hpp @@ -19,18 +19,15 @@ #include -#include +#include #include #include #include #include -#include -#include -#include -#include #include #include +#include #include #include #include @@ -187,7 +184,7 @@ namespace detail { value = false }; - typedef mpl::false_ type; + typedef std::false_type type; }; template <> struct is_random_access< vecS > { @@ -195,12 +192,12 @@ namespace detail { value = true }; - typedef mpl::true_ type; + typedef std::true_type type; }; } // namespace detail -template < typename Selector > struct is_distributed_selector : mpl::false_ +template < typename Selector > struct is_distributed_selector : std::false_type { }; @@ -220,8 +217,8 @@ struct adjacency_list_traits typedef typename DirectedS::is_bidir_t is_bidir; typedef typename DirectedS::is_directed_t is_directed; - typedef typename mpl::if_< is_bidir, bidirectional_tag, - typename mpl::if_< is_directed, directed_tag, + typedef typename std::conditional< is_bidir::value, bidirectional_tag, + typename std::conditional< is_directed::value, directed_tag, undirected_tag >::type >::type directed_category; typedef typename parallel_edge_traits< OutEdgeListS >::type @@ -229,7 +226,7 @@ struct adjacency_list_traits typedef std::size_t vertices_size_type; typedef void* vertex_ptr; - typedef typename mpl::if_< is_rand_access, vertices_size_type, + typedef typename std::conditional< is_rand_access::value, vertices_size_type, vertex_ptr >::type vertex_descriptor; typedef detail::edge_desc_impl< directed_category, vertex_descriptor > edge_descriptor; @@ -242,11 +239,12 @@ struct adjacency_list_traits typedef typename container_gen< EdgeListS, dummy >::type EdgeContainer; typedef typename DirectedS::is_bidir_t BidirectionalT; typedef typename DirectedS::is_directed_t DirectedT; - typedef typename mpl::and_< DirectedT, - typename mpl::not_< BidirectionalT >::type >::type on_edge_storage; + typedef std::integral_constant< bool, + DirectedT::value && !BidirectionalT::value > + on_edge_storage; public: - typedef typename mpl::if_< on_edge_storage, std::size_t, + typedef typename std::conditional< on_edge_storage::value, std::size_t, typename EdgeContainer::size_type >::type edges_size_type; }; @@ -407,7 +405,7 @@ class adjacency_list #endif // protected: (would be protected if friends were more portable) - typedef scoped_ptr< graph_property_type > property_ptr; + using property_ptr = std::unique_ptr< graph_property_type >; property_ptr m_property; }; diff --git a/include/boost/graph/adjacency_matrix.hpp b/include/boost/graph/adjacency_matrix.hpp index 83c22de50..cc929139d 100644 --- a/include/boost/graph/adjacency_matrix.hpp +++ b/include/boost/graph/adjacency_matrix.hpp @@ -20,8 +20,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -413,7 +412,7 @@ template < typename Directed = directedS > class adjacency_matrix_traits // in_degree, etc.). BOOST_STATIC_ASSERT(!(is_same< Directed, bidirectionalS >::value)); - typedef typename mpl::if_< is_directed, bidirectional_tag, + typedef typename std::conditional< is_directed::value, bidirectional_tag, undirected_tag >::type directed_category; typedef disallow_parallel_edge_tag edge_parallel_category; @@ -470,7 +469,7 @@ class adjacency_matrix public: // should be private typedef - typename mpl::if_< typename has_property< edge_property_type >::type, + typename std::conditional< has_property< edge_property_type >::type::value, std::pair< bool, edge_property_type >, char >::type StoredEdge; #if defined(BOOST_NO_STD_ALLOCATOR) typedef std::vector< StoredEdge > Matrix; @@ -510,7 +509,7 @@ class adjacency_matrix MatrixIter, size_type, edge_descriptor > UnDirOutEdgeIter; - typedef typename mpl::if_< typename Directed::is_directed_t, DirOutEdgeIter, + typedef typename std::conditional< Directed::is_directed_t::value, DirOutEdgeIter, UnDirOutEdgeIter >::type unfiltered_out_edge_iter; typedef detail::dir_adj_matrix_in_edge_iter< vertex_descriptor, MatrixIter, @@ -521,7 +520,7 @@ class adjacency_matrix MatrixIter, size_type, edge_descriptor > UnDirInEdgeIter; - typedef typename mpl::if_< typename Directed::is_directed_t, DirInEdgeIter, + typedef typename std::conditional< Directed::is_directed_t::value, DirInEdgeIter, UnDirInEdgeIter >::type unfiltered_in_edge_iter; typedef detail::adj_matrix_edge_iter< Directed, MatrixIter, size_type, @@ -1103,7 +1102,7 @@ struct adj_mat_pm_helper< D, VP, EP, GP, A, Tag, edge_property_tag > { Tag tag; lookup_property_from_edge(Tag tag) : tag(tag) {} - typedef typename boost::mpl::if_< IsConst, const EP, EP >::type + typedef typename std::conditional< IsConst::value, const EP, EP >::type ep_type_nonref; typedef ep_type_nonref& ep_type; typedef typename lookup_one_property< ep_type_nonref, Tag >::type& @@ -1116,20 +1115,20 @@ struct adj_mat_pm_helper< D, VP, EP, GP, A, Tag, edge_property_tag > }; typedef function_property_map< - lookup_property_from_edge< boost::mpl::false_ >, + lookup_property_from_edge< std::false_type >, typename graph_traits< adjacency_matrix< D, VP, EP, GP, A > >::edge_descriptor > type; typedef function_property_map< - lookup_property_from_edge< boost::mpl::true_ >, + lookup_property_from_edge< std::true_type >, typename graph_traits< adjacency_matrix< D, VP, EP, GP, A > >::edge_descriptor > const_type; typedef edge_descriptor arg_type; typedef - typename lookup_property_from_edge< boost::mpl::false_ >::result_type + typename lookup_property_from_edge< std::false_type >::result_type single_nonconst_type; - typedef typename lookup_property_from_edge< boost::mpl::true_ >::result_type + typedef typename lookup_property_from_edge< std::true_type >::result_type single_const_type; static type get_nonconst(adjacency_matrix< D, VP, EP, GP, A >& g, Tag tag) diff --git a/include/boost/graph/bc_clustering.hpp b/include/boost/graph/bc_clustering.hpp index dd26bdf39..d005f9e1c 100644 --- a/include/boost/graph/bc_clustering.hpp +++ b/include/boost/graph/bc_clustering.hpp @@ -9,7 +9,6 @@ #ifndef BOOST_GRAPH_BETWEENNESS_CENTRALITY_CLUSTERING_HPP #define BOOST_GRAPH_BETWEENNESS_CENTRALITY_CLUSTERING_HPP -#include #include #include #include @@ -132,8 +131,11 @@ void betweenness_centrality_clustering(MutableGraph& g, Done done, edge_centrality_map(edge_centrality) .vertex_index_map(vertex_index)); std::pair< edge_iterator, edge_iterator > edges_iters = edges(g); - edge_descriptor e - = *boost::first_max_element(edges_iters.first, edges_iters.second, cmp); + auto max_edge_it = edges_iters.first; + for (auto edge_it = edges_iters.first; edge_it != edges_iters.second; ++edge_it) + if (cmp(*max_edge_it, *edge_it)) + max_edge_it = edge_it; + edge_descriptor e = *max_edge_it; is_done = done(get(edge_centrality, e), e, g); if (!is_done) remove_edge(e, g); diff --git a/include/boost/graph/betweenness_centrality.hpp b/include/boost/graph/betweenness_centrality.hpp index b6148e46a..b8fd65e2b 100644 --- a/include/boost/graph/betweenness_centrality.hpp +++ b/include/boost/graph/betweenness_centrality.hpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -451,7 +451,7 @@ namespace detail degree_size_type; typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor; - typedef typename mpl::if_c< + typedef typename std::conditional< (is_same< CentralityMap, dummy_property_map >::value), EdgeCentralityMap, CentralityMap >::type a_centrality_map; typedef typename property_traits< a_centrality_map >::value_type @@ -483,7 +483,7 @@ namespace detail degree_size_type; typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor; - typedef typename mpl::if_c< + typedef typename std::conditional< (is_same< CentralityMap, dummy_property_map >::value), EdgeCentralityMap, CentralityMap >::type a_centrality_map; typedef typename property_traits< a_centrality_map >::value_type diff --git a/include/boost/graph/boyer_myrvold_planar_test.hpp b/include/boost/graph/boyer_myrvold_planar_test.hpp index 34a476b50..965e94318 100644 --- a/include/boost/graph/boyer_myrvold_planar_test.hpp +++ b/include/boost/graph/boyer_myrvold_planar_test.hpp @@ -10,7 +10,11 @@ #define __BOYER_MYRVOLD_PLANAR_TEST_HPP__ #include -#include +#include +#include +#include +#include +#include #include #include diff --git a/include/boost/graph/breadth_first_search.hpp b/include/boost/graph/breadth_first_search.hpp index 0993d55d1..8dae81825 100644 --- a/include/boost/graph/breadth_first_search.hpp +++ b/include/boost/graph/breadth_first_search.hpp @@ -24,11 +24,8 @@ #include #include #include -#include #include -#include BOOST_GRAPH_MPI_INCLUDE() - namespace boost { @@ -224,16 +221,6 @@ template < class Visitors = null_visitor > class bfs_visitor return graph::bfs_visitor_event_not_overridden(); } - BOOST_GRAPH_EVENT_STUB(on_initialize_vertex, bfs) - BOOST_GRAPH_EVENT_STUB(on_discover_vertex, bfs) - BOOST_GRAPH_EVENT_STUB(on_examine_vertex, bfs) - BOOST_GRAPH_EVENT_STUB(on_examine_edge, bfs) - BOOST_GRAPH_EVENT_STUB(on_tree_edge, bfs) - BOOST_GRAPH_EVENT_STUB(on_non_tree_edge, bfs) - BOOST_GRAPH_EVENT_STUB(on_gray_target, bfs) - BOOST_GRAPH_EVENT_STUB(on_black_target, bfs) - BOOST_GRAPH_EVENT_STUB(on_finish_vertex, bfs) - protected: Visitors m_vis; }; @@ -265,15 +252,6 @@ namespace detail vis, color); } -#ifdef BOOST_GRAPH_USE_MPI - template < class DistributedGraph, class ColorMap, class BFSVisitor, - class P, class T, class R > - void bfs_helper(DistributedGraph& g, - typename graph_traits< DistributedGraph >::vertex_descriptor s, - ColorMap color, BFSVisitor vis, - const bgl_named_params< P, T, R >& params, boost::mpl::true_); -#endif // BOOST_GRAPH_USE_MPI - //------------------------------------------------------------------------- // Choose between default color and color parameters. Using // function dispatching so that we don't require vertex index if @@ -403,6 +381,4 @@ namespace graph } // namespace boost -#include BOOST_GRAPH_MPI_INCLUDE() - #endif // BOOST_GRAPH_BREADTH_FIRST_SEARCH_HPP diff --git a/include/boost/graph/buffer_concepts.hpp b/include/boost/graph/buffer_concepts.hpp index 1eb48abcf..11bfc39c8 100644 --- a/include/boost/graph/buffer_concepts.hpp +++ b/include/boost/graph/buffer_concepts.hpp @@ -7,7 +7,6 @@ #define BOOST_GRAPH_BUFFER_CONCEPTS_HPP 1 #include #include -#include #include #include #include diff --git a/include/boost/graph/circle_layout.hpp b/include/boost/graph/circle_layout.hpp index f99cc56df..bee533cac 100644 --- a/include/boost/graph/circle_layout.hpp +++ b/include/boost/graph/circle_layout.hpp @@ -9,7 +9,6 @@ #ifndef BOOST_GRAPH_CIRCLE_LAYOUT_HPP #define BOOST_GRAPH_CIRCLE_LAYOUT_HPP #include -#include #include #include #include @@ -34,7 +33,7 @@ void circle_graph_layout( { BOOST_STATIC_ASSERT( property_traits< PositionMap >::value_type::dimensions >= 2); - const double pi = boost::math::constants::pi< double >(); + const double pi = 3.14159265358979323846; #ifndef BOOST_NO_STDC_NAMESPACE using std::cos; diff --git a/include/boost/graph/compressed_sparse_row_graph.hpp b/include/boost/graph/compressed_sparse_row_graph.hpp index e777d8c4b..4411ca79d 100644 --- a/include/boost/graph/compressed_sparse_row_graph.hpp +++ b/include/boost/graph/compressed_sparse_row_graph.hpp @@ -17,8 +17,8 @@ #include #include #include -#include #include +#include #if 0 #include // For some debugging code below #endif @@ -36,16 +36,13 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include -#include namespace boost { @@ -170,9 +167,9 @@ namespace detail T saved_value; const T& dereference() const { return saved_value; } bool equal(default_construct_iterator /*i*/) const { return true; } - void increment() {} - void decrement() {} - void advance(typename base_type::difference_type) {} + void increment() { } + void decrement() { } + void advance(typename base_type::difference_type) { } typename base_type::difference_type distance_to( default_construct_iterator) const { @@ -183,7 +180,7 @@ namespace detail template < typename Less > struct compare_first { Less less; - compare_first(Less less = Less()) : less(less) {} + compare_first(Less less = Less()) : less(less) { } template < typename Tuple > bool operator()(const Tuple& a, const Tuple& b) const { @@ -224,11 +221,14 @@ class compressed_sparse_row_graph< directedS, VertexProperty, EdgeProperty, VertexProperty, Vertex, typed_identity_property_map< Vertex > > inherited_vertex_properties; - // Some tests to prevent use of "void" is a property type (as was done in + // Some tests to prevent use of "void" as a property type (as was done in // some test cases): - BOOST_STATIC_ASSERT((!is_same< VertexProperty, void >::value)); - BOOST_STATIC_ASSERT((!is_same< EdgeProperty, void >::value)); - BOOST_STATIC_ASSERT((!is_same< GraphProperty, void >::value)); + static_assert(!std::is_void< VertexProperty>::value, + "Vertex property type cannot be of type void: use boost::no_property instead."); + static_assert(!std::is_void< EdgeProperty >::value, + "Edge property type cannot be of type void: use boost::no_property instead."); + static_assert(!std::is_void< GraphProperty >::value, + "Graph property type cannot be of type void: use boost::no_property instead."); public: // For Property Graph @@ -245,7 +245,7 @@ class compressed_sparse_row_graph< directedS, VertexProperty, EdgeProperty, * create directed and bidirectional graphs. In the future, * undirected CSR graphs will also be supported. */ - // BOOST_STATIC_ASSERT((is_same::value)); + // static_assert(std::is_same::value, "Direction can only be directed, i.e. use directedS."); // Concept requirements: // For Graph @@ -299,7 +299,7 @@ class compressed_sparse_row_graph< directedS, VertexProperty, EdgeProperty, // Constructors // Default constructor: an empty graph. - compressed_sparse_row_graph() : m_property() {} + compressed_sparse_row_graph() : m_property() { } // With numverts vertices compressed_sparse_row_graph(vertices_size_type numverts) @@ -898,7 +898,7 @@ class compressed_sparse_row_graph< bidirectionalS, VertexProperty, EdgeProperty, // Constructors // Default constructor: an empty graph. - compressed_sparse_row_graph() : m_property() {} + compressed_sparse_row_graph() : m_property() { } // With numverts vertices compressed_sparse_row_graph(vertices_size_type numverts) diff --git a/include/boost/graph/connected_components.hpp b/include/boost/graph/connected_components.hpp index 75e76a073..0187b17c4 100644 --- a/include/boost/graph/connected_components.hpp +++ b/include/boost/graph/connected_components.hpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -109,6 +108,4 @@ connected_components(const Graph& g, } // namespace boost -#include BOOST_GRAPH_MPI_INCLUDE() - #endif // BOOST_GRAPH_CONNECTED_COMPONENTS_HPP diff --git a/include/boost/graph/depth_first_search.hpp b/include/boost/graph/depth_first_search.hpp index 17d25e89c..985ab5612 100644 --- a/include/boost/graph/depth_first_search.hpp +++ b/include/boost/graph/depth_first_search.hpp @@ -19,13 +19,11 @@ #include #include #include -#include #include -#include #include -#include #include -#include +#include +#include #include #include @@ -69,7 +67,19 @@ namespace detail } }; - BOOST_TTI_HAS_MEMBER_FUNCTION(finish_edge) + // has_finish_edge::value is true when vis.finish_edge(e, g) is + // a valid call for e of type E and g of type const G&. + template < typename Vis, typename E, typename G, typename = void > + struct has_finish_edge : std::false_type + { + }; + template < typename Vis, typename E, typename G > + struct has_finish_edge< Vis, E, G, + boost::void_t< decltype(std::declval< Vis& >().finish_edge( + std::declval< E& >(), std::declval< const G& >())) > > + : std::true_type + { + }; template < bool IsCallable > struct do_call_finish_edge { @@ -90,18 +100,9 @@ namespace detail template < typename E, typename G, typename Vis > void call_finish_edge(Vis& vis, E e, const G& g) - { // Only call if method exists -#if ((defined(__GNUC__) && (__GNUC__ > 4) \ - || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9))) \ - || defined(__clang__) \ - || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1200))) - do_call_finish_edge< has_member_function_finish_edge< Vis, void, - boost::mpl::vector< E, const G& > >::value >::call_finish_edge(vis, - e, g); -#else - do_call_finish_edge< has_member_function_finish_edge< Vis, - void >::value >::call_finish_edge(vis, e, g); -#endif + { // Only call if the visitor has a callable finish_edge(e, g) + do_call_finish_edge< has_finish_edge< Vis, E, G >::value >:: + call_finish_edge(vis, e, g); } // Define BOOST_RECURSIVE_DFS to use older, recursive version. @@ -275,7 +276,7 @@ void depth_first_search(const VertexListGraph& g, DFSVisitor vis, typename graph_traits< VertexListGraph >::vertex_iterator ui, ui_end; for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { - Vertex u = implicit_cast< Vertex >(*ui); + Vertex u = *ui; put(color, u, Color::white()); vis.initialize_vertex(u, g); } @@ -289,7 +290,7 @@ void depth_first_search(const VertexListGraph& g, DFSVisitor vis, for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { - Vertex u = implicit_cast< Vertex >(*ui); + Vertex u = *ui; ColorValue u_color = get(color, u); if (u_color == Color::white()) { @@ -362,16 +363,6 @@ template < class Visitors = null_visitor > class dfs_visitor invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex()); } - BOOST_GRAPH_EVENT_STUB(on_initialize_vertex, dfs) - BOOST_GRAPH_EVENT_STUB(on_start_vertex, dfs) - BOOST_GRAPH_EVENT_STUB(on_discover_vertex, dfs) - BOOST_GRAPH_EVENT_STUB(on_examine_edge, dfs) - BOOST_GRAPH_EVENT_STUB(on_tree_edge, dfs) - BOOST_GRAPH_EVENT_STUB(on_back_edge, dfs) - BOOST_GRAPH_EVENT_STUB(on_forward_or_cross_edge, dfs) - BOOST_GRAPH_EVENT_STUB(on_finish_edge, dfs) - BOOST_GRAPH_EVENT_STUB(on_finish_vertex, dfs) - protected: Visitors m_vis; }; @@ -428,6 +419,4 @@ void depth_first_visit(const IncidenceGraph& g, } } // namespace boost -#include BOOST_GRAPH_MPI_INCLUDE() - #endif diff --git a/include/boost/graph/detail/adjacency_list.hpp b/include/boost/graph/detail/adjacency_list.hpp index 9a0c29bd7..a55daa120 100644 --- a/include/boost/graph/detail/adjacency_list.hpp +++ b/include/boost/graph/detail/adjacency_list.hpp @@ -27,9 +27,7 @@ #include -#include -#include -#include +#include #include #include #include @@ -2343,8 +2341,8 @@ namespace detail typedef typename container_gen< VertexListS, vertex_ptr >::type SeqVertexList; typedef boost::integer_range< vertex_descriptor > RandVertexList; - typedef typename mpl::if_< is_rand_access, RandVertexList, - SeqVertexList >::type VertexList; + typedef typename std::conditional< is_rand_access::value, + RandVertexList, SeqVertexList >::type VertexList; typedef typename VertexList::iterator vertex_iterator; @@ -2354,21 +2352,22 @@ namespace detail list_edge< vertex_descriptor, EdgeProperty > >::type EdgeContainer; - typedef typename mpl::and_< DirectedT, - typename mpl::not_< BidirectionalT >::type >::type + typedef std::integral_constant< bool, + DirectedT::value && !BidirectionalT::value > on_edge_storage; - typedef typename mpl::if_< on_edge_storage, std::size_t, - typename EdgeContainer::size_type >::type edges_size_type; + typedef typename std::conditional< on_edge_storage::value, + std::size_t, typename EdgeContainer::size_type >::type + edges_size_type; typedef typename EdgeContainer::iterator EdgeIter; typedef typename detail::is_random_access< EdgeListS >::type is_edge_ra; - typedef typename mpl::if_< on_edge_storage, + typedef typename std::conditional< on_edge_storage::value, stored_edge_property< vertex_descriptor, EdgeProperty >, - typename mpl::if_< is_edge_ra, + typename std::conditional< is_edge_ra::value, stored_ra_edge_iter< vertex_descriptor, EdgeContainer, EdgeProperty >, stored_edge_iter< vertex_descriptor, EdgeIter, @@ -2421,8 +2420,8 @@ namespace detail graph_type > DirectedEdgeIter; - typedef typename mpl::if_< on_edge_storage, DirectedEdgeIter, - UndirectedEdgeIter >::type edge_iterator; + typedef typename std::conditional< on_edge_storage::value, + DirectedEdgeIter, UndirectedEdgeIter >::type edge_iterator; // stored_vertex and StoredVertexList typedef typename container_gen< VertexListS, vertex_ptr >::type @@ -2464,11 +2463,12 @@ namespace detail InEdgeList m_in_edges; VertexProperty m_property; }; - typedef typename mpl::if_< is_rand_access, - typename mpl::if_< BidirectionalT, bidir_rand_stored_vertex, - rand_stored_vertex >::type, - typename mpl::if_< BidirectionalT, bidir_seq_stored_vertex, - seq_stored_vertex >::type >::type StoredVertex; + typedef typename std::conditional< is_rand_access::value, + typename std::conditional< BidirectionalT::value, + bidir_rand_stored_vertex, rand_stored_vertex >::type, + typename std::conditional< BidirectionalT::value, + bidir_seq_stored_vertex, seq_stored_vertex >::type >::type + StoredVertex; struct stored_vertex : public StoredVertex { stored_vertex() {} @@ -2477,17 +2477,19 @@ namespace detail typedef typename container_gen< VertexListS, stored_vertex >::type RandStoredVertexList; - typedef typename mpl::if_< is_rand_access, RandStoredVertexList, - SeqStoredVertexList >::type StoredVertexList; + typedef typename std::conditional< is_rand_access::value, + RandStoredVertexList, SeqStoredVertexList >::type + StoredVertexList; }; // end of config - typedef typename mpl::if_< BidirectionalT, + typedef typename std::conditional< BidirectionalT::value, bidirectional_graph_helper_with_property< config >, - typename mpl::if_< DirectedT, directed_graph_helper< config >, + typename std::conditional< DirectedT::value, + directed_graph_helper< config >, undirected_graph_helper< config > >::type >::type DirectedHelper; - typedef typename mpl::if_< is_rand_access, + typedef typename std::conditional< is_rand_access::value, vec_adj_list_impl< Graph, config, DirectedHelper >, adj_list_impl< Graph, config, DirectedHelper > >::type type; }; @@ -2687,7 +2689,7 @@ namespace detail { template < class Tag, class Graph, class Property > struct adj_list_choose_vertex_pa - : boost::mpl::if_< boost::is_same< Tag, vertex_all_t >, + : std::conditional< boost::is_same< Tag, vertex_all_t >::value, adj_list_all_vertex_pa, adj_list_any_vertex_pa >::type :: template bind_< Tag, Graph, Property > { diff --git a/include/boost/graph/detail/compressed_sparse_row_struct.hpp b/include/boost/graph/detail/compressed_sparse_row_struct.hpp index a6be13e51..b285d87ec 100644 --- a/include/boost/graph/detail/compressed_sparse_row_struct.hpp +++ b/include/boost/graph/detail/compressed_sparse_row_struct.hpp @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/include/boost/graph/detail/d_ary_heap.hpp b/include/boost/graph/detail/d_ary_heap.hpp index 7c423dcac..02763b330 100644 --- a/include/boost/graph/detail/d_ary_heap.hpp +++ b/include/boost/graph/detail/d_ary_heap.hpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include // WARNING: it is not safe to copy a d_ary_heap_indirect and then modify one of @@ -45,23 +45,25 @@ namespace detail { template < typename Value > class fixed_max_size_vector { - boost::shared_array< Value > m_data; + // todo : C++17: replace with std::shared_ptr + std::shared_ptr< Value > m_data; std::size_t m_size; public: typedef std::size_t size_type; fixed_max_size_vector(std::size_t max_size) - : m_data(new Value[max_size]), m_size(0) + : m_data(new Value[max_size], std::default_delete< Value[] >()) + , m_size(0) { } std::size_t size() const { return m_size; } bool empty() const { return m_size == 0; } - Value& operator[](std::size_t i) { return m_data[i]; } - const Value& operator[](std::size_t i) const { return m_data[i]; } - void push_back(Value v) { m_data[m_size++] = v; } + Value& operator[](std::size_t i) { return m_data.get()[i]; } + const Value& operator[](std::size_t i) const { return m_data.get()[i]; } + void push_back(Value v) { m_data.get()[m_size++] = v; } void pop_back() { --m_size; } - Value& back() { return m_data[m_size - 1]; } - const Value& back() const { return m_data[m_size - 1]; } + Value& back() { return m_data.get()[m_size - 1]; } + const Value& back() const { return m_data.get()[m_size - 1]; } }; } diff --git a/include/boost/graph/detail/empty_header.hpp b/include/boost/graph/detail/empty_header.hpp deleted file mode 100644 index fde367255..000000000 --- a/include/boost/graph/detail/empty_header.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef BOOST_GRAPH_DETAIL_EMPTY_HEADER_HPP_INCLUDED -#define BOOST_GRAPH_DETAIL_EMPTY_HEADER_HPP_INCLUDED - -// Copyright 2018 Peter Dimov -// -// Use, modification and distribution are subject to the -// Boost Software License, Version 1.0 (See accompanying file -// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) - -#endif // #ifndef BOOST_GRAPH_DETAIL_EMPTY_HEADER_HPP_INCLUDED diff --git a/include/boost/graph/detail/index.hpp b/include/boost/graph/detail/index.hpp index 7ffc843fc..ba2a46ffb 100644 --- a/include/boost/graph/detail/index.hpp +++ b/include/boost/graph/detail/index.hpp @@ -9,6 +9,7 @@ #include #include +#include // The structures in this module are responsible for selecting and defining // types for accessing a builting index map. Note that the selection of these @@ -67,8 +68,8 @@ namespace detail // VertexEdgeGraph - whichever type Key is selecting. template < typename Graph, typename Key > struct choose_indexer { - typedef typename mpl::if_< - is_same< Key, typename graph_traits< Graph >::vertex_descriptor >, + typedef typename std::conditional< + is_same< Key, typename graph_traits< Graph >::vertex_descriptor >::value, vertex_indexer< Graph >, edge_indexer< Graph > >::type indexer_type; typedef typename indexer_type::index_type index_type; }; diff --git a/include/boost/graph/detail/indexed_properties.hpp b/include/boost/graph/detail/indexed_properties.hpp index b86cf31a7..f36f5365c 100644 --- a/include/boost/graph/detail/indexed_properties.hpp +++ b/include/boost/graph/detail/indexed_properties.hpp @@ -24,7 +24,6 @@ #include #include #include -#include namespace boost { diff --git a/include/boost/graph/detail/is_distributed_selector.hpp b/include/boost/graph/detail/is_distributed_selector.hpp index 0a25a6852..aad7b0108 100644 --- a/include/boost/graph/detail/is_distributed_selector.hpp +++ b/include/boost/graph/detail/is_distributed_selector.hpp @@ -15,13 +15,13 @@ #ifndef BOOST_GRAPH_DETAIL_IS_DISTRIBUTED_SELECTOR_HPP #define BOOST_GRAPH_DETAIL_IS_DISTRIBUTED_SELECTOR_HPP -#include +#include namespace boost { namespace detail { - template < typename > struct is_distributed_selector : boost::mpl::false_ + template < typename > struct is_distributed_selector : std::false_type { }; } diff --git a/include/boost/graph/detail/labeled_graph_traits.hpp b/include/boost/graph/detail/labeled_graph_traits.hpp index b6600dbb0..1575ea046 100644 --- a/include/boost/graph/detail/labeled_graph_traits.hpp +++ b/include/boost/graph/detail/labeled_graph_traits.hpp @@ -9,6 +9,8 @@ #include +#include + namespace boost { @@ -84,7 +86,7 @@ struct labeled_add_only_property_graph_tag template < typename Graph > struct graph_has_add_vertex_by_label -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_mutability_traits< Graph >::category, labeled_add_vertex_tag >::value > { @@ -92,7 +94,7 @@ struct graph_has_add_vertex_by_label template < typename Graph > struct graph_has_add_vertex_by_label_with_property -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_mutability_traits< Graph >::category, labeled_add_vertex_property_tag >::value > { @@ -100,7 +102,7 @@ struct graph_has_add_vertex_by_label_with_property template < typename Graph > struct graph_has_remove_vertex_by_label -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_mutability_traits< Graph >::category, labeled_remove_vertex_tag >::value > { @@ -108,7 +110,7 @@ struct graph_has_remove_vertex_by_label template < typename Graph > struct graph_has_add_edge_by_label -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_mutability_traits< Graph >::category, labeled_add_edge_tag >::value > { @@ -116,7 +118,7 @@ struct graph_has_add_edge_by_label template < typename Graph > struct graph_has_add_edge_by_label_with_property -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_mutability_traits< Graph >::category, labeled_add_edge_property_tag >::value > { @@ -124,7 +126,7 @@ struct graph_has_add_edge_by_label_with_property template < typename Graph > struct graph_has_remove_edge_by_label -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_mutability_traits< Graph >::category, labeled_remove_edge_tag >::value > { @@ -132,49 +134,55 @@ struct graph_has_remove_edge_by_label template < typename Graph > struct is_labeled_mutable_vertex_graph -: mpl::and_< graph_has_add_vertex_by_label< Graph >, - graph_has_remove_vertex_by_label< Graph > > +: std::integral_constant< bool, + graph_has_add_vertex_by_label< Graph >::value + && graph_has_remove_vertex_by_label< Graph >::value > { }; template < typename Graph > struct is_labeled_mutable_vertex_property_graph -: mpl::and_< graph_has_add_vertex_by_label< Graph >, - graph_has_remove_vertex_by_label< Graph > > +: std::integral_constant< bool, + graph_has_add_vertex_by_label< Graph >::value + && graph_has_remove_vertex_by_label< Graph >::value > { }; template < typename Graph > struct is_labeled_mutable_edge_graph -: mpl::and_< graph_has_add_edge_by_label< Graph >, - graph_has_remove_edge_by_label< Graph > > +: std::integral_constant< bool, + graph_has_add_edge_by_label< Graph >::value + && graph_has_remove_edge_by_label< Graph >::value > { }; template < typename Graph > struct is_labeled_mutable_edge_property_graph -: mpl::and_< graph_has_add_edge_by_label< Graph >, - graph_has_remove_edge_by_label< Graph > > +: std::integral_constant< bool, + graph_has_add_edge_by_label< Graph >::value + && graph_has_remove_edge_by_label< Graph >::value > { }; template < typename Graph > struct is_labeled_mutable_graph -: mpl::and_< is_labeled_mutable_vertex_graph< Graph >, - is_labeled_mutable_edge_graph< Graph > > +: std::integral_constant< bool, + is_labeled_mutable_vertex_graph< Graph >::value + && is_labeled_mutable_edge_graph< Graph >::value > { }; template < typename Graph > struct is_labeled_mutable_property_graph -: mpl::and_< is_labeled_mutable_vertex_property_graph< Graph >, - is_labeled_mutable_edge_property_graph< Graph > > +: std::integral_constant< bool, + is_labeled_mutable_vertex_property_graph< Graph >::value + && is_labeled_mutable_edge_property_graph< Graph >::value > { }; template < typename Graph > struct is_labeled_add_only_property_graph -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_mutability_traits< Graph >::category, labeled_add_only_property_graph_tag >::value > { @@ -182,7 +190,7 @@ struct is_labeled_add_only_property_graph template < typename Graph > struct is_labeled_graph -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_mutability_traits< Graph >::category, label_vertex_tag >::value > { @@ -197,13 +205,15 @@ namespace graph_detail // graph_mutability_traits specialization below. template < typename Graph > struct determine_mutability { - typedef typename mpl::if_< is_add_only_property_graph< Graph >, + typedef typename std::conditional< + is_add_only_property_graph< Graph >::value, labeled_add_only_property_graph_tag, - typename mpl::if_< is_mutable_property_graph< Graph >, + typename std::conditional< is_mutable_property_graph< Graph >::value, labeled_mutable_property_graph_tag, - typename mpl::if_< is_mutable_graph< Graph >, + typename std::conditional< is_mutable_graph< Graph >::value, labeled_mutable_graph_tag, - typename mpl::if_< is_mutable_edge_graph< Graph >, + typename std::conditional< + is_mutable_edge_graph< Graph >::value, labeled_graph_tag, typename graph_mutability_traits< Graph >::category >:: type >::type >::type >::type type; diff --git a/include/boost/graph/detail/mpi_include.hpp b/include/boost/graph/detail/mpi_include.hpp deleted file mode 100644 index f64592dab..000000000 --- a/include/boost/graph/detail/mpi_include.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef BOOST_GRAPH_DETAIL_MPI_INCLUDE_HPP_INCLUDED -#define BOOST_GRAPH_DETAIL_MPI_INCLUDE_HPP_INCLUDED - -// Copyright 2018 Peter Dimov -// -// Use, modification and distribution are subject to the -// Boost Software License, Version 1.0 (See accompanying file -// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) - -#if defined BOOST_GRAPH_USE_MPI -#define BOOST_GRAPH_MPI_INCLUDE(x) x -#else -#define BOOST_GRAPH_MPI_INCLUDE(x) -#endif - -#endif // #ifndef BOOST_GRAPH_DETAIL_MPI_INCLUDE_HPP_INCLUDED diff --git a/include/boost/graph/detail/rapidxml.hpp b/include/boost/graph/detail/rapidxml.hpp new file mode 100644 index 000000000..ce6d440b3 --- /dev/null +++ b/include/boost/graph/detail/rapidxml.hpp @@ -0,0 +1,2606 @@ +// ---------------------------------------------------------------------------- +// Copyright (C) 2006, 2009 Marcin Kalicinski +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org +// ---------------------------------------------------------------------------- +// +// This is a vendored copy of the rapidxml parser that Boost.PropertyTree +// carries at boost/property_tree/detail/rapidxml.hpp. It lets Boost.Graph's +// GraphML reader parse XML without depending on the property_tree module. +// The only edits from the upstream copy are mechanical, to avoid clashing +// with a translation unit that also includes property_tree: the namespace is +// boost::graph::detail::rapidxml, the include guard and the +// BOOST_GRAPH_DETAIL_RAPIDXML_* macros are renamed. No parser logic is changed. +// +// ---------------------------------------------------------------------------- +#ifndef BOOST_GRAPH_DETAIL_RAPIDXML_HPP_INCLUDED +#define BOOST_GRAPH_DETAIL_RAPIDXML_HPP_INCLUDED + +//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation + +#include +#include +#include // For std::size_t +#include // For placement new + +// On MSVC, disable "conditional expression is constant" warning (level 4). +// This warning is almost impossible to avoid with certain types of templated code +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) // Conditional expression is constant +#endif + +/////////////////////////////////////////////////////////////////////////// +// BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR + +#include // For std::exception + +#define BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where) + +namespace boost { namespace graph { namespace detail { namespace rapidxml +{ + + //! Parse error exception. + //! This exception is thrown by the parser when an error occurs. + //! Use what() function to get human-readable error message. + //! Use where() function to get a pointer to position within source text where error was detected. + //!

    + //! If throwing exceptions by the parser is undesirable, + //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. + //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. + //! This function must be defined by the user. + //!

    + //! This class derives from std::exception class. + class parse_error: public std::exception + { + + public: + + //! Constructs parse error + parse_error(const char *wa, void *we) + : m_what(wa) + , m_where(we) + { + } + + //! Gets human readable description of error. + //! \return Pointer to null terminated description of the error. + const char *what() const throw() override + { + return m_what; + } + + //! Gets pointer to character data where error happened. + //! Ch should be the same as char type of xml_document that produced the error. + //! \return Pointer to location within the parsed string where error occurred. + template + Ch *where() const + { + return reinterpret_cast(m_where); + } + + private: + + const char *m_what; + void *m_where; + + }; +}}}} + +/////////////////////////////////////////////////////////////////////////// +// Pool sizes + +#ifndef BOOST_GRAPH_DETAIL_RAPIDXML_STATIC_POOL_SIZE + // Size of static memory block of memory_pool. + // Define BOOST_GRAPH_DETAIL_RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // No dynamic memory allocations are performed by memory_pool until static memory is exhausted. + #define BOOST_GRAPH_DETAIL_RAPIDXML_STATIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef BOOST_GRAPH_DETAIL_RAPIDXML_DYNAMIC_POOL_SIZE + // Size of dynamic memory block of memory_pool. + // Define BOOST_GRAPH_DETAIL_RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool. + #define BOOST_GRAPH_DETAIL_RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef BOOST_GRAPH_DETAIL_RAPIDXML_ALIGNMENT + // Memory allocation alignment. + // Define BOOST_GRAPH_DETAIL_RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer. + // All memory allocations for nodes, attributes and strings will be aligned to this value. + // This must be a power of 2 and at least 1, otherwise memory_pool will not work. + #define BOOST_GRAPH_DETAIL_RAPIDXML_ALIGNMENT sizeof(void *) +#endif + +namespace boost { namespace graph { namespace detail { namespace rapidxml +{ + // Forward declarations + template class xml_node; + template class xml_attribute; + template class xml_document; + + //! Enumeration listing all node types produced by the parser. + //! Use xml_node::type() function to query node type. + enum node_type + { + node_document, //!< A document node. Name and value are empty. + node_element, //!< An element node. Name contains element name. Value contains text of first data node. + node_data, //!< A data node. Name is empty. Value contains data text. + node_cdata, //!< A CDATA node. Name is empty. Value contains data text. + node_comment, //!< A comment node. Name is empty. Value contains comment text. + node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes. + node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text. + node_pi //!< A PI node. Name contains target. Value contains instructions. + }; + + /////////////////////////////////////////////////////////////////////// + // Parsing flags + + //! Parse flag instructing the parser to not create data nodes. + //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_no_data_nodes = 0x1; + + //! Parse flag instructing the parser to not use text of first data node as a value of parent element. + //! Can be combined with other flags by use of | operator. + //! Note that child data nodes of element node take precedence over its value when printing. + //! That is, if element has one or more child data nodes and a value, the value will be ignored. + //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements. + //!

    + //! See xml_document::parse() function. + const int parse_no_element_values = 0x2; + + //! Parse flag instructing the parser to not place zero terminators after strings in the source text. + //! By default zero terminators are placed, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_no_string_terminators = 0x4; + + //! Parse flag instructing the parser to not translate entities in the source text. + //! By default entities are translated, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_no_entity_translation = 0x8; + + //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. + //! By default, UTF-8 handling is enabled. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_no_utf8 = 0x10; + + //! Parse flag instructing the parser to create XML declaration node. + //! By default, declaration node is not created. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_declaration_node = 0x20; + + //! Parse flag instructing the parser to create comments nodes. + //! By default, comment nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_comment_nodes = 0x40; + + //! Parse flag instructing the parser to create DOCTYPE node. + //! By default, doctype node is not created. + //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_doctype_node = 0x80; + + //! Parse flag instructing the parser to create PI nodes. + //! By default, PI nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_pi_nodes = 0x100; + + //! Parse flag instructing the parser to validate closing tag names. + //! If not set, name inside closing tag is irrelevant to the parser. + //! By default, closing tags are not validated. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_validate_closing_tags = 0x200; + + //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. + //! By default, whitespace is not trimmed. + //! This flag does not cause the parser to modify source text. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_trim_whitespace = 0x400; + + //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. + //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. + //! By default, whitespace is not normalized. + //! If this flag is specified, source text will be modified. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_normalize_whitespace = 0x800; + + // Compound flags + + //! Parse flags which represent default behaviour of the parser. + //! This is always equal to 0, so that all other flags can be simply ored together. + //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values. + //! This also means that meaning of each flag is a negation of the default setting. + //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is enabled by default, + //! and using the flag will disable it. + //!

    + //! See xml_document::parse() function. + const int parse_default = 0; + + //! A combination of parse flags that forbids any modifications of the source text. + //! This also results in faster parsing. However, note that the following will occur: + //!
      + //!
    • names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends
    • + //!
    • entities will not be translated
    • + //!
    • whitespace will not be normalized
    • + //!
    + //! See xml_document::parse() function. + const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation; + + //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data. + //!

    + //! See xml_document::parse() function. + const int parse_fastest = parse_non_destructive | parse_no_data_nodes; + + //! A combination of parse flags resulting in largest amount of data being extracted. + //! This usually results in slowest parsing. + //!

    + //! See xml_document::parse() function. + const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; + + /////////////////////////////////////////////////////////////////////// + // Internals + + //! \cond internal + namespace internal + { + + // Struct that contains lookup tables for the parser + // It must be a template to allow correct linking (because it has static data members, which are defined in a header file). + template + struct lookup_tables + { + static const unsigned char lookup_whitespace[256]; // Whitespace table + static const unsigned char lookup_node_name[256]; // Node name table + static const unsigned char lookup_text[256]; // Text table + static const unsigned char lookup_text_pure_no_ws[256]; // Text table + static const unsigned char lookup_text_pure_with_ws[256]; // Text table + static const unsigned char lookup_attribute_name[256]; // Attribute name table + static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes + static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes + static const unsigned char lookup_digits[256]; // Digits + static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters + }; + + // Find length of the string + template + inline std::size_t measure(const Ch *p) + { + const Ch *tmp = p; + while (*tmp) + ++tmp; + return tmp - p; + } + + // Compare strings for equality + template + inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive) + { + if (size1 != size2) + return false; + if (case_sensitive) + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (*p1 != *p2) + return false; + } + else + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (lookup_tables<0>::lookup_upcase[static_cast(*p1)] != lookup_tables<0>::lookup_upcase[static_cast(*p2)]) + return false; + } + return true; + } + + template + inline size_t get_index(const Ch c) + { + // If not ASCII char, its semantic is same as plain 'z'. + // char could be signed, so first stretch and make unsigned. + unsigned n = c; + if (n > 127) + { + return 'z'; + } + return c; + } + } + //! \endcond + + /////////////////////////////////////////////////////////////////////// + // Memory pool + + //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. + //! In most cases, you will not need to use this class directly. + //! However, if you need to create nodes manually or modify names/values of nodes, + //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. + //! Not only is this faster than allocating them by using new operator, + //! but also their lifetime will be tied to the lifetime of document, + //! possibly simplifying memory management. + //!

    + //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. + //! You can also call allocate_string() function to allocate strings. + //! Such strings can then be used as names or values of nodes without worrying about their lifetime. + //! Note that there is no free() function -- all allocations are freed at once when clear() function is called, + //! or when the pool is destroyed. + //!

    + //! It is also possible to create a standalone memory_pool, and use it + //! to allocate nodes, whose lifetime will not be tied to any document. + //!

    + //! Pool maintains BOOST_GRAPH_DETAIL_RAPIDXML_STATIC_POOL_SIZE bytes of statically allocated memory. + //! Until static memory is exhausted, no dynamic memory allocations are done. + //! When static memory is exhausted, pool allocates additional blocks of memory of size BOOST_GRAPH_DETAIL_RAPIDXML_DYNAMIC_POOL_SIZE each, + //! by using global new[] and delete[] operators. + //! This behaviour can be changed by setting custom allocation routines. + //! Use set_allocator() function to set them. + //!

    + //! Allocations for nodes, attributes and strings are aligned at BOOST_GRAPH_DETAIL_RAPIDXML_ALIGNMENT bytes. + //! This value defaults to the size of pointer on target architecture. + //!

    + //! To obtain absolutely top performance from the parser, + //! it is important that all nodes are allocated from a single, contiguous block of memory. + //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. + //! If required, you can tweak BOOST_GRAPH_DETAIL_RAPIDXML_STATIC_POOL_SIZE, BOOST_GRAPH_DETAIL_RAPIDXML_DYNAMIC_POOL_SIZE and BOOST_GRAPH_DETAIL_RAPIDXML_ALIGNMENT + //! to obtain best wasted memory to performance compromise. + //! To do it, define their values before rapidxml.hpp file is included. + //! \param Ch Character type of created nodes. + template + class memory_pool + { + + public: + + //! \cond internal + // Prefixed names to work around weird MSVC lookup bug. + typedef void *(boost_ptree_raw_alloc_func)(std::size_t); // Type of user-defined function used to allocate memory + typedef void (boost_ptree_raw_free_func)(void *); // Type of user-defined function used to free memory + //! \endcond + + //! Constructs empty pool with default allocator functions. + memory_pool() + : m_alloc_func(0) + , m_free_func(0) + { + init(); + } + + //! Destroys pool and frees all the memory. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Nodes allocated from the pool are no longer valid. + ~memory_pool() + { + clear(); + } + + //! Allocates a new node from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accommodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param type Type of node to create. + //! \param name Name to assign to the node, or 0 to assign no name. + //! \param value Value to assign to the node, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated node. This pointer will never be NULL. + xml_node *allocate_node(node_type type, + const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_node)); + xml_node *node = new(memory) xml_node(type); + if (name) + { + if (name_size > 0) + node->name(name, name_size); + else + node->name(name); + } + if (value) + { + if (value_size > 0) + node->value(value, value_size); + else + node->value(value); + } + return node; + } + + //! Allocates a new attribute from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accommodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param name Name to assign to the attribute, or 0 to assign no name. + //! \param value Value to assign to the attribute, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated attribute. This pointer will never be NULL. + xml_attribute *allocate_attribute(const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_attribute)); + xml_attribute *attribute = new(memory) xml_attribute; + if (name) + { + if (name_size > 0) + attribute->name(name, name_size); + else + attribute->name(name); + } + if (value) + { + if (value_size > 0) + attribute->value(value, value_size); + else + attribute->value(value); + } + return attribute; + } + + //! Allocates a char array of given size from the pool, and optionally copies a given string to it. + //! If the allocation request cannot be accommodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param source String to initialize the allocated memory with, or 0 to not initialize it. + //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated. + //! \return Pointer to allocated char array. This pointer will never be NULL. + Ch *allocate_string(const Ch *source = 0, std::size_t size = 0) + { + BOOST_ASSERT(source || size); // Either source or size (or both) must be specified + if (size == 0) + size = internal::measure(source) + 1; + Ch *result = static_cast(allocate_aligned(size * sizeof(Ch))); + if (source) + for (std::size_t i = 0; i < size; ++i) + result[i] = source[i]; + return result; + } + + //! Clones an xml_node and its hierarchy of child nodes and attributes. + //! Nodes and attributes are allocated from this memory pool. + //! Names and values are not cloned, they are shared between the clone and the source. + //! Result node can be optionally specified as a second parameter, + //! in which case its contents will be replaced with cloned source node. + //! This is useful when you want to clone entire document. + //! \param source Node to clone. + //! \param result Node to put results in, or 0 to automatically allocate result node + //! \return Pointer to cloned node. This pointer will never be NULL. + xml_node *clone_node(const xml_node *source, xml_node *result = 0) + { + // Prepare result node + if (result) + { + result->remove_all_attributes(); + result->remove_all_nodes(); + result->type(source->type()); + } + else + result = allocate_node(source->type()); + + // Clone name and value + result->name(source->name(), source->name_size()); + result->value(source->value(), source->value_size()); + + // Clone child nodes and attributes + for (xml_node *child = source->first_node(); child; child = child->next_sibling()) + result->append_node(clone_node(child)); + for (xml_attribute *attr = source->first_attribute(); attr; attr = attr->next_attribute()) + result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size())); + + return result; + } + + //! Clears the pool. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Any nodes or strings allocated from the pool will no longer be valid. + void clear() + { + while (m_begin != m_static_memory) + { + char *previous_begin = reinterpret_cast
    (align(m_begin))->previous_begin; + if (m_free_func) + m_free_func(m_begin); + else + delete[] m_begin; + m_begin = previous_begin; + } + init(); + } + + //! Sets or resets the user-defined memory allocation functions for the pool. + //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. + //! Allocation function must not return invalid pointer on failure. It should either throw, + //! stop the program, or use longjmp() function to pass control to other place of program. + //! If it returns invalid pointer, results are undefined. + //!

    + //! User defined allocation functions must have the following forms: + //!
    + //!
    void *allocate(std::size_t size); + //!
    void free(void *pointer); + //!

    + //! \param af Allocation function, or 0 to restore default function + //! \param ff Free function, or 0 to restore default function + void set_allocator(boost_ptree_raw_alloc_func *af, boost_ptree_raw_free_func *ff) + { + BOOST_ASSERT(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet + m_alloc_func = af; + m_free_func = ff; + } + + private: + + struct header + { + char *previous_begin; + }; + + void init() + { + m_begin = m_static_memory; + m_ptr = align(m_begin); + m_end = m_static_memory + sizeof(m_static_memory); + } + + char *align(char *ptr) + { + std::size_t alignment = ((BOOST_GRAPH_DETAIL_RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (BOOST_GRAPH_DETAIL_RAPIDXML_ALIGNMENT - 1))) & (BOOST_GRAPH_DETAIL_RAPIDXML_ALIGNMENT - 1)); + return ptr + alignment; + } + + char *allocate_raw(std::size_t size) + { + // Allocate + void *memory; + if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[] + { + memory = m_alloc_func(size); + BOOST_ASSERT(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp + } + else + { + memory = new char[size]; + } + return static_cast(memory); + } + + void *allocate_aligned(std::size_t size) + { + // Calculate aligned pointer + char *result = align(m_ptr); + + // If not enough memory left in current pool, allocate a new pool + if (result + size > m_end) + { + // Calculate required pool size (may be bigger than BOOST_GRAPH_DETAIL_RAPIDXML_DYNAMIC_POOL_SIZE) + std::size_t pool_size = BOOST_GRAPH_DETAIL_RAPIDXML_DYNAMIC_POOL_SIZE; + if (pool_size < size) + pool_size = size; + + // Allocate + std::size_t alloc_size = sizeof(header) + (2 * BOOST_GRAPH_DETAIL_RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation + char *raw_memory = allocate_raw(alloc_size); + + // Setup new pool in allocated memory + char *pool = align(raw_memory); + header *new_header = reinterpret_cast
    (pool); + new_header->previous_begin = m_begin; + m_begin = raw_memory; + m_ptr = pool + sizeof(header); + m_end = raw_memory + alloc_size; + + // Calculate aligned pointer again using new pool + result = align(m_ptr); + } + + // Update pool and return aligned pointer + m_ptr = result + size; + return result; + } + + char *m_begin; // Start of raw memory making up current pool + char *m_ptr; // First free byte in current pool + char *m_end; // One past last available byte in current pool + char m_static_memory[BOOST_GRAPH_DETAIL_RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory + boost_ptree_raw_alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used + boost_ptree_raw_free_func *m_free_func; // Free function, or 0 if default is to be used + }; + + /////////////////////////////////////////////////////////////////////////// + // XML base + + //! Base class for xml_node and xml_attribute implementing common functions: + //! name(), name_size(), value(), value_size() and parent(). + //! \param Ch Character type to use + template + class xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + // Construct a base with empty name, value and parent + xml_base() + : m_name(0) + , m_value(0) + , m_parent(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets name of the node. + //! Interpretation of name depends on type of node. + //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

    + //! Use name_size() function to determine length of the name. + //! \return Name of node, or empty string if node has no name. + Ch *name() const + { + return m_name ? m_name : nullstr(); + } + + //! Gets size of node name, not including terminator character. + //! This function works correctly irrespective of whether name is or is not zero terminated. + //! \return Size of node name, in characters. + std::size_t name_size() const + { + return m_name ? m_name_size : 0; + } + + //! Gets value of node. + //! Interpretation of value depends on type of node. + //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

    + //! Use value_size() function to determine length of the value. + //! \return Value of node, or empty string if node has no value. + Ch *value() const + { + return m_value ? m_value : nullstr(); + } + + //! Gets size of node value, not including terminator character. + //! This function works correctly irrespective of whether value is or is not zero terminated. + //! \return Size of node value, in characters. + std::size_t value_size() const + { + return m_value ? m_value_size : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets name of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

    + //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is responsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

    + //! Size of name must be specified separately, because name does not have to be zero terminated. + //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //! \param n Name of node to set. Does not have to be zero terminated. + //! \param size Size of name, in characters. This does not include zero terminator, if one is present. + void name(const Ch *n, std::size_t size) + { + m_name = const_cast(n); + m_name_size = size; + } + + //! Sets name of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t). + //! \param n Name of node to set. Must be zero terminated. + void name(const Ch *n) + { + name(n, internal::measure(n)); + } + + //! Sets value of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

    + //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is responsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

    + //! Size of value must be specified separately, because it does not have to be zero terminated. + //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //!

    + //! If an element has a child node of type node_data, it will take precedence over element value when printing. + //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser. + //! \param val Value of node to set. Does not have to be zero terminated. + //! \param size Size of value, in characters. This does not include zero terminator, if one is present. + void value(const Ch *val, std::size_t size) + { + m_value = const_cast(val); + m_value_size = size; + } + + //! Sets value of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t). + //! \param val Name of node to set. Must be zero terminated. + void value(const Ch *val) + { + this->value(val, internal::measure(val)); + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets node parent. + //! \return Pointer to parent node, or 0 if there is no parent. + xml_node *parent() const + { + return m_parent; + } + + protected: + + // Return empty string + static Ch *nullstr() + { + static Ch zero = Ch('\0'); + return &zero; + } + + Ch *m_name; // Name of node, or 0 if no name + Ch *m_value; // Value of node, or 0 if no value + std::size_t m_name_size; // Length of node name, or undefined of no name + std::size_t m_value_size; // Length of node value, or undefined if no value + xml_node *m_parent; // Pointer to parent node, or 0 if none + + }; + + //! Class representing attribute node of XML document. + //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). + //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. + //! Thus, this text must persist in memory for the lifetime of attribute. + //! \param Ch Character type to use. + template + class xml_attribute: public xml_base + { + + friend class xml_node; + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty attribute with the specified type. + //! Consider using memory_pool of appropriate xml_document if allocating attributes manually. + xml_attribute() + { + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which attribute is a child. + //! \return Pointer to document that contains this attribute, or 0 if there is no parent document. + xml_document *document() const + { + if (xml_node *node = this->parent()) + { + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + else + return 0; + } + + //! Gets previous attribute, optionally matching attribute name. + //! \param n Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero + //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *previous_attribute(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const + { + if (n) + { + if (nsize == 0) + nsize = internal::measure(n); + for (xml_attribute *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), n, nsize, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_prev_attribute : 0; + } + + //! Gets next attribute, optionally matching attribute name. + //! \param n Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero + //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *next_attribute(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const + { + if (n) + { + if (nsize == 0) + nsize = internal::measure(n); + for (xml_attribute *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), n, nsize, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_next_attribute : 0; + } + + private: + + xml_attribute *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero + xml_attribute *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML node + + //! Class representing a node of XML document. + //! Each node may have associated name and value strings, which are available through name() and value() functions. + //! Interpretation of name and value depends on type of the node. + //! Type of node can be determined by using type() function. + //!

    + //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. + //! Thus, this text must persist in the memory for the lifetime of node. + //! \param Ch Character type to use. + template + class xml_node: public xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty node with the specified type. + //! Consider using memory_pool of appropriate document to allocate nodes manually. + //! \param t Type of node to construct. + xml_node(node_type t) + : m_type(t) + , m_first_node(0) + , m_first_attribute(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets type of node. + //! \return Type of node. + node_type type() const + { + return m_type; + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which node is a child. + //! \return Pointer to document that contains this node, or 0 if there is no parent document. + xml_document *document() const + { + xml_node *node = const_cast *>(this); + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + + //! Gets first child node, optionally matching node name. + //! \param n Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero + //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *first_node(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const + { + if (n) + { + if (nsize == 0) + nsize = internal::measure(n); + for (xml_node *child = m_first_node; child; child = child->next_sibling()) + if (internal::compare(child->name(), child->name_size(), n, nsize, case_sensitive)) + return child; + return 0; + } + else + return m_first_node; + } + + //! Gets last child node, optionally matching node name. + //! Behaviour is undefined if node has no children. + //! Use first_node() to test if node has children. + //! \param n Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero + //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *last_node(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const + { + BOOST_ASSERT(m_first_node); // Cannot query for last child if node has no children + if (n) + { + if (nsize == 0) + nsize = internal::measure(n); + for (xml_node *child = m_last_node; child; child = child->previous_sibling()) + if (internal::compare(child->name(), child->name_size(), n, nsize, case_sensitive)) + return child; + return 0; + } + else + return m_last_node; + } + + //! Gets previous sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param n Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero + //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *previous_sibling(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const + { + BOOST_ASSERT(this->m_parent); // Cannot query for siblings if node has no parent + if (n) + { + if (nsize == 0) + nsize = internal::measure(n); + for (xml_node *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), n, nsize, case_sensitive)) + return sibling; + return 0; + } + else + return m_prev_sibling; + } + + //! Gets next sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param n Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero + //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *next_sibling(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const + { + BOOST_ASSERT(this->m_parent); // Cannot query for siblings if node has no parent + if (n) + { + if (nsize == 0) + nsize = internal::measure(n); + for (xml_node *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), n, nsize, case_sensitive)) + return sibling; + return 0; + } + else + return m_next_sibling; + } + + //! Gets first attribute of node, optionally matching attribute name. + //! \param n Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero + //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *first_attribute(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const + { + if (n) + { + if (nsize == 0) + nsize = internal::measure(n); + for (xml_attribute *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), n, nsize, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute; + } + + //! Gets last attribute of node, optionally matching attribute name. + //! \param n Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if nsize is non-zero + //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *last_attribute(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const + { + if (n) + { + if (nsize == 0) + nsize = internal::measure(n); + for (xml_attribute *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), n, nsize, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute ? m_last_attribute : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets type of node. + //! \param t Type of node to set. + void type(node_type t) + { + m_type = t; + } + + /////////////////////////////////////////////////////////////////////////// + // Node manipulation + + //! Prepends a new child node. + //! The prepended child becomes the first child, and all existing children are moved one position back. + //! \param child Node to prepend. + void prepend_node(xml_node *child) + { + BOOST_ASSERT(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_next_sibling = m_first_node; + m_first_node->m_prev_sibling = child; + } + else + { + child->m_next_sibling = 0; + m_last_node = child; + } + m_first_node = child; + child->m_parent = this; + child->m_prev_sibling = 0; + } + + //! Appends a new child node. + //! The appended child becomes the last child. + //! \param child Node to append. + void append_node(xml_node *child) + { + BOOST_ASSERT(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_prev_sibling = m_last_node; + m_last_node->m_next_sibling = child; + } + else + { + child->m_prev_sibling = 0; + m_first_node = child; + } + m_last_node = child; + child->m_parent = this; + child->m_next_sibling = 0; + } + + //! Inserts a new child node at specified place inside the node. + //! All children after and including the specified node are moved one position back. + //! \param where Place where to insert the child, or 0 to insert at the back. + //! \param child Node to insert. + void insert_node(xml_node *where, xml_node *child) + { + BOOST_ASSERT(!where || where->parent() == this); + BOOST_ASSERT(child && !child->parent() && child->type() != node_document); + if (where == m_first_node) + prepend_node(child); + else if (where == 0) + append_node(child); + else + { + child->m_prev_sibling = where->m_prev_sibling; + child->m_next_sibling = where; + where->m_prev_sibling->m_next_sibling = child; + where->m_prev_sibling = child; + child->m_parent = this; + } + } + + //! Removes first child node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_first_node() + { + BOOST_ASSERT(first_node()); + xml_node *child = m_first_node; + m_first_node = child->m_next_sibling; + if (child->m_next_sibling) + child->m_next_sibling->m_prev_sibling = 0; + else + m_last_node = 0; + child->m_parent = 0; + } + + //! Removes last child of the node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_last_node() + { + BOOST_ASSERT(first_node()); + xml_node *child = m_last_node; + if (child->m_prev_sibling) + { + m_last_node = child->m_prev_sibling; + child->m_prev_sibling->m_next_sibling = 0; + } + else + m_first_node = 0; + child->m_parent = 0; + } + + //! Removes specified child from the node + // \param where Pointer to child to be removed. + void remove_node(xml_node *where) + { + BOOST_ASSERT(where && where->parent() == this); + BOOST_ASSERT(first_node()); + if (where == m_first_node) + remove_first_node(); + else if (where == m_last_node) + remove_last_node(); + else + { + where->m_prev_sibling->m_next_sibling = where->m_next_sibling; + where->m_next_sibling->m_prev_sibling = where->m_prev_sibling; + where->m_parent = 0; + } + } + + //! Removes all child nodes (but not attributes). + void remove_all_nodes() + { + for (xml_node *node = first_node(); node; node = node->m_next_sibling) + node->m_parent = 0; + m_first_node = 0; + } + + //! Prepends a new attribute to the node. + //! \param attribute Attribute to prepend. + void prepend_attribute(xml_attribute *attribute) + { + BOOST_ASSERT(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_next_attribute = m_first_attribute; + m_first_attribute->m_prev_attribute = attribute; + } + else + { + attribute->m_next_attribute = 0; + m_last_attribute = attribute; + } + m_first_attribute = attribute; + attribute->m_parent = this; + attribute->m_prev_attribute = 0; + } + + //! Appends a new attribute to the node. + //! \param attribute Attribute to append. + void append_attribute(xml_attribute *attribute) + { + BOOST_ASSERT(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_prev_attribute = m_last_attribute; + m_last_attribute->m_next_attribute = attribute; + } + else + { + attribute->m_prev_attribute = 0; + m_first_attribute = attribute; + } + m_last_attribute = attribute; + attribute->m_parent = this; + attribute->m_next_attribute = 0; + } + + //! Inserts a new attribute at specified place inside the node. + //! All attributes after and including the specified attribute are moved one position back. + //! \param where Place where to insert the attribute, or 0 to insert at the back. + //! \param attribute Attribute to insert. + void insert_attribute(xml_attribute *where, xml_attribute *attribute) + { + BOOST_ASSERT(!where || where->parent() == this); + BOOST_ASSERT(attribute && !attribute->parent()); + if (where == m_first_attribute) + prepend_attribute(attribute); + else if (where == 0) + append_attribute(attribute); + else + { + attribute->m_prev_attribute = where->m_prev_attribute; + attribute->m_next_attribute = where; + where->m_prev_attribute->m_next_attribute = attribute; + where->m_prev_attribute = attribute; + attribute->m_parent = this; + } + } + + //! Removes first attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_first_attribute() + { + BOOST_ASSERT(first_attribute()); + xml_attribute *attribute = m_first_attribute; + if (attribute->m_next_attribute) + { + attribute->m_next_attribute->m_prev_attribute = 0; + } + else + m_last_attribute = 0; + attribute->m_parent = 0; + m_first_attribute = attribute->m_next_attribute; + } + + //! Removes last attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_last_attribute() + { + BOOST_ASSERT(first_attribute()); + xml_attribute *attribute = m_last_attribute; + if (attribute->m_prev_attribute) + { + attribute->m_prev_attribute->m_next_attribute = 0; + m_last_attribute = attribute->m_prev_attribute; + } + else + m_first_attribute = 0; + attribute->m_parent = 0; + } + + //! Removes specified attribute from node. + //! \param where Pointer to attribute to be removed. + void remove_attribute(xml_attribute *where) + { + BOOST_ASSERT(first_attribute() && where->parent() == this); + if (where == m_first_attribute) + remove_first_attribute(); + else if (where == m_last_attribute) + remove_last_attribute(); + else + { + where->m_prev_attribute->m_next_attribute = where->m_next_attribute; + where->m_next_attribute->m_prev_attribute = where->m_prev_attribute; + where->m_parent = 0; + } + } + + //! Removes all attributes of node. + void remove_all_attributes() + { + for (xml_attribute *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute) + attribute->m_parent = 0; + m_first_attribute = 0; + } + + private: + + /////////////////////////////////////////////////////////////////////////// + // Restrictions + + // No copying + xml_node(const xml_node &); + void operator =(const xml_node &); + + /////////////////////////////////////////////////////////////////////////// + // Data members + + // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0. + // This is required for maximum performance, as it allows the parser to omit initialization of + // unneeded/redundant values. + // + // The rules are as follows: + // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively + // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage + // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage + + node_type m_type; // Type of node; always valid + xml_node *m_first_node; // Pointer to first child node, or 0 if none; always valid + xml_node *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero + xml_attribute *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid + xml_attribute *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero + xml_node *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + xml_node *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML document + + //! This class represents root of the DOM hierarchy. + //! It is also an xml_node and a memory_pool through public inheritance. + //! Use parse() function to build a DOM tree from a zero-terminated XML text string. + //! parse() function allocates memory for nodes and attributes by using functions of xml_document, + //! which are inherited from memory_pool. + //! To access root node of the document, use the document itself, as if it was an xml_node. + //! \param Ch Character type to use. + template + class xml_document: public xml_node, public memory_pool + { + + public: + + //! Constructs empty XML document + xml_document() + : xml_node(node_document) + { + } + + //! Parses zero-terminated XML string according to given flags. + //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. + //! The string must persist for the lifetime of the document. + //! In case of error, rapidxml::parse_error exception will be thrown. + //!

    + //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. + //! Make sure that data is zero-terminated. + //!

    + //! Document can be parsed into multiple times. + //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool. + //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser. + template + void parse(Ch *text) + { + BOOST_ASSERT(text); + + // Remove current contents + this->remove_all_nodes(); + this->remove_all_attributes(); + + // Parse BOM, if any + parse_bom(text); + + // Parse children + while (true) + { + // Skip whitespace before node + skip(text); + if (*text == 0) + break; + + // Parse and append new child + if (*text == Ch('<')) + { + ++text; // Skip '<' + if (xml_node *node = parse_node(text)) + this->append_node(node); + } + else + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("expected <", text); + } + + } + + //! Clears the document by deleting all nodes and clearing the memory pool. + //! All nodes owned by document pool are destroyed. + void clear() + { + this->remove_all_nodes(); + this->remove_all_attributes(); + memory_pool::clear(); + } + + private: + + /////////////////////////////////////////////////////////////////////// + // Internal character utility functions + + // Detect whitespace character + struct whitespace_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_whitespace[internal::get_index(ch)]; + } + }; + + // Detect node name character + struct node_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_node_name[internal::get_index(ch)]; + } + }; + + // Detect attribute name character + struct attribute_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_attribute_name[internal::get_index(ch)]; + } + }; + + // Detect text character (PCDATA) + struct text_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text[internal::get_index(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_no_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_no_ws[internal::get_index(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_with_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_with_ws[internal::get_index(ch)]; + } + }; + + // Detect attribute value character + template + struct attribute_value_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1[internal::get_index(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2[internal::get_index(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Detect attribute value character + template + struct attribute_value_pure_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1_pure[internal::get_index(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2_pure[internal::get_index(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Insert coded character, using UTF8 or 8-bit ASCII + template + static void insert_coded_character(Ch *&text, unsigned long code) + { + if (Flags & parse_no_utf8) + { + // Insert 8-bit ASCII character + // Todo: possibly verify that code is less than 256 and use replacement char otherwise? + text[0] = static_cast(code); + text += 1; + } + else + { + // Insert UTF8 sequence + if (code < 0x80) // 1 byte sequence + { + text[0] = static_cast(code); + text += 1; + } + else if (code < 0x800) // 2 byte sequence + { + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xC0); + text += 2; + } + else if (code < 0x10000) // 3 byte sequence + { + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xE0); + text += 3; + } + else if (code < 0x110000) // 4 byte sequence + { + text[3] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xF0); + text += 4; + } + else // Invalid, only codes up to 0x10FFFF are allowed in Unicode + { + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("invalid numeric character entity", text); + } + } + } + + // Skip characters until predicate evaluates to true + template + static void skip(Ch *&text) + { + Ch *tmp = text; + while (StopPred::test(*tmp)) + ++tmp; + text = tmp; + } + + // Skip characters until predicate evaluates to true while doing the following: + // - replacing XML character entity references with proper characters (' & " < > &#...;) + // - condensing whitespace sequences to single space character + template + static Ch *skip_and_expand_character_refs(Ch *&text) + { + // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip + if (Flags & parse_no_entity_translation && + !(Flags & parse_normalize_whitespace) && + !(Flags & parse_trim_whitespace)) + { + skip(text); + return text; + } + + // Use simple skip until first modification is detected + skip(text); + + // Use translation skip + Ch *src = text; + Ch *dest = src; + while (StopPred::test(*src)) + { + // If entity translation is enabled + if (!(Flags & parse_no_entity_translation)) + { + // Test if replacement is needed + if (src[0] == Ch('&')) + { + switch (src[1]) + { + + // & ' + case Ch('a'): + if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';')) + { + *dest = Ch('&'); + ++dest; + src += 5; + continue; + } + if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';')) + { + *dest = Ch('\''); + ++dest; + src += 6; + continue; + } + break; + + // " + case Ch('q'): + if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';')) + { + *dest = Ch('"'); + ++dest; + src += 6; + continue; + } + break; + + // > + case Ch('g'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('>'); + ++dest; + src += 4; + continue; + } + break; + + // < + case Ch('l'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('<'); + ++dest; + src += 4; + continue; + } + break; + + // &#...; - assumes ASCII + case Ch('#'): + if (src[2] == Ch('x')) + { + unsigned long code = 0; + src += 3; // Skip &#x + while (true) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 16 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + else + { + unsigned long code = 0; + src += 2; // Skip &# + while (true) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 10 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + if (*src == Ch(';')) + ++src; + else + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("expected ;", src); + continue; + + // Something else + default: + // Ignore, just copy '&' verbatim + break; + + } + } + } + + // If whitespace condensing is enabled + if (Flags & parse_normalize_whitespace) + { + // Test if condensing is needed + if (whitespace_pred::test(*src)) + { + *dest = Ch(' '); ++dest; // Put single space in dest + ++src; // Skip first whitespace char + // Skip remaining whitespace chars + while (whitespace_pred::test(*src)) + ++src; + continue; + } + } + + // No replacement, only copy character + *dest++ = *src++; + + } + + // Return new end + text = src; + return dest; + + } + + /////////////////////////////////////////////////////////////////////// + // Internal parsing functions + + // Parse UTF-8 BOM, if any + template + void parse_bom(char *&text) + { + if (static_cast(text[0]) == 0xEF && + static_cast(text[1]) == 0xBB && + static_cast(text[2]) == 0xBF) + { + text += 3; + } + } + + // Parse UTF-16/32 BOM, if any + template + void parse_bom(wchar_t *&text) + { + const wchar_t bom = 0xFEFF; + if (text[0] == bom) + { + ++text; + } + } + + // Parse XML declaration ( + xml_node *parse_xml_declaration(Ch *&text) + { + // If parsing of declaration is disabled + if (!(Flags & parse_declaration_node)) + { + // Skip until end of declaration + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (!text[0]) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + + // Create declaration + xml_node *declaration = this->allocate_node(node_declaration); + + // Skip whitespace before attributes or ?> + skip(text); + + // Parse declaration attributes + parse_node_attributes(text, declaration); + + // Skip ?> + if (text[0] != Ch('?') || text[1] != Ch('>')) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("expected ?>", text); + text += 2; + + return declaration; + } + + // Parse XML comment (' + return 0; // Do not produce comment node + } + + // Remember value start + Ch *val = text; + + // Skip until end of comment + while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) + { + if (!text[0]) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create comment node + xml_node *comment = this->allocate_node(node_comment); + comment->value(val, text - val); + + // Place zero terminator after comment value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip '-->' + return comment; + } + + // Parse DOCTYPE + template + xml_node *parse_doctype(Ch *&text) + { + // Remember value start + Ch *val = text; + + // Skip to > + while (*text != Ch('>')) + { + // Determine character type + switch (*text) + { + + // If '[' encountered, scan for matching ending ']' using naive algorithm with depth + // This works for all W3C test files except for 2 most wicked + case Ch('['): + { + ++text; // Skip '[' + int depth = 1; + while (depth > 0) + { + switch (*text) + { + case Ch('['): ++depth; break; + case Ch(']'): --depth; break; + case 0: BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("unexpected end of data", text); + default: break; + } + ++text; + } + break; + } + + // Error on end of text + case Ch('\0'): + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Other character, skip it + default: + ++text; + + } + } + + // If DOCTYPE nodes enabled + if (Flags & parse_doctype_node) + { + // Create a new doctype node + xml_node *doctype = this->allocate_node(node_doctype); + doctype->value(val, text - val); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 1; // skip '>' + return doctype; + } + else + { + text += 1; // skip '>' + return 0; + } + + } + + // Parse PI + template + xml_node *parse_pi(Ch *&text) + { + // If creation of PI nodes is enabled + if (Flags & parse_pi_nodes) + { + // Create pi node + xml_node *pi = this->allocate_node(node_pi); + + // Extract PI target name + Ch *n = text; + skip(text); + if (text == n) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("expected PI target", text); + pi->name(n, text - n); + + // Skip whitespace between pi target and pi + skip(text); + + // Remember start of pi + Ch *val = text; + + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Set pi value (verbatim, no entity expansion or whitespace normalization) + pi->value(val, text - val); + + // Place zero terminator after name and value + if (!(Flags & parse_no_string_terminators)) + { + pi->name()[pi->name_size()] = Ch('\0'); + pi->value()[pi->value_size()] = Ch('\0'); + } + + text += 2; // Skip '?>' + return pi; + } + else + { + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + } + + // Parse and append data + // Return character that ends data. + // This is necessary because this character might have been overwritten by a terminating 0 + template + Ch parse_and_append_data(xml_node *node, Ch *&text, Ch *contents_start) + { + // Backup to contents start if whitespace trimming is disabled + if (!(Flags & parse_trim_whitespace)) + text = contents_start; + + // Skip until end of data + Ch *val = text, *end; + if (Flags & parse_normalize_whitespace) + end = skip_and_expand_character_refs(text); + else + end = skip_and_expand_character_refs(text); + + // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after > + if (Flags & parse_trim_whitespace) + { + if (Flags & parse_normalize_whitespace) + { + // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end + if (*(end - 1) == Ch(' ')) + --end; + } + else + { + // Backup until non-whitespace character is found + while (whitespace_pred::test(*(end - 1))) + --end; + } + } + + // If characters are still left between end and value (this test is only necessary if normalization is enabled) + // Create new data node + if (!(Flags & parse_no_data_nodes)) + { + xml_node *data = this->allocate_node(node_data); + data->value(val, end - val); + node->append_node(data); + } + + // Add data to parent node if no data exists yet + if (!(Flags & parse_no_element_values)) + if (*node->value() == Ch('\0')) + node->value(val, end - val); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + { + Ch ch = *text; + *end = Ch('\0'); + return ch; // Return character that ends data; this is required because zero terminator overwritten it + } + + // Return character that ends data + return *text; + } + + // Parse CDATA + template + xml_node *parse_cdata(Ch *&text) + { + // If CDATA is disabled + if (Flags & parse_no_data_nodes) + { + // Skip until end of cdata + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 3; // Skip ]]> + return 0; // Do not produce CDATA node + } + + // Skip until end of cdata + Ch *val = text; + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create new cdata node + xml_node *cdata = this->allocate_node(node_cdata); + cdata->value(val, text - val); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip ]]> + return cdata; + } + + // Parse element node + template + xml_node *parse_element(Ch *&text) + { + // Create element node + xml_node *element = this->allocate_node(node_element); + + // Extract element name + Ch *n = text; + skip(text); + if (text == n) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("expected element name", text); + element->name(n, text - n); + + // Skip whitespace between element name and attributes or > + skip(text); + + // Parse attributes, if any + parse_node_attributes(text, element); + + // Determine ending type + if (*text == Ch('>')) + { + ++text; + parse_node_contents(text, element); + } + else if (*text == Ch('/')) + { + ++text; + if (*text != Ch('>')) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("expected >", text); + ++text; + } + else + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("expected >", text); + + // Place zero terminator after name + if (!(Flags & parse_no_string_terminators)) + element->name()[element->name_size()] = Ch('\0'); + + // Return parsed element + return element; + } + + // Determine node type, and parse it + template + xml_node *parse_node(Ch *&text) + { + // Parse proper node type + switch (text[0]) + { + + // <... + default: + // Parse and append element node + return parse_element(text); + + // (text); + } + else + { + // Parse PI + return parse_pi(text); + } + + // (text); + } + break; + + // (text); + } + break; + + // (text); + } + break; + + default: break; + + } // switch + + // Attempt to skip other, unrecognized node types starting with ')) + { + if (*text == 0) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + ++text; // Skip '>' + return 0; // No node recognized + + } + } + + // Parse contents of the node - children, data etc. + template + void parse_node_contents(Ch *&text, xml_node *node) + { + // For all children and text + while (true) + { + // Skip whitespace between > and node contents + Ch *contents_start = text; // Store start of node contents before whitespace is skipped + if (Flags & parse_trim_whitespace) + skip(text); + Ch next_char = *text; + + // After data nodes, instead of continuing the loop, control jumps here. + // This is because zero termination inside parse_and_append_data() function + // would wreak havoc with the above code. + // Also, skipping whitespace after data nodes is unnecessary. + after_data_node: + + // Determine what comes next: node closing, child node, data node, or 0? + switch (next_char) + { + + // Node closing or child node + case Ch('<'): + if (text[1] == Ch('/')) + { + // Node closing + text += 2; // Skip '(text); + if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true)) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("invalid closing tag name", text); + } + else + { + // No validation, just skip name + skip(text); + } + // Skip remaining whitespace after node name + skip(text); + if (*text != Ch('>')) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("expected >", text); + ++text; // Skip '>' + return; // Node closed, finished parsing contents + } + else + { + // Child node + ++text; // Skip '<' + if (xml_node *child = parse_node(text)) + node->append_node(child); + } + break; + + // End of data - error + case Ch('\0'): + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Data node + default: + next_char = parse_and_append_data(node, text, contents_start); + goto after_data_node; // Bypass regular processing after data nodes + + } + } + } + + // Parse XML attributes of the node + template + void parse_node_attributes(Ch *&text, xml_node *node) + { + // For all attributes + while (attribute_name_pred::test(*text)) + { + // Extract attribute name + Ch *n = text; + ++text; // Skip first character of attribute name + skip(text); + if (text == n) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("expected attribute name", n); + + // Create new attribute + xml_attribute *attribute = this->allocate_attribute(); + attribute->name(n, text - n); + node->append_attribute(attribute); + + // Skip whitespace after attribute name + skip(text); + + // Skip = + if (*text != Ch('=')) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("expected =", text); + ++text; + + // Add terminating zero after name + if (!(Flags & parse_no_string_terminators)) + attribute->name()[attribute->name_size()] = 0; + + // Skip whitespace after = + skip(text); + + // Skip quote and remember if it was ' or " + Ch quote = *text; + if (quote != Ch('\'') && quote != Ch('"')) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; + + // Extract attribute value and expand char refs in it + Ch *val = text, *end; + const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes + if (quote == Ch('\'')) + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + else + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + + // Set attribute value + attribute->value(val, end - val); + + // Make sure that end quote is present + if (*text != quote) + BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; // Skip quote + + // Add terminating zero after value + if (!(Flags & parse_no_string_terminators)) + attribute->value()[attribute->value_size()] = 0; + + // Skip whitespace after attribute value + skip(text); + } + } + + }; + + //! \cond internal + namespace internal + { + + // Whitespace (space \n \r \t) + template + const unsigned char lookup_tables::lookup_whitespace[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F + }; + + // Node name (anything but space \n \r \t / > ? \0) + template + const unsigned char lookup_tables::lookup_node_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) (anything but < \0) + template + const unsigned char lookup_tables::lookup_text[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled + // (anything but < \0 &) + template + const unsigned char lookup_tables::lookup_text_pure_no_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalizations is enabled + // (anything but < \0 & space \n \r \t) + template + const unsigned char lookup_tables::lookup_text_pure_with_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute name (anything but space \n \r \t / < > = ? ! \0) + template + const unsigned char lookup_tables::lookup_attribute_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote (anything but ' \0) + template + const unsigned char lookup_tables::lookup_attribute_data_1[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote that does not require processing (anything but ' \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_1_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote (anything but " \0) + template + const unsigned char lookup_tables::lookup_attribute_data_2[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote that does not require processing (anything but " \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_2_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Digits (dec and hex, 255 denotes end of numeric character reference) + template + const unsigned char lookup_tables::lookup_digits[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 2 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255, // 3 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 4 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 5 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 6 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 7 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // F + }; + + // Upper case conversion + template + const unsigned char lookup_tables::lookup_upcase[256] = + { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0 + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2 + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3 + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5 + 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127, // 7 + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 8 + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 9 + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // A + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // B + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // C + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // D + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // E + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // F + }; + } + //! \endcond + +}}}} + +// Undefine internal macros +#undef BOOST_GRAPH_DETAIL_RAPIDXML_PARSE_ERROR + +// On MSVC, restore warnings state +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#endif diff --git a/include/boost/graph/detail/read_graphviz_spirit.hpp b/include/boost/graph/detail/read_graphviz_spirit.hpp deleted file mode 100644 index 165007766..000000000 --- a/include/boost/graph/detail/read_graphviz_spirit.hpp +++ /dev/null @@ -1,673 +0,0 @@ -// Copyright 2004-9 Trustees of Indiana University - -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -// -// read_graphviz_spirit.hpp - -// Initialize a model of the BGL's MutableGraph concept and an associated -// collection of property maps using a graph expressed in the GraphViz -// DOT Language. -// -// Based on the grammar found at: -// https://web.archive.org/web/20041213234742/http://www.graphviz.org/cvs/doc/info/lang.html -// -// See documentation for this code at: -// http://www.boost.org/libs/graph/doc/read_graphviz.html -// - -// Author: Ronald Garcia -// - -#ifndef BOOST_READ_GRAPHVIZ_SPIRIT_HPP -#define BOOST_READ_GRAPHVIZ_SPIRIT_HPP - -// Phoenix/Spirit set these limits to 3, but I need more. -#define PHOENIX_LIMIT 6 -#define BOOST_SPIRIT_CLOSURE_LIMIT 6 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // for std::exception -#include -#include -#include -#include -#include -#include -#include - -namespace phoenix -{ -// Workaround: std::map::operator[] uses a different return type than all -// other standard containers. Phoenix doesn't account for that. -template < typename TK, typename T0, typename T1 > -struct binary_operator< index_op, std::map< TK, T0 >, T1 > -{ - typedef typename std::map< TK, T0 >::mapped_type& result_type; - static result_type eval(std::map< TK, T0 >& container, T1 const& index) - { - return container[index]; - } -}; -} // namespace phoenix - -namespace boost -{ -namespace detail -{ - namespace graph - { - - ///////////////////////////////////////////////////////////////////////////// - // Application-specific type definitions - ///////////////////////////////////////////////////////////////////////////// - - typedef std::set< edge_t > edges_t; - typedef std::set< node_t > nodes_t; - typedef std::set< id_t > ids_t; - typedef std::map< edge_t, ids_t > edge_map_t; - typedef std::map< node_t, ids_t > node_map_t; - typedef std::map< id_t, id_t > props_t; - typedef std::map< id_t, props_t > subgraph_props_t; - typedef boost::function2< void, id_t const&, id_t const& > actor_t; - typedef std::vector< edge_t > edge_stack_t; - typedef std::map< id_t, nodes_t > subgraph_nodes_t; - typedef std::map< id_t, edges_t > subgraph_edges_t; - - ///////////////////////////////////////////////////////////////////////////// - // Stack frames used by semantic actions - ///////////////////////////////////////////////////////////////////////////// - struct id_closure - : boost::spirit::classic::closure< id_closure, node_t > - { - member1 name; - }; - - struct node_id_closure - : boost::spirit::classic::closure< node_id_closure, node_t > - { - member1 name; - }; - - struct attr_list_closure - : boost::spirit::classic::closure< attr_list_closure, actor_t > - { - member1 prop_actor; - }; - - struct property_closure - : boost::spirit::classic::closure< property_closure, id_t, id_t > - { - member1 key; - member2 value; - }; - - struct data_stmt_closure - : boost::spirit::classic::closure< data_stmt_closure, nodes_t, nodes_t, - edge_stack_t, bool, node_t > - { - member1 sources; - member2 dests; - member3 edge_stack; - member4 saw_node; - member5 active_node; - }; - - struct subgraph_closure - : boost::spirit::classic::closure< subgraph_closure, nodes_t, edges_t, - node_t > - { - member1 nodes; - member2 edges; - member3 name; - }; - - ///////////////////////////////////////////////////////////////////////////// - // Grammar and Actions for the DOT Language - ///////////////////////////////////////////////////////////////////////////// - - // Grammar for a dot file. - struct dot_grammar - : public boost::spirit::classic::grammar< dot_grammar > - { - mutate_graph& graph_; - explicit dot_grammar(mutate_graph& graph) : graph_(graph) {} - - template < class ScannerT > struct definition - { - - definition(dot_grammar const& self) - : self(self), subgraph_depth(0), keyword_p("0-9a-zA-Z_") - { - using namespace boost::spirit::classic; - using namespace phoenix; - - // RG - Future Work - // - Handle multi-line strings using \ line continuation - // - Make keywords case insensitive - ID = (lexeme_d[( - (alpha_p | ch_p('_')) >> *(alnum_p | ch_p('_')))] - | real_p | lexeme_d[confix_p('"', *c_escape_ch_p, '"')] - | comment_nest_p('<', '>'))[ID.name - = construct_< std::string >(arg1, arg2)]; - - a_list = list_p( - ID[((a_list.key = arg1), (a_list.value = "true"))] >> !( - ch_p('=') >> ID[a_list.value = arg1])[phoenix::bind( - &definition::call_prop_actor)( - var(*this), a_list.key, a_list.value)], - !ch_p(',')); - - attr_list = +(ch_p('[') >> !a_list >> ch_p(']')); - - // RG - disregard port id's for now. - port_location = (ch_p(':') >> ID) - | (ch_p(':') >> ch_p('(') >> ID >> ch_p(',') >> ID - >> ch_p(')')); - - port_angle = ch_p('@') >> ID; - - port = port_location >> (!port_angle) - | port_angle >> (!port_location); - - node_id - = (ID[node_id.name = arg1] >> (!port))[phoenix::bind( - &definition::memoize_node)(var(*this))]; - - graph_stmt = (ID[graph_stmt.key = arg1] >> ch_p('=') - >> ID[graph_stmt.value = arg1])[phoenix::bind( - &definition::call_graph_prop)(var(*this), - graph_stmt.key, graph_stmt.value)]; // Graph property. - - attr_stmt - = (as_lower_d[keyword_p("graph")] >> attr_list(actor_t( - phoenix::bind(&definition::default_graph_prop)( - var(*this), arg1, arg2)))) - | (as_lower_d[keyword_p("node")] >> attr_list(actor_t( - phoenix::bind(&definition::default_node_prop)( - var(*this), arg1, arg2)))) - | (as_lower_d[keyword_p("edge")] >> attr_list(actor_t( - phoenix::bind(&definition::default_edge_prop)( - var(*this), arg1, arg2)))); - - // edge_head is set depending on the graph type - // (directed/undirected) - edgeop = ch_p('-') >> ch_p(boost::ref(edge_head)); - - edgeRHS = +(edgeop[((data_stmt.sources = data_stmt.dests), - (data_stmt.dests = construct_< nodes_t >()))] - >> (subgraph[data_stmt.dests = arg1] - | node_id[phoenix::bind(&definition::insert_node)( - var(*this), data_stmt.dests, arg1)]) - [phoenix::bind(&definition::activate_edge)( - var(*this), data_stmt.sources, data_stmt.dests, - var(edges), var(default_edge_props))]); - - // To avoid backtracking, edge, node, and subgraph - // statements are processed as one nonterminal. - data_stmt - = (subgraph[((data_stmt.dests - = arg1), // will get moved in rhs - (data_stmt.saw_node = false))] - | node_id[((phoenix::bind( - &definition::insert_node)( - var(*this), data_stmt.dests, arg1)), - (data_stmt.saw_node = true), -#ifdef BOOST_GRAPH_DEBUG - (std::cout << val("AcTive Node: ") << arg1 - << "\n"), -#endif // BOOST_GRAPH_DEBUG - (data_stmt.active_node = arg1))]) - >> if_p(edgeRHS)[!attr_list(actor_t(phoenix::bind( - &definition::edge_prop)( - var(*this), arg1, arg2)))] - .else_p[if_p(data_stmt.saw_node)[!attr_list( - actor_t(phoenix::bind( - &definition::node_prop)(var(*this), arg1, - arg2)))] // otherwise it's a subgraph, - // nothing more to do. - ]; - - stmt = graph_stmt | attr_stmt | data_stmt; - - stmt_list = *(stmt >> !ch_p(';')); - - subgraph = !(as_lower_d[keyword_p("subgraph")] - >> (!ID[((subgraph.name = arg1), - (subgraph.nodes - = (var(subgraph_nodes))[arg1]), - (subgraph.edges - = (var(subgraph_edges))[arg1]))])) - >> ch_p('{')[++var(subgraph_depth)] >> stmt_list - >> ch_p('}')[--var(subgraph_depth)] - [(var(subgraph_nodes))[subgraph.name] - = subgraph.nodes] - [(var(subgraph_edges))[subgraph.name] - = subgraph.edges] - - | as_lower_d[keyword_p("subgraph")] - >> ID[((subgraph.nodes - = (var(subgraph_nodes))[arg1]), - (subgraph.edges = (var(subgraph_edges))[arg1]))]; - - the_grammar = (!as_lower_d[keyword_p("strict")]) - >> (as_lower_d[keyword_p( - "graph")][((var(edge_head) = '-'), - (phoenix::bind(&definition::check_undirected)( - var(*this))))] - | as_lower_d[keyword_p( - "digraph")][((var(edge_head) = '>'), - (phoenix::bind(&definition::check_directed)( - var(*this))))]) - >> (!ID) >> ch_p('{') >> stmt_list >> ch_p('}'); - - } // definition() - - typedef boost::spirit::classic::rule< ScannerT > rule_t; - - rule_t const& start() const { return the_grammar; } - - // - // Semantic actions - // - - void check_undirected() - { - if (self.graph_.is_directed()) - boost::throw_exception(boost::undirected_graph_error()); - } - - void check_directed() - { - if (!self.graph_.is_directed()) - boost::throw_exception(boost::directed_graph_error()); - } - - void memoize_node() - { - id_t const& node = node_id.name(); - props_t& node_props = default_node_props; - - if (nodes.find(node) == nodes.end()) - { - nodes.insert(node); - self.graph_.do_add_vertex(node); - - node_map.insert(std::make_pair(node, ids_t())); - -#ifdef BOOST_GRAPH_DEBUG - std::cout << "Add new node " << node << std::endl; -#endif // BOOST_GRAPH_DEBUG - // Set the default properties for this edge - // RG: Here I would actually set the properties - for (props_t::iterator i = node_props.begin(); - i != node_props.end(); ++i) - { - set_node_property(node, i->first, i->second); - } - if (subgraph_depth > 0) - { - subgraph.nodes().insert(node); - // Set the subgraph's default properties as well - props_t& props - = subgraph_node_props[subgraph.name()]; - for (props_t::iterator i = props.begin(); - i != props.end(); ++i) - { - set_node_property(node, i->first, i->second); - } - } - } - else - { -#ifdef BOOST_GRAPH_DEBUG - std::cout << "See node " << node << std::endl; -#endif // BOOST_GRAPH_DEBUG - } - } - - void activate_edge(nodes_t& sources, nodes_t& dests, - edges_t& edges, props_t& edge_props) - { - edge_stack_t& edge_stack = data_stmt.edge_stack(); - for (nodes_t::iterator i = sources.begin(); - i != sources.end(); ++i) - { - for (nodes_t::iterator j = dests.begin(); - j != dests.end(); ++j) - { - // Create the edge and push onto the edge stack. -#ifdef BOOST_GRAPH_DEBUG - std::cout << "Edge " << *i << " to " << *j - << std::endl; -#endif // BOOST_GRAPH_DEBUG - - edge_t edge = edge_t::new_edge(); - edge_stack.push_back(edge); - edges.insert(edge); - edge_map.insert(std::make_pair(edge, ids_t())); - - // Add the real edge. - self.graph_.do_add_edge(edge, *i, *j); - - // Set the default properties for this edge - for (props_t::iterator k = edge_props.begin(); - k != edge_props.end(); ++k) - { - set_edge_property(edge, k->first, k->second); - } - if (subgraph_depth > 0) - { - subgraph.edges().insert(edge); - // Set the subgraph's default properties as well - props_t& props - = subgraph_edge_props[subgraph.name()]; - for (props_t::iterator k = props.begin(); - k != props.end(); ++k) - { - set_edge_property( - edge, k->first, k->second); - } - } - } - } - } - - // node_prop - Assign the property for the current active node. - void node_prop(id_t const& key, id_t const& value) - { - node_t& active_object = data_stmt.active_node(); - set_node_property(active_object, key, value); - } - - // edge_prop - Assign the property for the current active edges. - void edge_prop(id_t const& key, id_t const& value) - { - edge_stack_t const& active_edges_ = data_stmt.edge_stack(); - for (edge_stack_t::const_iterator i = active_edges_.begin(); - i != active_edges_.end(); ++i) - { - set_edge_property(*i, key, value); - } - } - - // default_graph_prop - Store as a graph property. - void default_graph_prop(id_t const& key, id_t const& value) - { -#ifdef BOOST_GRAPH_DEBUG - std::cout << key << " = " << value << std::endl; -#endif // BOOST_GRAPH_DEBUG - self.graph_.set_graph_property(key, value); - } - - // default_node_prop - declare default properties for any future - // new nodes - void default_node_prop(id_t const& key, id_t const& value) - { - nodes_t& nodes_ - = subgraph_depth == 0 ? nodes : subgraph.nodes(); - props_t& node_props_ = subgraph_depth == 0 - ? default_node_props - : subgraph_node_props[subgraph.name()]; - - // add this to the selected list of default node properties. - node_props_[key] = value; - // for each node, set its property to default-constructed - // value - // if it hasn't been set already. - // set the dynamic property map value - for (nodes_t::iterator i = nodes_.begin(); - i != nodes_.end(); ++i) - if (node_map[*i].find(key) == node_map[*i].end()) - { - set_node_property(*i, key, id_t()); - } - } - - // default_edge_prop - declare default properties for any future - // new edges - void default_edge_prop(id_t const& key, id_t const& value) - { - edges_t& edges_ - = subgraph_depth == 0 ? edges : subgraph.edges(); - props_t& edge_props_ = subgraph_depth == 0 - ? default_edge_props - : subgraph_edge_props[subgraph.name()]; - - // add this to the list of default edge properties. - edge_props_[key] = value; - // for each edge, set its property to be empty string - // set the dynamic property map value - for (edges_t::iterator i = edges_.begin(); - i != edges_.end(); ++i) - if (edge_map[*i].find(key) == edge_map[*i].end()) - set_edge_property(*i, key, id_t()); - } - - // helper function - void insert_node(nodes_t& nodes, id_t const& name) - { - nodes.insert(name); - } - - void call_prop_actor( - std::string const& lhs, std::string const& rhs) - { - actor_t& actor = attr_list.prop_actor(); - // If first and last characters of the rhs are - // double-quotes, remove them. - if (!rhs.empty() && rhs[0] == '"' - && rhs[rhs.size() - 1] == '"') - actor(lhs, rhs.substr(1, rhs.size() - 2)); - else - actor(lhs, rhs); - } - - void call_graph_prop( - std::string const& lhs, std::string const& rhs) - { - // If first and last characters of the rhs are - // double-quotes, remove them. - if (!rhs.empty() && rhs[0] == '"' - && rhs[rhs.size() - 1] == '"') - this->default_graph_prop( - lhs, rhs.substr(1, rhs.size() - 2)); - else - this->default_graph_prop(lhs, rhs); - } - - void set_node_property( - node_t const& node, id_t const& key, id_t const& value) - { - - // Add the property key to the "set" table to avoid default - // overwrite - node_map[node].insert(key); - // Set the user's property map - self.graph_.set_node_property(key, node, value); -#ifdef BOOST_GRAPH_DEBUG - // Tell the world - std::cout << node << ": " << key << " = " << value - << std::endl; -#endif // BOOST_GRAPH_DEBUG - } - - void set_edge_property( - edge_t const& edge, id_t const& key, id_t const& value) - { - - // Add the property key to the "set" table to avoid default - // overwrite - edge_map[edge].insert(key); - // Set the user's property map - self.graph_.set_edge_property(key, edge, value); -#ifdef BOOST_GRAPH_DEBUG - // Tell the world -#if 0 // RG - edge representation changed, - std::cout << "(" << edge.first << "," << edge.second << "): " -#else - std::cout << "an edge: " -#endif // 0 - << key << " = " << value << std::endl; -#endif // BOOST_GRAPH_DEBUG - } - - // Variables explicitly initialized - dot_grammar const& self; - // if subgraph_depth > 0, then we're processing a subgraph. - int subgraph_depth; - - // Keywords; - const boost::spirit::classic::distinct_parser<> keyword_p; - // - // rules that make up the grammar - // - boost::spirit::classic::rule< ScannerT, id_closure::context_t > - ID; - boost::spirit::classic::rule< ScannerT, - property_closure::context_t > - a_list; - boost::spirit::classic::rule< ScannerT, - attr_list_closure::context_t > - attr_list; - rule_t port_location; - rule_t port_angle; - rule_t port; - boost::spirit::classic::rule< ScannerT, - node_id_closure::context_t > - node_id; - boost::spirit::classic::rule< ScannerT, - property_closure::context_t > - graph_stmt; - rule_t attr_stmt; - boost::spirit::classic::rule< ScannerT, - data_stmt_closure::context_t > - data_stmt; - boost::spirit::classic::rule< ScannerT, - subgraph_closure::context_t > - subgraph; - rule_t edgeop; - rule_t edgeRHS; - rule_t stmt; - rule_t stmt_list; - rule_t the_grammar; - - // The grammar uses edge_head to dynamically set the syntax for - // edges directed graphs: edge_head = '>', and so edgeop = "->" - // undirected graphs: edge_head = '-', and so edgeop = "--" - char edge_head; - - // - // Support data structures - // - - nodes_t nodes; // list of node names seen - edges_t edges; // list of edges seen - node_map_t - node_map; // remember the properties set for each node - edge_map_t - edge_map; // remember the properties set for each edge - - subgraph_nodes_t subgraph_nodes; // per-subgraph lists of nodes - subgraph_edges_t subgraph_edges; // per-subgraph lists of edges - - props_t default_node_props; // global default node properties - props_t default_edge_props; // global default edge properties - subgraph_props_t - subgraph_node_props; // per-subgraph default node properties - subgraph_props_t - subgraph_edge_props; // per-subgraph default edge properties - }; // struct definition - }; // struct dot_grammar - - // - // dot_skipper - GraphViz whitespace and comment skipper - // - struct dot_skipper - : public boost::spirit::classic::grammar< dot_skipper > - { - dot_skipper() {} - - template < typename ScannerT > struct definition - { - definition(dot_skipper const& /*self*/) - { - using namespace boost::spirit::classic; - using namespace phoenix; - // comment forms - skip = eol_p >> comment_p("#") | space_p | comment_p("//") -#if BOOST_WORKAROUND(BOOST_MSVC, <= 1400) - | confix_p(str_p("/*"), *anychar_p, str_p("*/")) -#else - | confix_p("/*", *anychar_p, "*/") -#endif - ; - -#ifdef BOOST_SPIRIT_DEBUG - BOOST_SPIRIT_DEBUG_RULE(skip); -#endif - } - - boost::spirit::classic::rule< ScannerT > skip; - boost::spirit::classic::rule< ScannerT > const& start() const - { - return skip; - } - }; // definition - }; // dot_skipper - - } // namespace graph -} // namespace detail - -template < typename MultiPassIterator, typename MutableGraph > -bool read_graphviz_spirit(MultiPassIterator begin, MultiPassIterator end, - MutableGraph& graph, dynamic_properties& dp, - std::string const& node_id = "node_id") -{ - using namespace boost; - using namespace boost::spirit::classic; - - typedef MultiPassIterator iterator_t; - typedef skip_parser_iteration_policy< boost::detail::graph::dot_skipper > - iter_policy_t; - typedef scanner_policies< iter_policy_t > scanner_policies_t; - typedef scanner< iterator_t, scanner_policies_t > scanner_t; - - ::boost::detail::graph::mutate_graph_impl< MutableGraph > m_graph( - graph, dp, node_id); - - ::boost::detail::graph::dot_grammar p(m_graph); - ::boost::detail::graph::dot_skipper skip_p; - - iter_policy_t iter_policy(skip_p); - scanner_policies_t policies(iter_policy); - - scanner_t scan(begin, end, policies); - - bool ok = p.parse(scan); - m_graph.finish_building_graph(); - return ok; -} - -} // namespace boost - -#endif // BOOST_READ_GRAPHVIZ_SPIRIT_HPP diff --git a/include/boost/graph/dijkstra_shortest_paths.hpp b/include/boost/graph/dijkstra_shortest_paths.hpp index 9fbcfcce0..afaf0302d 100644 --- a/include/boost/graph/dijkstra_shortest_paths.hpp +++ b/include/boost/graph/dijkstra_shortest_paths.hpp @@ -22,11 +22,11 @@ #include #include #include +#include #include -#include +#include #include #include -#include #include #include #include @@ -237,7 +237,7 @@ namespace detail { typedef boost::iterator_property_map< Value*, IndexMap > type; static type build(const Graph& g, const IndexMap& index, - boost::scoped_array< Value >& array_holder) + std::unique_ptr< Value[] >& array_holder) { array_holder.reset(new Value[num_vertices(g)]); std::fill(array_holder.get(), array_holder.get() + num_vertices(g), @@ -251,7 +251,7 @@ namespace detail { typedef boost::vector_property_map< Value, IndexMap > type; static type build(const Graph& g, const IndexMap& index, - boost::scoped_array< Value >& array_holder) + std::unique_ptr< Value[] >& array_holder) { return boost::make_vector_property_map< Value >(index); } @@ -268,7 +268,7 @@ namespace detail helper; typedef typename helper::type type; static type build(const Graph& g, const IndexMap& index, - boost::scoped_array< Value >& array_holder) + std::unique_ptr< Value[] >& array_holder) { return helper::build(g, index, array_holder); } @@ -368,7 +368,7 @@ inline void dijkstra_shortest_paths_no_init(const Graph& g, typedef typename graph_traits< Graph >::vertex_descriptor Vertex; // Now the default: use a d-ary heap - boost::scoped_array< std::size_t > index_in_heap_map_holder; + std::unique_ptr< std::size_t[] > index_in_heap_map_holder; typedef detail::vertex_property_map_generator< Graph, IndexMap, std::size_t > IndexInHeapMapHelper; @@ -575,6 +575,4 @@ inline void dijkstra_shortest_paths(const VertexListGraph& g, } // namespace boost -#include BOOST_GRAPH_MPI_INCLUDE() - #endif // BOOST_GRAPH_DIJKSTRA_HPP diff --git a/include/boost/graph/dijkstra_shortest_paths_no_color_map.hpp b/include/boost/graph/dijkstra_shortest_paths_no_color_map.hpp index 09607c49a..54224ae04 100644 --- a/include/boost/graph/dijkstra_shortest_paths_no_color_map.hpp +++ b/include/boost/graph/dijkstra_shortest_paths_no_color_map.hpp @@ -15,7 +15,9 @@ #include #include #include +#include #include +#include namespace boost { @@ -51,7 +53,7 @@ void dijkstra_shortest_paths_no_color_map_no_init(const Graph& graph, DistanceCompare > VertexQueue; - boost::scoped_array< std::size_t > index_in_heap_map_holder; + std::unique_ptr< std::size_t[] > index_in_heap_map_holder; IndexInHeapMap index_in_heap = IndexInHeapMapHelper::build( graph, index_map, index_in_heap_map_holder); VertexQueue vertex_queue(distance_map, index_in_heap, distance_compare); diff --git a/include/boost/graph/dimacs.hpp b/include/boost/graph/dimacs.hpp index d6171d243..c309bf555 100644 --- a/include/boost/graph/dimacs.hpp +++ b/include/boost/graph/dimacs.hpp @@ -171,7 +171,7 @@ namespace graph protected: bool read_edge_line(char* linebuf, int& from, int& to, int& weight) { - char *fs = NULL, *ts = NULL, *ws = NULL; + char *fs = nullptr, *ts = nullptr, *ws = nullptr; char* tmp = linebuf + 2; fs = tmp; @@ -188,7 +188,7 @@ namespace graph tmp++; } *tmp = '\0'; - if (NULL == fs || NULL == ts) + if (fs == nullptr || ts == nullptr) return false; from = atoi(fs); to = atoi(ts); @@ -219,7 +219,7 @@ namespace graph while (*tmp != '\n' && *tmp != '\0') tmp++; *tmp = '\0'; - if (fs == NULL || ts == NULL || ws == NULL) + if (fs == nullptr || ts == nullptr || ws == nullptr) return false; from = atoi(fs); to = atoi(ts); diff --git a/include/boost/graph/directed_graph.hpp b/include/boost/graph/directed_graph.hpp index f40c1beb1..5c200b93b 100644 --- a/include/boost/graph/directed_graph.hpp +++ b/include/boost/graph/directed_graph.hpp @@ -12,7 +12,6 @@ #include #include #include -#include namespace boost { diff --git a/include/boost/graph/edge_list.hpp b/include/boost/graph/edge_list.hpp index 77c0c01ea..cfaba5b6f 100644 --- a/include/boost/graph/edge_list.hpp +++ b/include/boost/graph/edge_list.hpp @@ -13,8 +13,7 @@ #include #include -#include -#include +#include #include #include #include @@ -264,7 +263,7 @@ template < class Cat > struct is_random { RET = false }; - typedef mpl::false_ type; + typedef std::false_type type; }; template <> struct is_random< std::random_access_iterator_tag > { @@ -272,7 +271,7 @@ template <> struct is_random< std::random_access_iterator_tag > { RET = true }; - typedef mpl::true_ type; + typedef std::true_type type; }; // The edge_list class conditionally inherits from one of the @@ -287,7 +286,7 @@ template < class EdgeIter, class T, class D, class Cat > #endif class edge_list -: public mpl::if_< typename is_random< Cat >::type, +: public std::conditional< is_random< Cat >::type::value, edge_list_impl_ra< edge_list< EdgeIter, T, D, Cat >, EdgeIter, T, D >, edge_list_impl< edge_list< EdgeIter, T, D, Cat >, EdgeIter, T, D > >::type { diff --git a/include/boost/graph/erdos_renyi_generator.hpp b/include/boost/graph/erdos_renyi_generator.hpp index f5e33c963..7ec242e21 100644 --- a/include/boost/graph/erdos_renyi_generator.hpp +++ b/include/boost/graph/erdos_renyi_generator.hpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -207,7 +207,7 @@ class sorted_erdos_renyi_iterator src = (std::numeric_limits< vertices_size_type >::max)(); } - shared_ptr< uniform_01< RandomGenerator* > > gen; + std::shared_ptr< uniform_01< RandomGenerator* > > gen; geometric_distribution< vertices_size_type > rand_vertex; vertices_size_type n; bool allow_self_loops; diff --git a/include/boost/graph/fruchterman_reingold.hpp b/include/boost/graph/fruchterman_reingold.hpp index 5d60674cf..04b2566ad 100644 --- a/include/boost/graph/fruchterman_reingold.hpp +++ b/include/boost/graph/fruchterman_reingold.hpp @@ -14,7 +14,6 @@ #include #include #include // For topology concepts -#include #include #include #include // for std::min and std::max @@ -455,6 +454,4 @@ void fruchterman_reingold_force_directed_layout( } // end namespace boost -#include BOOST_GRAPH_MPI_INCLUDE() - #endif // BOOST_GRAPH_FRUCHTERMAN_REINGOLD_FORCE_DIRECTED_LAYOUT_HPP diff --git a/include/boost/graph/graph_concepts.hpp b/include/boost/graph/graph_concepts.hpp index c013ccd4c..0ff429016 100644 --- a/include/boost/graph/graph_concepts.hpp +++ b/include/boost/graph/graph_concepts.hpp @@ -21,8 +21,6 @@ #include #include #include -#include -#include #include #include @@ -78,11 +76,11 @@ BOOST_concept(IncidenceGraph, (G)) : Graph< G > typedef typename graph_traits< G >::out_edge_iterator out_edge_iterator; typedef typename graph_traits< G >::degree_size_type degree_size_type; typedef typename graph_traits< G >::traversal_category traversal_category; - - BOOST_STATIC_ASSERT( - (boost::mpl::not_< boost::is_same< out_edge_iterator, void > >::value)); - BOOST_STATIC_ASSERT( - (boost::mpl::not_< boost::is_same< degree_size_type, void > >::value)); + + static_assert(!boost::is_same< out_edge_iterator, void>::value, + "IncidenceGraph's out edge iterator must NOT be void"); + static_assert(!boost::is_same< degree_size_type , void>::value, + "IncidenceGraph's degree size type must NOT be void"); BOOST_CONCEPT_USAGE(IncidenceGraph) { @@ -125,9 +123,8 @@ BOOST_concept(BidirectionalGraph, (G)) : IncidenceGraph< G > BOOST_CONCEPT_ASSERT((MultiPassInputIterator< in_edge_iterator >)); BOOST_CONCEPT_ASSERT( (Convertible< traversal_category, bidirectional_graph_tag >)); - - BOOST_STATIC_ASSERT((boost::mpl::not_< - boost::is_same< in_edge_iterator, void > >::value)); + static_assert(!boost::is_same< in_edge_iterator, void>::value, + "BidirectionalGraph's in edge iterator must NOT be void"); p = in_edges(v, g); n = in_degree(v, g); @@ -159,9 +156,9 @@ BOOST_concept(AdjacencyGraph, (G)) : Graph< G > BOOST_CONCEPT_ASSERT((MultiPassInputIterator< adjacency_iterator >)); BOOST_CONCEPT_ASSERT( (Convertible< traversal_category, adjacency_graph_tag >)); - - BOOST_STATIC_ASSERT((boost::mpl::not_< - boost::is_same< adjacency_iterator, void > >::value)); + + static_assert(!boost::is_same< adjacency_iterator, void>::value , + "AdjacencyGraph's adjacency iterator must NOT be void"); p = adjacent_vertices(v, g); v = *p.first; @@ -184,11 +181,11 @@ BOOST_concept(VertexListGraph, (G)) : Graph< G > BOOST_CONCEPT_ASSERT((MultiPassInputIterator< vertex_iterator >)); BOOST_CONCEPT_ASSERT( (Convertible< traversal_category, vertex_list_graph_tag >)); - - BOOST_STATIC_ASSERT((boost::mpl::not_< - boost::is_same< vertex_iterator, void > >::value)); - BOOST_STATIC_ASSERT((boost::mpl::not_< - boost::is_same< vertices_size_type, void > >::value)); + + static_assert(!boost::is_same< vertex_iterator, void>::value , + "VertexListGraph's vertex iterator must NOT be void"); + static_assert(!boost::is_same< vertices_size_type, void>::value, + "VertexListGraph's vertex size type must NOT be void"); #ifdef BOOST_VECTOR_AS_GRAPH_GRAPH_ADL_HACK // dwa 2003/7/11 -- This clearly shouldn't be necessary, but if @@ -238,11 +235,11 @@ BOOST_concept(EdgeListGraph, (G)) : Graph< G > BOOST_CONCEPT_ASSERT((Assignable< edge_descriptor >)); BOOST_CONCEPT_ASSERT( (Convertible< traversal_category, edge_list_graph_tag >)); - - BOOST_STATIC_ASSERT( - (boost::mpl::not_< boost::is_same< edge_iterator, void > >::value)); - BOOST_STATIC_ASSERT((boost::mpl::not_< - boost::is_same< edges_size_type, void > >::value)); + + static_assert(!boost::is_same< edge_iterator, void>::value, + "EdgeListGraph's edge iterator must NOT be void"); + static_assert(!boost::is_same< edges_size_type , void>::value, + "EdgeListGraph's edge size type must NOT be void"); p = edges(g); e = *p.first; @@ -304,9 +301,9 @@ BOOST_concept(VertexMutableGraph, (G)) BOOST_concept(MutableGraph, (G)) : EdgeMutableGraph< G >, VertexMutableGraph< G > {}; -template < class edge_descriptor > struct dummy_edge_predicate +template < class EdgeDescriptor > struct dummy_edge_predicate { - bool operator()(const edge_descriptor&) const { return false; } + bool operator()(const EdgeDescriptor&) const { return false; } }; BOOST_concept(MutableIncidenceGraph, (G)) : MutableGraph< G > diff --git a/include/boost/graph/graph_mutability_traits.hpp b/include/boost/graph/graph_mutability_traits.hpp index 064f32ff3..eb6526680 100644 --- a/include/boost/graph/graph_mutability_traits.hpp +++ b/include/boost/graph/graph_mutability_traits.hpp @@ -8,9 +8,7 @@ #define BOOST_GRAPH_MUTABILITY_TRAITS_HPP #include -#include -#include -#include +#include #include #include @@ -90,7 +88,7 @@ template < typename Graph > struct graph_mutability_traits template < typename Graph > struct graph_has_add_vertex -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_mutability_traits< Graph >::category, add_vertex_tag >::value > { @@ -98,7 +96,7 @@ struct graph_has_add_vertex template < typename Graph > struct graph_has_add_vertex_with_property -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_mutability_traits< Graph >::category, add_vertex_property_tag >::value > { @@ -106,7 +104,7 @@ struct graph_has_add_vertex_with_property template < typename Graph > struct graph_has_remove_vertex -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_mutability_traits< Graph >::category, remove_vertex_tag >::value > { @@ -114,7 +112,7 @@ struct graph_has_remove_vertex template < typename Graph > struct graph_has_add_edge -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_mutability_traits< Graph >::category, add_edge_tag >::value > { @@ -122,7 +120,7 @@ struct graph_has_add_edge template < typename Graph > struct graph_has_add_edge_with_property -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_mutability_traits< Graph >::category, add_edge_property_tag >::value > { @@ -130,7 +128,7 @@ struct graph_has_add_edge_with_property template < typename Graph > struct graph_has_remove_edge -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_mutability_traits< Graph >::category, remove_edge_tag >::value > { @@ -138,46 +136,55 @@ struct graph_has_remove_edge template < typename Graph > struct is_mutable_vertex_graph -: mpl::and_< graph_has_add_vertex< Graph >, graph_has_remove_vertex< Graph > > +: std::integral_constant< bool, + graph_has_add_vertex< Graph >::value + && graph_has_remove_vertex< Graph >::value > { }; template < typename Graph > struct is_mutable_vertex_property_graph -: mpl::and_< graph_has_add_vertex_with_property< Graph >, - graph_has_remove_vertex< Graph > > +: std::integral_constant< bool, + graph_has_add_vertex_with_property< Graph >::value + && graph_has_remove_vertex< Graph >::value > { }; template < typename Graph > struct is_mutable_edge_graph -: mpl::and_< graph_has_add_edge< Graph >, graph_has_remove_edge< Graph > > +: std::integral_constant< bool, + graph_has_add_edge< Graph >::value + && graph_has_remove_edge< Graph >::value > { }; template < typename Graph > struct is_mutable_edge_property_graph -: mpl::and_< graph_has_add_edge_with_property< Graph >, - graph_has_remove_edge< Graph > > +: std::integral_constant< bool, + graph_has_add_edge_with_property< Graph >::value + && graph_has_remove_edge< Graph >::value > { }; template < typename Graph > struct is_mutable_graph -: mpl::and_< is_mutable_vertex_graph< Graph >, is_mutable_edge_graph< Graph > > +: std::integral_constant< bool, + is_mutable_vertex_graph< Graph >::value + && is_mutable_edge_graph< Graph >::value > { }; template < typename Graph > struct is_mutable_property_graph -: mpl::and_< is_mutable_vertex_property_graph< Graph >, - is_mutable_edge_property_graph< Graph > > +: std::integral_constant< bool, + is_mutable_vertex_property_graph< Graph >::value + && is_mutable_edge_property_graph< Graph >::value > { }; template < typename Graph > struct is_add_only_property_graph -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_mutability_traits< Graph >::category, add_only_property_graph_tag >::value > { diff --git a/include/boost/graph/graph_selectors.hpp b/include/boost/graph/graph_selectors.hpp index e37210d09..b7ba91272 100644 --- a/include/boost/graph/graph_selectors.hpp +++ b/include/boost/graph/graph_selectors.hpp @@ -10,7 +10,7 @@ #ifndef BOOST_GRAPH_SELECTORS_HPP #define BOOST_GRAPH_SELECTORS_HPP -#include +#include namespace boost { @@ -26,8 +26,8 @@ struct directedS is_directed = true, is_bidir = false }; - typedef mpl::true_ is_directed_t; - typedef mpl::false_ is_bidir_t; + using is_directed_t = std::true_type; + using is_bidir_t = std::false_type; }; struct undirectedS { @@ -36,8 +36,8 @@ struct undirectedS is_directed = false, is_bidir = false }; - typedef mpl::false_ is_directed_t; - typedef mpl::false_ is_bidir_t; + using is_directed_t = std::false_type; + using is_bidir_t = std::false_type; }; struct bidirectionalS { @@ -46,8 +46,8 @@ struct bidirectionalS is_directed = true, is_bidir = true }; - typedef mpl::true_ is_directed_t; - typedef mpl::true_ is_bidir_t; + using is_directed_t = std::true_type; + using is_bidir_t = std::true_type; }; } // namespace boost diff --git a/include/boost/graph/graph_traits.hpp b/include/boost/graph/graph_traits.hpp index ea8652172..06dd01a70 100644 --- a/include/boost/graph/graph_traits.hpp +++ b/include/boost/graph/graph_traits.hpp @@ -14,15 +14,9 @@ #include #include /* Primarily for std::pair */ #include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include #include #include #include @@ -33,16 +27,18 @@ namespace boost namespace detail { -#define BOOST_GRAPH_MEMBER_OR_VOID(name) \ - BOOST_MPL_HAS_XXX_TRAIT_DEF(name) \ - template < typename T > struct BOOST_JOIN(get_member_, name) \ - { \ - typedef typename T::name type; \ - }; \ - template < typename T > \ - struct BOOST_JOIN(get_opt_member_, name) \ - : boost::mpl::eval_if_c< BOOST_JOIN(has_, name) < T >::value, BOOST_JOIN(get_member_, name)< T >, boost::mpl::identity< void > >\ - { \ +// get_opt_member_##name::type is T::name when that member type exists, void otherwise. +#define BOOST_GRAPH_MEMBER_OR_VOID(name) \ + template < typename T, typename = void > \ + struct BOOST_JOIN(get_opt_member_, name) \ + { \ + using type = void; \ + }; \ + template < typename T > \ + struct BOOST_JOIN(get_opt_member_, name)< T, \ + boost::void_t< typename T::name > > \ + { \ + using type = typename T::name; \ }; BOOST_GRAPH_MEMBER_OR_VOID(adjacency_iterator) BOOST_GRAPH_MEMBER_OR_VOID(out_edge_iterator) @@ -122,7 +118,7 @@ namespace graph_detail { template < typename Tag > struct is_directed_tag - : mpl::bool_< is_convertible< Tag, directed_tag >::value > + : std::integral_constant< bool, is_convertible< Tag, directed_tag >::value > { }; } // namespace graph_detail @@ -135,7 +131,8 @@ struct is_directed_graph }; template < typename Graph > -struct is_undirected_graph : mpl::not_< is_directed_graph< Graph > > +struct is_undirected_graph +: std::integral_constant< bool, !is_directed_graph< Graph >::value > { }; //@} @@ -170,8 +167,9 @@ template < typename Graph > bool allows_parallel_edges(const Graph&) */ template < typename Graph > struct is_multigraph -: mpl::bool_< is_same< typename graph_traits< Graph >::edge_parallel_category, - allow_parallel_edge_tag >::value > +: std::integral_constant< bool, + is_same< typename graph_traits< Graph >::edge_parallel_category, + allow_parallel_edge_tag >::value > { }; //@} @@ -218,7 +216,7 @@ struct distributed_edge_list_graph_tag //@{ template < typename Graph > struct is_incidence_graph -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_traits< Graph >::traversal_category, incidence_graph_tag >::value > { @@ -226,7 +224,7 @@ struct is_incidence_graph template < typename Graph > struct is_bidirectional_graph -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_traits< Graph >::traversal_category, bidirectional_graph_tag >::value > { @@ -234,7 +232,7 @@ struct is_bidirectional_graph template < typename Graph > struct is_vertex_list_graph -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_traits< Graph >::traversal_category, vertex_list_graph_tag >::value > { @@ -242,7 +240,7 @@ struct is_vertex_list_graph template < typename Graph > struct is_edge_list_graph -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_traits< Graph >::traversal_category, edge_list_graph_tag >::value > { @@ -250,7 +248,7 @@ struct is_edge_list_graph template < typename Graph > struct is_adjacency_matrix -: mpl::bool_< +: std::integral_constant< bool, is_convertible< typename graph_traits< Graph >::traversal_category, adjacency_matrix_tag >::value > { @@ -265,14 +263,17 @@ struct is_adjacency_matrix //@{ template < typename Graph > struct is_directed_unidirectional_graph -: mpl::and_< is_directed_graph< Graph >, - mpl::not_< is_bidirectional_graph< Graph > > > +: std::integral_constant< bool, + is_directed_graph< Graph >::value + && !is_bidirectional_graph< Graph >::value > { }; template < typename Graph > struct is_directed_bidirectional_graph -: mpl::and_< is_directed_graph< Graph >, is_bidirectional_graph< Graph > > +: std::integral_constant< bool, + is_directed_graph< Graph >::value + && is_bidirectional_graph< Graph >::value > { }; //@} @@ -282,40 +283,47 @@ typedef boost::forward_traversal_tag multi_pass_input_iterator_tag; namespace detail { - BOOST_MPL_HAS_XXX_TRAIT_DEF(graph_property_type) - BOOST_MPL_HAS_XXX_TRAIT_DEF(edge_property_type) - BOOST_MPL_HAS_XXX_TRAIT_DEF(vertex_property_type) - - template < typename G > struct get_graph_property_type + // When the member type is present these expose it as ::type + // when absent they inherit no_property and expose no nested ::type. + template < typename G, typename = void > + struct get_graph_property_type : no_property + { + }; + template < typename G > + struct get_graph_property_type< G, boost::void_t< typename G::graph_property_type > > + { + using type = typename G::graph_property_type; + }; + template < typename G, typename = void > + struct get_edge_property_type : no_property + { + }; + template < typename G > + struct get_edge_property_type< G, boost::void_t< typename G::edge_property_type > > { - typedef typename G::graph_property_type type; + using type = typename G::edge_property_type; }; - template < typename G > struct get_edge_property_type + template < typename G, typename = void > + struct get_vertex_property_type : no_property { - typedef typename G::edge_property_type type; }; - template < typename G > struct get_vertex_property_type + template < typename G > + struct get_vertex_property_type< G, boost::void_t< typename G::vertex_property_type > > { - typedef typename G::vertex_property_type type; + using type = typename G::vertex_property_type; }; } template < typename G > -struct graph_property_type -: boost::mpl::eval_if< detail::has_graph_property_type< G >, - detail::get_graph_property_type< G >, no_property > +struct graph_property_type : detail::get_graph_property_type< G > { }; template < typename G > -struct edge_property_type -: boost::mpl::eval_if< detail::has_edge_property_type< G >, - detail::get_edge_property_type< G >, no_property > +struct edge_property_type : detail::get_edge_property_type< G > { }; template < typename G > -struct vertex_property_type -: boost::mpl::eval_if< detail::has_vertex_property_type< G >, - detail::get_vertex_property_type< G >, no_property > +struct vertex_property_type : detail::get_vertex_property_type< G > { }; @@ -341,7 +349,8 @@ namespace graph template < typename Graph, typename Descriptor > class bundled_result { typedef typename graph_traits< Graph >::vertex_descriptor Vertex; - typedef typename mpl::if_c< (is_same< Descriptor, Vertex >::value), + typedef typename std::conditional< + (is_same< Descriptor, Vertex >::value), vertex_bundle_type< Graph >, edge_bundle_type< Graph > >::type bundler; @@ -367,7 +376,8 @@ namespace graph_detail // A helper metafunction for determining whether or not a type is // bundled. template < typename T > - struct is_no_bundle : mpl::bool_< is_same< T, no_property >::value > + struct is_no_bundle + : std::integral_constant< bool, is_same< T, no_property >::value > { }; } // namespace graph_detail @@ -380,43 +390,49 @@ namespace graph_detail //@{ template < typename Graph > struct has_graph_property -: mpl::not_< typename detail::is_no_property< - typename graph_property_type< Graph >::type >::type >::type +: std::integral_constant< bool, + !detail::is_no_property< + typename graph_property_type< Graph >::type >::value > { }; template < typename Graph > struct has_bundled_graph_property -: mpl::not_< - graph_detail::is_no_bundle< typename graph_bundle_type< Graph >::type > > +: std::integral_constant< bool, + !graph_detail::is_no_bundle< + typename graph_bundle_type< Graph >::type >::value > { }; template < typename Graph > struct has_vertex_property -: mpl::not_< typename detail::is_no_property< - typename vertex_property_type< Graph >::type > >::type +: std::integral_constant< bool, + !detail::is_no_property< + typename vertex_property_type< Graph >::type >::value > { }; template < typename Graph > struct has_bundled_vertex_property -: mpl::not_< - graph_detail::is_no_bundle< typename vertex_bundle_type< Graph >::type > > +: std::integral_constant< bool, + !graph_detail::is_no_bundle< + typename vertex_bundle_type< Graph >::type >::value > { }; template < typename Graph > struct has_edge_property -: mpl::not_< typename detail::is_no_property< - typename edge_property_type< Graph >::type > >::type +: std::integral_constant< bool, + !detail::is_no_property< + typename edge_property_type< Graph >::type >::value > { }; template < typename Graph > struct has_bundled_edge_property -: mpl::not_< - graph_detail::is_no_bundle< typename edge_bundle_type< Graph >::type > > +: std::integral_constant< bool, + !graph_detail::is_no_bundle< + typename edge_bundle_type< Graph >::type >::value > { }; //@} diff --git a/include/boost/graph/graphml.hpp b/include/boost/graph/graphml.hpp index 8c57e1da1..1be775bbd 100644 --- a/include/boost/graph/graphml.hpp +++ b/include/boost/graph/graphml.hpp @@ -15,18 +15,14 @@ #include #include #include +#include +#include #include #include #include #include #include - -#include -#include -#include -#include #include -#include #include #include #include @@ -111,7 +107,7 @@ template < typename MutableGraph > class mutate_graph_impl : public mutate_graph bool type_found = false; try { - mpl::for_each< value_types >( + mp11::mp_for_each< value_types >( put_property< MutableGraph*, value_types >(name, m_dp, &m_g, value, value_type, m_type_names, type_found)); } @@ -133,7 +129,7 @@ template < typename MutableGraph > class mutate_graph_impl : public mutate_graph bool type_found = false; try { - mpl::for_each< value_types >( + mp11::mp_for_each< value_types >( put_property< vertex_descriptor, value_types >(name, m_dp, any_cast< vertex_descriptor >(vertex), value, value_type, m_type_names, type_found)); @@ -156,7 +152,7 @@ template < typename MutableGraph > class mutate_graph_impl : public mutate_graph bool type_found = false; try { - mpl::for_each< value_types >( + mp11::mp_for_each< value_types >( put_property< edge_descriptor, value_types >(name, m_dp, any_cast< edge_descriptor >(edge), value, value_type, m_type_names, type_found)); @@ -192,8 +188,7 @@ template < typename MutableGraph > class mutate_graph_impl : public mutate_graph template < class Value > void operator()(Value) { if (m_value_type - == m_type_names[mpl::find< ValueVector, - Value >::type::pos::value]) + == m_type_names[mp11::mp_find< ValueVector, Value >::value]) { put(m_name, m_dp, m_key, lexical_cast< Value >(m_value)); m_type_found = true; @@ -213,8 +208,7 @@ template < typename MutableGraph > class mutate_graph_impl : public mutate_graph protected: MutableGraph& m_g; dynamic_properties& m_dp; - typedef mpl::vector< bool, int, long, float, double, std::string > - value_types; + using value_types = mp11::mp_list< bool, int, long, float, double, std::string >; static const char* m_type_names[]; }; @@ -244,8 +238,7 @@ template < typename Types > class get_type_name template < typename Type > void operator()(Type) { if (typeid(Type) == m_type) - m_type_name - = m_type_names[mpl::find< Types, Type >::type::pos::value]; + m_type_name = m_type_names[mp11::mp_find< Types, Type >::value]; } private: @@ -254,6 +247,42 @@ template < typename Types > class get_type_name std::string& m_type_name; }; +namespace detail +{ + namespace graphml + { + // Replace <, >, &, ", ' with their XML character entities when writing + // element text. This reproduces the behaviour of the encode_char_entities + // helper Boost.PropertyTree used to provide, so that write_graphml output + // is unchanged. A string made up entirely of spaces has its first space + // written as so the value survives whitespace trimming on read-back. + inline std::string encode_char_entities(const std::string& s) + { + if (s.empty()) + return s; + + if (s.find_first_not_of(' ') == std::string::npos) + return " " + std::string(s.size() - 1, ' '); + + std::string r; + r.reserve(s.size()); + for (char c : s) + { + switch (c) + { + case '<': r += "<"; break; + case '>': r += ">"; break; + case '&': r += "&"; break; + case '"': r += """; break; + case '\'': r += "'"; break; + default: r += c; break; + } + } + return r; + } + } +} + template < typename Graph, typename VertexIndexMap > void write_graphml(std::ostream& out, const Graph& g, VertexIndexMap vertex_index, const dynamic_properties& dp, @@ -263,7 +292,7 @@ void write_graphml(std::ostream& out, const Graph& g, typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor; typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor; - using boost::property_tree::xml_parser::encode_char_entities; + using boost::detail::graphml::encode_char_entities; BOOST_STATIC_CONSTANT(bool, graph_is_directed @@ -275,10 +304,9 @@ void write_graphml(std::ostream& out, const Graph& g, "xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns " "http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">\n"; - typedef mpl::vector< bool, short, unsigned short, int, unsigned int, long, - unsigned long, long long, unsigned long long, float, double, - long double, std::string > - value_types; + using value_types = mp11::mp_list< bool, short, + unsigned short, int, unsigned int, long, unsigned long, long long, + unsigned long long, float, double, long double, std::string >; const char* type_names[] = { "boolean", "int", "int", "int", "int", "long", "long", "long", "long", "float", "double", "double", "string" }; std::map< std::string, std::string > graph_key_ids; @@ -299,8 +327,9 @@ void write_graphml(std::ostream& out, const Graph& g, else continue; std::string type_name = "string"; - mpl::for_each< value_types >(get_type_name< value_types >( - i->second->value(), type_names, type_name)); + mp11::mp_for_each< value_types >( + get_type_name< value_types >( + i->second->value(), type_names, type_name)); out << " second->key() == typeid(Graph*) ? "graph" diff --git a/include/boost/graph/graphviz.hpp b/include/boost/graph/graphviz.hpp index 4b7bd00c5..029a46e36 100644 --- a/include/boost/graph/graphviz.hpp +++ b/include/boost/graph/graphviz.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -28,13 +29,9 @@ #include #include #include -#include -#include +#include #include #include -#include -#include -#include namespace boost { @@ -57,19 +54,69 @@ struct default_writer template < class VorE > void operator()(std::ostream&, const VorE&) const {} }; +namespace detail +{ + + inline bool dot_id_is_alpha(char c) + { + return c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + } + + inline bool dot_id_is_digit(char c) { return c >= '0' && c <= '9'; } + + inline bool dot_id_is_word(char c) + { + return dot_id_is_alpha(c) || dot_id_is_digit(c); + } + + // True when s matches the DOT grammar for an ID that needs no quoting: + // identifier [A-Za-z_][A-Za-z0-9_]* + // numeral -?( .[0-9]* | [0-9]+(.[0-9]*)? ) + inline bool is_dot_unquoted_id(const std::string& s) + { + using size_type = std::string::size_type; + if (s.empty()) + return false; + if (dot_id_is_alpha(s[0])) + { + for (size_type i = 1; i < s.size(); ++i) + if (!dot_id_is_word(s[i])) + return false; + return true; + } + size_type i = 0; + if (s[i] == '-') + ++i; + if (i >= s.size()) + return false; + if (s[i] != '.' && !dot_id_is_digit(s[i])) + return false; + if (dot_id_is_digit(s[i])) + while (i < s.size() && dot_id_is_digit(s[i])) + ++i; + if (i < s.size() && s[i] == '.') + ++i; + for (; i < s.size(); ++i) + if (!dot_id_is_digit(s[i])) + return false; + return true; + } + +} // namespace detail + template < typename T > inline std::string escape_dot_string(const T& obj) { - using namespace boost::xpressive; - static sregex valid_unquoted_id = (((alpha | '_') >> *_w) - | (!as_xpr('-') >> (('.' >> *_d) | (+_d >> !('.' >> *_d))))); std::string s(boost::lexical_cast< std::string >(obj)); - if (regex_match(s, valid_unquoted_id)) + if (detail::is_dot_unquoted_id(s)) { return s; } else { - boost::algorithm::replace_all(s, "\"", "\\\""); + for (auto pos = s.find('"'); pos != std::string::npos; pos = s.find('"', pos + 2)) + { + s.insert(pos, 1, '\\'); + } return "\"" + s + "\""; } } @@ -843,13 +890,13 @@ namespace detail edge_permutation_from_sorting[temp[e]] = e; } typedef boost::tuple< id_t, bgl_vertex_t, id_t > v_prop; - BOOST_FOREACH (const v_prop& t, vertex_props) + for (const v_prop& t : vertex_props) { put(boost::get< 0 >(t), dp_, boost::get< 1 >(t), boost::get< 2 >(t)); } typedef boost::tuple< id_t, bgl_edge_t, id_t > e_prop; - BOOST_FOREACH (const e_prop& t, edge_props) + for (const e_prop& t : edge_props) { put(boost::get< 0 >(t), dp_, edge_permutation_from_sorting[boost::get< 1 >(t)], @@ -925,14 +972,14 @@ namespace detail } } // end namespace boost::detail::graph +// BOOST_GRAPH_USE_SPIRIT_PARSER deprecated and will be removed in 1.95 #ifdef BOOST_GRAPH_USE_SPIRIT_PARSER -#ifndef BOOST_GRAPH_READ_GRAPHVIZ_ITERATORS -#define BOOST_GRAPH_READ_GRAPHVIZ_ITERATORS +BOOST_PRAGMA_MESSAGE( + "BOOST_GRAPH_USE_SPIRIT_PARSER has no longer any effect and will be removed in 1.95. " + "the Boost.Spirit read_graphviz parser has been removed" + "read_graphviz now always uses the default parser.") #endif -#include -#else // New default parser #include -#endif // BOOST_GRAPH_USE_SPIRIT_PARSER namespace boost { @@ -942,11 +989,7 @@ template < typename MutableGraph > bool read_graphviz(const std::string& data, MutableGraph& graph, dynamic_properties& dp, std::string const& node_id = "node_id") { -#ifdef BOOST_GRAPH_USE_SPIRIT_PARSER - return read_graphviz_spirit(data.begin(), data.end(), graph, dp, node_id); -#else // Non-Spirit parser return read_graphviz_new(data, graph, dp, node_id); -#endif } // Parse the passed iterator range as a GraphViz dot file. @@ -955,18 +998,8 @@ bool read_graphviz(InputIterator user_first, InputIterator user_last, MutableGraph& graph, dynamic_properties& dp, std::string const& node_id = "node_id") { -#ifdef BOOST_GRAPH_USE_SPIRIT_PARSER - typedef InputIterator is_t; - typedef boost::spirit::classic::multi_pass< is_t > iterator_t; - - iterator_t first(boost::spirit::classic::make_multi_pass(user_first)); - iterator_t last(boost::spirit::classic::make_multi_pass(user_last)); - - return read_graphviz_spirit(first, last, graph, dp, node_id); -#else // Non-Spirit parser return read_graphviz_new( std::string(user_first, user_last), graph, dp, node_id); -#endif } // Parse the passed stream as a GraphViz dot file. @@ -981,6 +1014,4 @@ bool read_graphviz(std::istream& in, MutableGraph& graph, } // namespace boost -#include BOOST_GRAPH_MPI_INCLUDE() - #endif // BOOST_GRAPHVIZ_HPP diff --git a/include/boost/graph/gursoy_atun_layout.hpp b/include/boost/graph/gursoy_atun_layout.hpp index 1a8709b17..613ea5b1b 100644 --- a/include/boost/graph/gursoy_atun_layout.hpp +++ b/include/boost/graph/gursoy_atun_layout.hpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff --git a/include/boost/graph/hawick_circuits.hpp b/include/boost/graph/hawick_circuits.hpp index cefd6a13a..a26f7b8ba 100644 --- a/include/boost/graph/hawick_circuits.hpp +++ b/include/boost/graph/hawick_circuits.hpp @@ -9,18 +9,18 @@ #include #include -#include #include #include #include -#include #include #include #include #include +#include #include // for boost::tie #include #include +#include // for std::reference_wrapper #include #include // for std::pair #include @@ -48,11 +48,11 @@ namespace hawick_circuits_detail template < typename Vertex, typename Graph > typename result< get_all_adjacent_vertices( - BOOST_FWD_REF(Vertex), BOOST_FWD_REF(Graph)) >::type - operator()(BOOST_FWD_REF(Vertex) v, BOOST_FWD_REF(Graph) g) const + Vertex&&, Graph&&) >::type + operator()(Vertex&& v, Graph&& g) const { return adjacent_vertices( - boost::forward< Vertex >(v), boost::forward< Graph >(g)); + std::forward< Vertex >(v), std::forward< Graph >(g)); } }; @@ -89,6 +89,16 @@ namespace hawick_circuits_detail return std::find(boost::begin(c), boost::end(c), v) != boost::end(c); } + template < typename T > + struct unwrap_reference_wrapper { + typedef T type; + }; + + template < typename T > + struct unwrap_reference_wrapper > { + typedef T& type; + }; + /*! * @internal * Algorithm finding all the cycles starting from a given vertex. @@ -134,7 +144,7 @@ namespace hawick_circuits_detail // documented above. bool blocked_map_starts_all_unblocked() const { - BOOST_FOREACH (Vertex v, vertices(graph_)) + for (Vertex v : boost::make_iterator_range(vertices(graph_))) if (is_blocked(v)) return false; return true; @@ -144,7 +154,7 @@ namespace hawick_circuits_detail // sharing data structures between iterations does not break the code. bool all_closed_rows_are_empty() const { - BOOST_FOREACH (typename ClosedMatrix::reference row, closed_) + for (typename ClosedMatrix::reference row : closed_) if (!row.empty()) return false; return true; @@ -314,8 +324,9 @@ namespace hawick_circuits_detail typedef std::vector< Vertex > Stack; typedef std::vector< std::vector< Vertex > > ClosedMatrix; + typedef typename unwrap_reference_wrapper::type VisitorNoRef; - typedef hawick_circuits_from< Graph, Visitor, VertexIndexMap, Stack, + typedef hawick_circuits_from< Graph, VisitorNoRef, VertexIndexMap, Stack, ClosedMatrix, GetAdjacentVertices > SubAlgorithm; @@ -347,34 +358,34 @@ namespace hawick_circuits_detail template < typename GetAdjacentVertices, typename Graph, typename Visitor > void call_hawick_circuits( - Graph const& graph, BOOST_FWD_REF(Visitor) visitor, + Graph const& graph, Visitor&& visitor, unsigned int max_length) { call_hawick_circuits< GetAdjacentVertices >(graph, - boost::forward< Visitor >(visitor), get(vertex_index, graph), + std::forward< Visitor >(visitor), get(vertex_index, graph), max_length); } } // end namespace hawick_circuits_detail //! Enumerate all the elementary circuits in a directed multigraph. template < typename Graph, typename Visitor, typename VertexIndexMap > -void hawick_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor, - BOOST_FWD_REF(VertexIndexMap) vertex_index_map, +void hawick_circuits(Graph&& graph, Visitor&& visitor, + VertexIndexMap&& vertex_index_map, unsigned int max_length = 0) { hawick_circuits_detail::call_hawick_circuits< hawick_circuits_detail::get_all_adjacent_vertices >( - boost::forward< Graph >(graph), boost::forward< Visitor >(visitor), - boost::forward< VertexIndexMap >(vertex_index_map), max_length); + std::forward< Graph >(graph), std::forward< Visitor >(visitor), + std::forward< VertexIndexMap >(vertex_index_map), max_length); } template < typename Graph, typename Visitor > -void hawick_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor, +void hawick_circuits(Graph&& graph, Visitor&& visitor, unsigned int max_length = 0) { hawick_circuits_detail::call_hawick_circuits< hawick_circuits_detail::get_all_adjacent_vertices >( - boost::forward< Graph >(graph), boost::forward< Visitor >(visitor), + std::forward< Graph >(graph), std::forward< Visitor >(visitor), max_length); } @@ -383,25 +394,25 @@ void hawick_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor, * edges will not be considered. Each circuit will be considered only once. */ template < typename Graph, typename Visitor, typename VertexIndexMap > -void hawick_unique_circuits(BOOST_FWD_REF(Graph) graph, - BOOST_FWD_REF(Visitor) visitor, - BOOST_FWD_REF(VertexIndexMap) vertex_index_map, +void hawick_unique_circuits(Graph&& graph, + Visitor&& visitor, + VertexIndexMap&& vertex_index_map, unsigned int max_length = 0) { hawick_circuits_detail::call_hawick_circuits< hawick_circuits_detail::get_unique_adjacent_vertices >( - boost::forward< Graph >(graph), boost::forward< Visitor >(visitor), - boost::forward< VertexIndexMap >(vertex_index_map), max_length); + std::forward< Graph >(graph), std::forward< Visitor >(visitor), + std::forward< VertexIndexMap >(vertex_index_map), max_length); } template < typename Graph, typename Visitor > void hawick_unique_circuits( - BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor, + Graph&& graph, Visitor&& visitor, unsigned int max_length = 0) { hawick_circuits_detail::call_hawick_circuits< hawick_circuits_detail::get_unique_adjacent_vertices >( - boost::forward< Graph >(graph), boost::forward< Visitor >(visitor), + std::forward< Graph >(graph), std::forward< Visitor >(visitor), max_length); } } // end namespace boost diff --git a/include/boost/graph/howard_cycle_ratio.hpp b/include/boost/graph/howard_cycle_ratio.hpp index 00912d5c5..5e1128462 100644 --- a/include/boost/graph/howard_cycle_ratio.hpp +++ b/include/boost/graph/howard_cycle_ratio.hpp @@ -22,7 +22,6 @@ #include #include #include -#include /** @file howard_cycle_ratio.hpp * @brief The implementation of the maximum/minimum cycle ratio/mean algorithm. @@ -141,11 +140,9 @@ namespace detail * Constructor * \param g = (V, E) - a directed multigraph. * \param vim Vertex Index Map. Read property Map: V -> [0, - * num_vertices(g)). \param ewm edge weight map. Read property map: E - * -> R \param ew2m edge weight map. Read property map: E -> R+ \param - * infty A big enough value to guaranty that there exist a cycle with - * better ratio. - * \param cmp The compare operator for float_ts. + * num_vertices(g)). + * \param ewm edge weight map. Read property map: E -> R + * \param ew2m edge weight map. Read property map: E -> R+ */ mcr_howard(const Graph& g, VertexIndexMap vim, EdgeWeight1 ewm, EdgeWeight2 ew2m) @@ -241,9 +238,10 @@ namespace detail for (boost::tie(vi, vie) = vertices(m_g); vi != vie; ++vi) { boost::tie(oei, oeie) = out_edges(*vi, m_g); - auto mei = boost::first_max_element(oei, oeie, - [this](const auto& first, const auto& second) - { return m_cmp(m_ew1m[first], m_ew1m[second]); }); + auto mei = oei; + for (auto edge_it = oei; edge_it != oeie; ++edge_it) + if (m_cmp(m_ew1m[*mei], m_ew1m[*edge_it])) + mei = edge_it; if (mei == oeie) { if (m_sink == graph_traits< Graph >().null_vertex()) diff --git a/include/boost/graph/incremental_components.hpp b/include/boost/graph/incremental_components.hpp index f16882e2a..bea82556b 100644 --- a/include/boost/graph/incremental_components.hpp +++ b/include/boost/graph/incremental_components.hpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include @@ -126,8 +126,8 @@ template < typename IndexType > class component_index component_index(ParentIterator parent_start, ParentIterator parent_end, const ElementIndexMap& index_map) : m_num_elements(std::distance(parent_start, parent_end)) - , m_components(make_shared< IndexContainer >()) - , m_index_list(make_shared< IndexContainer >(m_num_elements)) + , m_components(std::make_shared< IndexContainer >()) + , m_index_list(std::make_shared< IndexContainer >(m_num_elements)) { build_index_lists(parent_start, index_map); @@ -137,8 +137,8 @@ template < typename IndexType > class component_index template < typename ParentIterator > component_index(ParentIterator parent_start, ParentIterator parent_end) : m_num_elements(std::distance(parent_start, parent_end)) - , m_components(make_shared< IndexContainer >()) - , m_index_list(make_shared< IndexContainer >(m_num_elements)) + , m_components(std::make_shared< IndexContainer >()) + , m_index_list(std::make_shared< IndexContainer >(m_num_elements)) { build_index_lists(parent_start, boost::identity_property_map()); @@ -225,7 +225,7 @@ template < typename IndexType > class component_index protected: IndexType m_num_elements; - shared_ptr< IndexContainer > m_components, m_index_list; + std::shared_ptr< IndexContainer > m_components, m_index_list; }; // class component_index diff --git a/include/boost/graph/is_straight_line_drawing.hpp b/include/boost/graph/is_straight_line_drawing.hpp index 49b522f7f..4dc8d9e8c 100644 --- a/include/boost/graph/is_straight_line_drawing.hpp +++ b/include/boost/graph/is_straight_line_drawing.hpp @@ -15,8 +15,7 @@ #include #include #include -#include -#include +#include #include #include @@ -55,7 +54,7 @@ bool crosses(typename graph_traits::edge_descriptor e, const auto& q1 = drawing[source(f, g)]; const auto& q2 = drawing[target(f, g)]; - using boost::multiprecision::int128_t; + using int128_t = boost::int128::int128; int o1 = orientation2d(p1.x, p1.y, p2.x, p2.y, q1.x, q1.y); int o2 = orientation2d(p1.x, p1.y, p2.x, p2.y, q2.x, q2.y); int o3 = orientation2d(q1.x, q1.y, q2.x, q2.y, p1.x, p1.y); diff --git a/include/boost/graph/isomorphism.hpp b/include/boost/graph/isomorphism.hpp index a16643a0b..78f2762b4 100644 --- a/include/boost/graph/isomorphism.hpp +++ b/include/boost/graph/isomorphism.hpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/include/boost/graph/labeled_graph.hpp b/include/boost/graph/labeled_graph.hpp index 1c7706e10..f91e08db5 100644 --- a/include/boost/graph/labeled_graph.hpp +++ b/include/boost/graph/labeled_graph.hpp @@ -10,10 +10,9 @@ #include #include #include +#include #include -#include -#include #include #include #include @@ -38,7 +37,8 @@ namespace graph_detail { /** Returns true if the selector is the default selector. */ template < typename Selector > - struct is_default : mpl::bool_< is_same< Selector, defaultS >::value > + struct is_default + : std::integral_constant< bool, is_same< Selector, defaultS >::value > { }; @@ -48,7 +48,8 @@ namespace graph_detail */ template < typename Label, typename Vertex > struct choose_default_map { - typedef typename mpl::if_< is_unsigned< Label >, std::vector< Vertex >, + typedef typename std::conditional< is_unsigned< Label >::value, + std::vector< Vertex >, std::map< Label, Vertex > // TODO: Should use unordered_map? >::type type; }; @@ -111,9 +112,9 @@ namespace graph_detail template < typename Selector, typename Label, typename Vertex > struct choose_map { - typedef typename mpl::eval_if< is_default< Selector >, + typedef typename std::conditional< is_default< Selector >::value, choose_default_map< Label, Vertex >, - choose_custom_map< Selector, Label, Vertex > >::type type; + choose_custom_map< Selector, Label, Vertex > >::type::type type; }; /** @name Insert Labeled Vertex */ diff --git a/include/boost/graph/louvain_clustering.hpp b/include/boost/graph/louvain_clustering.hpp index e979e8205..daa0dcd51 100644 --- a/include/boost/graph/louvain_clustering.hpp +++ b/include/boost/graph/louvain_clustering.hpp @@ -16,7 +16,6 @@ #include #include -#include #include #include diff --git a/include/boost/graph/maximum_adjacency_search.hpp b/include/boost/graph/maximum_adjacency_search.hpp index ed4b5578d..7dffc9ab7 100644 --- a/include/boost/graph/maximum_adjacency_search.hpp +++ b/include/boost/graph/maximum_adjacency_search.hpp @@ -2,6 +2,7 @@ //======================================================================= // Copyright 2012 Fernando Vilas // 2010 Daniel Trebbien +// 2026 Arnaud Becheler // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -42,20 +43,29 @@ #include #include #include +#include #include #include +#include +#include #include +#include #include +#include namespace boost { -template < class Visitor, class Graph > struct MASVisitorConcept + +namespace graph +{ + +template < class Visitor, class Graph > +struct MASVisitorConcept { void constraints() { - boost::function_requires< - boost::CopyConstructibleConcept< Visitor > >(); + boost::function_requires< boost::CopyConstructibleConcept< Visitor > >(); vis.initialize_vertex(u, g); vis.start_vertex(u, g); vis.examine_edge(e, g); @@ -67,7 +77,8 @@ template < class Visitor, class Graph > struct MASVisitorConcept typename boost::graph_traits< Graph >::edge_descriptor e; }; -template < class Visitors = null_visitor > class mas_visitor +template < class Visitors = null_visitor > +class mas_visitor { public: mas_visitor() {} @@ -79,12 +90,14 @@ template < class Visitors = null_visitor > class mas_visitor invoke_visitors(m_vis, u, g, ::boost::on_initialize_vertex()); } - template < class Vertex, class Graph > void start_vertex(Vertex u, Graph& g) + template < class Vertex, class Graph > + void start_vertex(Vertex u, Graph& g) { invoke_visitors(m_vis, u, g, ::boost::on_start_vertex()); } - template < class Edge, class Graph > void examine_edge(Edge e, Graph& g) + template < class Edge, class Graph > + void examine_edge(Edge e, Graph& g) { invoke_visitors(m_vis, e, g, ::boost::on_examine_edge()); } @@ -95,163 +108,203 @@ template < class Visitors = null_visitor > class mas_visitor invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex()); } - BOOST_GRAPH_EVENT_STUB(on_initialize_vertex, mas) - BOOST_GRAPH_EVENT_STUB(on_start_vertex, mas) - BOOST_GRAPH_EVENT_STUB(on_examine_edge, mas) - BOOST_GRAPH_EVENT_STUB(on_finish_vertex, mas) - protected: Visitors m_vis; }; + template < class Visitors > mas_visitor< Visitors > make_mas_visitor(Visitors vis) { return mas_visitor< Visitors >(vis); } -typedef mas_visitor<> default_mas_visitor; -namespace detail +using default_mas_visitor = mas_visitor<>; + +namespace mas_detail { - template < class Graph, class WeightMap, class MASVisitor, - class VertexAssignmentMap, class KeyedUpdatablePriorityQueue > - void maximum_adjacency_search(const Graph& g, WeightMap weights, - MASVisitor vis, - const typename boost::graph_traits< Graph >::vertex_descriptor start, - VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq) - { - typedef typename boost::graph_traits< Graph >::vertex_descriptor - vertex_descriptor; - typedef typename boost::property_traits< WeightMap >::value_type - weight_type; - std::set< vertex_descriptor > assignedVertices; +// Unwrap a visitor that may be passed with std::ref. +template < class Visitor > struct unwrap_visitor { using type = Visitor; }; +template < class Visitor > struct unwrap_visitor< std::reference_wrapper< Visitor > > { using type = Visitor; }; +template < class Visitor > Visitor& deref_visitor(Visitor& vis) { return vis; } +template < class Visitor > Visitor& deref_visitor(std::reference_wrapper< Visitor > vis) { return vis.get(); } + +// Maximum adjacency sweep over an already populated queue. +// Shared engine behind both maximum_adjacency_search and stoer_wagner_min_cut. +// The graph may be contracted through assignments (each vertex maps to its representative) +// with assigned_vertices listing the contracted vertices. +// Pass an identity map and an empty set for no contraction. +template +void mas_sweep( + const Graph& g, + WeightMap weight_map, + MASVisitor vis, + VertexAssignmentMap assignment_map, + const std::set::vertex_descriptor >& assigned_vertices, + KeyedUpdatablePriorityQueue& pq) +{ + // for an unvisited vertex, reach count is the total weight of its edges + // to the set of already-visited vertices. + // That is, how strongly that vertex is pulled toward what's been visited so far. - // initialize `assignments` (all vertices are initially - // assigned to themselves) - BGL_FORALL_VERTICES_T(v, g, Graph) { put(assignments, v, v); } + // reach counts are the queue keys. + auto key_map = pq.keys(); - typename KeyedUpdatablePriorityQueue::key_map keys = pq.keys(); + // resolve a std::ref-wrapped visitor to the referenced object + auto& vis_ref = deref_visitor(vis); - // set number of visited neighbors for all vertices to 0 - BGL_FORALL_VERTICES_T(v, g, Graph) - { - if (v == get(assignments, v)) - { // foreach u \in V do - put(keys, v, weight_type(0)); - vis.initialize_vertex(v, g); + while (!pq.empty()) + { + // extract max: top then pop + const auto u = pq.top(); + vis_ref.start_vertex(u, g); + pq.pop(); - pq.push(v); + for (const auto& e : make_iterator_range(out_edges(u, g))) + { + vis_ref.examine_edge(e, g); + // map the target to itself or its super node + const auto v = get(assignment_map, target(e, g)); + // in the queue means still unvisited + if (pq.contains(v)) + { + // increase key: reach count plus the edge weight + put(key_map, v, get(key_map, v) + get(weight_map, e)); + pq.update(v); } } - BOOST_ASSERT(pq.size() >= 2); - - // Give the starting vertex high priority - put(keys, start, get(keys, start) + num_vertices(g) + 1); - pq.update(start); - - // start traversing the graph - // vertex_descriptor s, t; - // weight_type w; - while (!pq.empty()) - { // while PQ \neq {} do - const vertex_descriptor u = pq.top(); // u = extractmax(PQ) - /* weight_type w = */ get(keys, u); - vis.start_vertex(u, g); - pq.pop(); // vis.start_vertex(u, g); - - BGL_FORALL_OUTEDGES_T(u, e, g, Graph) - { // foreach (u, v) \in E do - vis.examine_edge(e, g); - - const vertex_descriptor v = get(assignments, target(e, g)); - if (pq.contains(v)) - { // if v \in PQ then - put(keys, v, - get(keys, v) - + get(weights, - e)); // increasekey(PQ, v, wA(v) + w(u, v)) - pq.update(v); - } - } + // also relax the edges of every vertex contracted into u + for (const auto& member : assigned_vertices) + { + // keep only vertices belonging to this supernode + if (get(assignment_map, member) != u) + continue; - typename std::set< vertex_descriptor >::const_iterator - assignedVertexIt, - assignedVertexEnd = assignedVertices.end(); - for (assignedVertexIt = assignedVertices.begin(); - assignedVertexIt != assignedVertexEnd; ++assignedVertexIt) + for (const auto& e : make_iterator_range(out_edges(member, g))) { - const vertex_descriptor uPrime = *assignedVertexIt; - - if (get(assignments, uPrime) == u) + vis_ref.examine_edge(e, g); + // map the target to itself or its super node + const auto v = get(assignment_map, target(e, g)); + if (pq.contains(v)) { - BGL_FORALL_OUTEDGES_T(uPrime, e, g, Graph) - { // foreach (u, v) \in E do - vis.examine_edge(e, g); - - const vertex_descriptor v - = get(assignments, target(e, g)); - - if (pq.contains(v)) - { // if v \in PQ then - put(keys, v, - get(keys, v) - + get(weights, e)); // increasekey(PQ, v, - // wA(v) + w(u, v)) - pq.update(v); - } - } + put(key_map, v, get(key_map, v) + get(weight_map, e)); + pq.update(v); } } - vis.finish_vertex(u, g); } + vis_ref.finish_vertex(u, g); } -} // end namespace detail +} +} // namespace mas_detail -template < class Graph, class WeightMap, class MASVisitor, - class VertexAssignmentMap, class KeyedUpdatablePriorityQueue > -void maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis, +// Public maximum adjacency search. +// Seeds the queue, gives the start vertex the +// highest priority, then runs the shared sweep with no contraction. +template < class Graph, class WeightMap, class MASVisitor, class KeyedUpdatablePriorityQueue > +void maximum_adjacency_search( + const Graph& g, + WeightMap weight_map, + MASVisitor vis, const typename boost::graph_traits< Graph >::vertex_descriptor start, - VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq) + KeyedUpdatablePriorityQueue pq) { + using vertex_descriptor = typename boost::graph_traits< Graph >::vertex_descriptor; + using weight_type = typename boost::property_traits< WeightMap >::value_type; + using directed_category = typename boost::graph_traits< Graph >::directed_category; + using edge_descriptor = typename boost::graph_traits< Graph >::edge_descriptor; + BOOST_CONCEPT_ASSERT((boost::IncidenceGraphConcept< Graph >)); BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept< Graph >)); - typedef typename boost::graph_traits< Graph >::vertex_descriptor - vertex_descriptor; - typedef typename boost::graph_traits< Graph >::vertices_size_type - vertices_size_type; - typedef - typename boost::graph_traits< Graph >::edge_descriptor edge_descriptor; - BOOST_CONCEPT_ASSERT((boost::Convertible< - typename boost::graph_traits< Graph >::directed_category, - boost::undirected_tag >)); - BOOST_CONCEPT_ASSERT( - (boost::ReadablePropertyMapConcept< WeightMap, edge_descriptor >)); - // typedef typename boost::property_traits::value_type - // weight_type; - boost::function_requires< MASVisitorConcept< MASVisitor, Graph > >(); - BOOST_CONCEPT_ASSERT( - (boost::ReadWritePropertyMapConcept< VertexAssignmentMap, - vertex_descriptor >)); - BOOST_CONCEPT_ASSERT((boost::Convertible< vertex_descriptor, - typename boost::property_traits< VertexAssignmentMap >::value_type >)); - BOOST_CONCEPT_ASSERT( - (boost::KeyedUpdatableQueueConcept< KeyedUpdatablePriorityQueue >)); - - vertices_size_type n = num_vertices(g); - if (n < 2) - throw boost::bad_graph( - "the input graph must have at least two vertices."); - else if (!pq.empty()) - throw std::invalid_argument( - "the max-priority queue must be empty initially."); - - detail::maximum_adjacency_search(g, weights, vis, start, assignments, pq); + BOOST_CONCEPT_ASSERT((boost::Convertible< directed_category, boost::undirected_tag >)); + BOOST_CONCEPT_ASSERT((boost::ReadablePropertyMapConcept< WeightMap, edge_descriptor >)); + using visitor_type = typename mas_detail::unwrap_visitor< MASVisitor >::type; + boost::function_requires< MASVisitorConcept< visitor_type, Graph > >(); + BOOST_CONCEPT_ASSERT((boost::KeyedUpdatableQueueConcept< KeyedUpdatablePriorityQueue >)); + + if (num_vertices(g) < 2) + throw boost::bad_graph("the input graph must have at least two vertices."); + if (!pq.empty()) + throw std::invalid_argument("the priority queue must be empty initially."); + + // reach counts are the queue keys + auto key_map = pq.keys(); + + // resolve a std::ref-wrapped visitor to the referenced object + auto& vis_ref = mas_detail::deref_visitor(vis); + + // seed every vertex with reach count 0 + for (const auto& v : make_iterator_range(vertices(g))) + { + put(key_map, v, static_cast< weight_type >(0)); + vis_ref.initialize_vertex(v, g); + pq.push(v); + } + BOOST_ASSERT(pq.size() >= 2); + + // give the start vertex the highest priority + put(key_map, start, get(key_map, start) + num_vertices(g) + 1); + pq.update(start); + + // no contraction: identity assignment map and empty contracted set + const boost::typed_identity_property_map< vertex_descriptor > identity_map; + const std::set< vertex_descriptor > no_assigned_vertices; + mas_detail::mas_sweep(g, weight_map, vis, identity_map, no_assigned_vertices, pq); +} + +// Convenience overload that defaults only the priority queue. Building the +// queue is the cumbersome part, so this spares the caller that while still +// letting them choose the start vertex. +template < class Graph, class WeightMap, class MASVisitor > +void maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis, + const typename boost::graph_traits< Graph >::vertex_descriptor start) +{ + using vertex_descriptor = typename boost::graph_traits< Graph >::vertex_descriptor; + using weight_type = typename boost::property_traits< WeightMap >::value_type; + using vertex_index_map_type = typename boost::property_map< Graph, boost::vertex_index_t >::const_type; + using distance_map_type = boost::shared_array_property_map< weight_type, vertex_index_map_type >; + using index_in_heap_type = typename std::vector< vertex_descriptor >::size_type; + using index_in_heap_map_type = boost::shared_array_property_map< index_in_heap_type, vertex_index_map_type >; + using priority_queue_type = boost::d_ary_heap_indirect< vertex_descriptor, 4, index_in_heap_map_type, distance_map_type, std::greater< weight_type > >; + + const vertex_index_map_type vertex_index_map = get(boost::vertex_index, g); + distance_map_type distance_map = boost::make_shared_array_property_map(num_vertices(g), weight_type(0), vertex_index_map); + index_in_heap_map_type index_in_heap_map = boost::make_shared_array_property_map(num_vertices(g), index_in_heap_type(-1), vertex_index_map); + priority_queue_type pq(distance_map, index_in_heap_map); + + maximum_adjacency_search(g, weights, vis, start, pq); +} + +// Convenience overload that additionally defaults the start vertex to the first +// vertex, matching what the deprecated named parameter interface built. +template < class Graph, class WeightMap, class MASVisitor > +void maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis) +{ + maximum_adjacency_search(g, weights, vis, *vertices(g).first); +} + +} // namespace graph + +// -- old interface to be deprecated -- + +template < class Graph, class WeightMap, class MASVisitor, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue > +BOOST_DEPRECATED("assignments is unused, use the 5-argument boost::graph::maximum_adjacency_search. Removal planned for Boost 1.95.") +void maximum_adjacency_search( + const Graph& g, + WeightMap weights, + MASVisitor vis, + const typename boost::graph_traits< Graph >::vertex_descriptor start, + VertexAssignmentMap, + KeyedUpdatablePriorityQueue pq) +{ + using vertex_descriptor = typename boost::graph_traits< Graph >::vertex_descriptor; + BOOST_CONCEPT_ASSERT((boost::ReadWritePropertyMapConcept< VertexAssignmentMap, vertex_descriptor >)); + graph::maximum_adjacency_search(g, weights, vis, start, pq); } namespace graph { - namespace detail + namespace mas_detail { template < typename WeightMap > struct mas_dispatch { @@ -282,7 +335,7 @@ namespace graph = pq_gen(g, params); boost::null_visitor null_vis; - boost::mas_visitor< boost::null_visitor > default_visitor( + boost::graph::mas_visitor< boost::null_visitor > default_visitor( null_vis); vertex_descriptor v = vertex_descriptor(); boost::detail::make_property_map_from_arg_pack_gen< @@ -333,7 +386,7 @@ namespace graph = pq_gen(g, params); boost::null_visitor null_vis; - boost::mas_visitor< boost::null_visitor > default_visitor( + boost::graph::mas_visitor< boost::null_visitor > default_visitor( null_vis); vertex_descriptor v = vertex_descriptor(); boost::detail::make_property_map_from_arg_pack_gen< @@ -350,12 +403,13 @@ namespace graph params[_vertex_assignment_map | default_map], pq); } }; - } // end namespace detail + } // end namespace mas_detail } // end namespace graph // Named parameter interface // BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(maximum_adjacency_search, 1) template < typename Graph, typename P, typename T, typename R > +BOOST_DEPRECATED("the named parameter interface is deprecated, use the positional boost::graph::maximum_adjacency_search. Removal planned for Boost 1.95.") void maximum_adjacency_search( const Graph& g, const bgl_named_params< P, T, R >& params) { @@ -366,7 +420,7 @@ void maximum_adjacency_search( // do the dispatch based on WeightMap typedef typename get_param_type< edge_weight_t, bgl_named_params< P, T, R > >::type W; - graph::detail::mas_dispatch< W >::apply( + graph::mas_detail::mas_dispatch< W >::apply( g, arg_pack, get_param(params, edge_weight)); } @@ -384,16 +438,46 @@ namespace graph // call the function that does the dispatching typedef typename get_param_type< edge_weight_t, ArgPack >::type W; - graph::detail::mas_dispatch< W >::apply( + graph::mas_detail::mas_dispatch< W >::apply( g, arg_pack, get_param(arg_pack, edge_weight)); } }; } // end namespace detail + BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(maximum_adjacency_search, 1, 5) + } // end namespace graph -} // end namespace boost +// -- deprecated aliases: the MAS visitor types moved into boost::graph. -- +// Kept in boost:: for backward compatibility. Removal planned for Boost 1.95. +// +// BOOST_DEPRECATED (__declspec on MSVC) does not parse inside an +// alias-declaration, so follow the Boost.URL pattern: delegate to +// BOOST_DEPRECATED on gcc/clang and drop the attribute on MSVC. This keeps the +// BOOST_ALLOW_DEPRECATED_SYMBOLS opt-out working on gcc/clang. +#if defined(BOOST_MSVC) +#define BOOST_GRAPH_MAS_DEPRECATED_ALIAS(msg) +#else +#define BOOST_GRAPH_MAS_DEPRECATED_ALIAS(msg) BOOST_DEPRECATED(msg) +#endif + +template < class Visitor, class Graph > +using MASVisitorConcept BOOST_GRAPH_MAS_DEPRECATED_ALIAS("use boost::graph::MASVisitorConcept") = graph::MASVisitorConcept< Visitor, Graph >; -#include +template < class Visitors = null_visitor > +using mas_visitor BOOST_GRAPH_MAS_DEPRECATED_ALIAS("use boost::graph::mas_visitor") = graph::mas_visitor< Visitors >; + +using default_mas_visitor BOOST_GRAPH_MAS_DEPRECATED_ALIAS("use boost::graph::default_mas_visitor") = graph::default_mas_visitor; + +#undef BOOST_GRAPH_MAS_DEPRECATED_ALIAS + +template < class Visitors > +BOOST_DEPRECATED("use boost::graph::make_mas_visitor") +graph::mas_visitor< Visitors > make_mas_visitor(Visitors vis) +{ + return graph::make_mas_visitor(vis); +} + +} // end namespace boost #endif // BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H diff --git a/include/boost/graph/mcgregor_common_subgraphs.hpp b/include/boost/graph/mcgregor_common_subgraphs.hpp index 9c2b4b980..32fbb3c62 100644 --- a/include/boost/graph/mcgregor_common_subgraphs.hpp +++ b/include/boost/graph/mcgregor_common_subgraphs.hpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include @@ -559,7 +559,7 @@ namespace detail , m_graph2(graph2) , m_vindex_map1(vindex_map1) , m_vindex_map2(vindex_map2) - , m_subgraphs(make_shared< SubGraphList >()) + , m_subgraphs(std::make_shared< SubGraphList >()) , m_user_callback(user_callback) { } @@ -627,7 +627,7 @@ namespace detail const GraphFirst& m_graph2; const VertexIndexMapFirst m_vindex_map1; const VertexIndexMapSecond m_vindex_map2; - shared_ptr< SubGraphList > m_subgraphs; + std::shared_ptr< SubGraphList > m_subgraphs; SubGraphCallback m_user_callback; }; @@ -732,8 +732,8 @@ namespace detail , m_graph2(graph2) , m_vindex_map1(vindex_map1) , m_vindex_map2(vindex_map2) - , m_subgraphs(make_shared< SubGraphList >()) - , m_largest_size_so_far(make_shared< VertexSizeFirst >(0)) + , m_subgraphs(std::make_shared< SubGraphList >()) + , m_largest_size_so_far(std::make_shared< VertexSizeFirst >(0)) , m_user_callback(user_callback) { } @@ -801,8 +801,8 @@ namespace detail const GraphFirst& m_graph2; const VertexIndexMapFirst m_vindex_map1; const VertexIndexMapSecond m_vindex_map2; - shared_ptr< SubGraphList > m_subgraphs; - shared_ptr< VertexSizeFirst > m_largest_size_so_far; + std::shared_ptr< SubGraphList > m_subgraphs; + std::shared_ptr< VertexSizeFirst > m_largest_size_so_far; SubGraphCallback m_user_callback; }; @@ -910,8 +910,8 @@ namespace detail , m_graph2(graph2) , m_vindex_map1(vindex_map1) , m_vindex_map2(vindex_map2) - , m_subgraphs(make_shared< SubGraphList >()) - , m_largest_size_so_far(make_shared< VertexSizeFirst >(0)) + , m_subgraphs(std::make_shared< SubGraphList >()) + , m_largest_size_so_far(std::make_shared< VertexSizeFirst >(0)) , m_user_callback(user_callback) { } @@ -996,8 +996,8 @@ namespace detail const GraphFirst& m_graph2; const VertexIndexMapFirst m_vindex_map1; const VertexIndexMapSecond m_vindex_map2; - shared_ptr< SubGraphList > m_subgraphs; - shared_ptr< VertexSizeFirst > m_largest_size_so_far; + std::shared_ptr< SubGraphList > m_subgraphs; + std::shared_ptr< VertexSizeFirst > m_largest_size_so_far; SubGraphCallback m_user_callback; }; diff --git a/include/boost/graph/metric_tsp_approx.hpp b/include/boost/graph/metric_tsp_approx.hpp index 38eaf6fa6..77bab72ca 100644 --- a/include/boost/graph/metric_tsp_approx.hpp +++ b/include/boost/graph/metric_tsp_approx.hpp @@ -28,7 +28,6 @@ #include -#include #include #include #include diff --git a/include/boost/graph/one_bit_color_map.hpp b/include/boost/graph/one_bit_color_map.hpp index cdc59e175..d3a1ab98a 100644 --- a/include/boost/graph/one_bit_color_map.hpp +++ b/include/boost/graph/one_bit_color_map.hpp @@ -16,8 +16,7 @@ #include #include -#include -#include +#include #include #include #include @@ -45,7 +44,8 @@ template < typename IndexMap = identity_property_map > struct one_bit_color_map int, bits_per_char = std::numeric_limits< unsigned char >::digits); std::size_t n; IndexMap index; - shared_array< unsigned char > data; + // todo : C++17: replace with std::shared_ptr + std::shared_ptr< unsigned char > data; typedef typename property_traits< IndexMap >::key_type key_type; typedef one_bit_color_type value_type; @@ -56,7 +56,8 @@ template < typename IndexMap = identity_property_map > struct one_bit_color_map std::size_t n, const IndexMap& index = IndexMap()) : n(n) , index(index) - , data(new unsigned char[(n + bits_per_char - 1) / bits_per_char]()) + , data(new unsigned char[(n + bits_per_char - 1) / bits_per_char](), + std::default_delete< unsigned char[] >()) { } }; @@ -99,6 +100,4 @@ inline one_bit_color_map< IndexMap > make_one_bit_color_map( } // end namespace boost -#include BOOST_GRAPH_MPI_INCLUDE() - #endif // BOOST_ONE_BIT_COLOR_MAP_HPP diff --git a/include/boost/graph/page_rank.hpp b/include/boost/graph/page_rank.hpp index 54170da54..7d5f4a166 100644 --- a/include/boost/graph/page_rank.hpp +++ b/include/boost/graph/page_rank.hpp @@ -16,7 +16,6 @@ #include #include #include -#include #include namespace boost @@ -174,6 +173,4 @@ namespace graph } } // end namespace boost::graph -#include BOOST_GRAPH_MPI_INCLUDE() - #endif // BOOST_GRAPH_PAGE_RANK_HPP diff --git a/include/boost/graph/planar_detail/boyer_myrvold_impl.hpp b/include/boost/graph/planar_detail/boyer_myrvold_impl.hpp index c2797c1d8..d18e70765 100644 --- a/include/boost/graph/planar_detail/boyer_myrvold_impl.hpp +++ b/include/boost/graph/planar_detail/boyer_myrvold_impl.hpp @@ -12,7 +12,7 @@ #include #include #include //for std::min macros -#include +#include #include #include #include @@ -150,8 +150,8 @@ class boyer_myrvold_impl typedef std::vector< edge_t > edge_vector_t; typedef std::list< vertex_t > vertex_list_t; typedef std::list< face_handle_t > face_handle_list_t; - typedef boost::shared_ptr< face_handle_list_t > face_handle_list_ptr_t; - typedef boost::shared_ptr< vertex_list_t > vertex_list_ptr_t; + using face_handle_list_ptr_t = std::shared_ptr< face_handle_list_t >; + using vertex_list_ptr_t = std::shared_ptr< vertex_list_t >; typedef boost::tuple< vertex_t, bool, bool > merge_stack_frame_t; typedef std::vector< merge_stack_frame_t > merge_stack_t; diff --git a/include/boost/graph/planar_detail/face_handles.hpp b/include/boost/graph/planar_detail/face_handles.hpp index 1ea7efcb4..728aa4f29 100644 --- a/include/boost/graph/planar_detail/face_handles.hpp +++ b/include/boost/graph/planar_detail/face_handles.hpp @@ -11,7 +11,7 @@ #include #include -#include +#include // A "face handle" is an optimization meant to serve two purposes in // the implementation of the Boyer-Myrvold planarity test: (1) it holds @@ -74,7 +74,7 @@ namespace graph template < typename DataType > struct lazy_list_node { - typedef shared_ptr< lazy_list_node< DataType > > ptr_t; + using ptr_t = std::shared_ptr< lazy_list_node< DataType > >; lazy_list_node(const DataType& data) : m_reversed(false), m_data(data), m_has_data(true) @@ -92,8 +92,8 @@ namespace graph bool m_reversed; DataType m_data; bool m_has_data; - shared_ptr< lazy_list_node > m_left_child; - shared_ptr< lazy_list_node > m_right_child; + std::shared_ptr< lazy_list_node > m_left_child; + std::shared_ptr< lazy_list_node > m_right_child; }; template < typename StoreOldHandlesPolicy, typename Vertex, @@ -136,7 +136,7 @@ namespace graph struct edge_list_storage< recursive_lazy_list, Edge > { typedef lazy_list_node< Edge > node_type; - typedef shared_ptr< node_type > type; + using type = std::shared_ptr< node_type >; type value; void push_back(Edge e) @@ -443,7 +443,7 @@ namespace graph void store_old_face_handles_dispatch(no_old_handles) {} - boost::shared_ptr< impl_t > pimpl; + std::shared_ptr< impl_t > pimpl; }; } /* namespace detail */ diff --git a/include/boost/graph/planar_detail/face_iterators.hpp b/include/boost/graph/planar_detail/face_iterators.hpp index f1a1c333c..7aaa71af7 100644 --- a/include/boost/graph/planar_detail/face_iterators.hpp +++ b/include/boost/graph/planar_detail/face_iterators.hpp @@ -10,7 +10,6 @@ #define __FACE_ITERATORS_HPP__ #include -#include #include namespace boost diff --git a/include/boost/graph/plod_generator.hpp b/include/boost/graph/plod_generator.hpp index 1f22d3919..e46a2ae7b 100644 --- a/include/boost/graph/plod_generator.hpp +++ b/include/boost/graph/plod_generator.hpp @@ -12,12 +12,12 @@ #include #include #include -#include +#include #include #include #include #include -#include +#include namespace boost { @@ -240,7 +240,7 @@ template < typename RandomGenerator > class undirected_plod_iterator RandomGenerator* gen; std::size_t n; - shared_ptr< out_degrees_t > out_degrees; + std::shared_ptr< out_degrees_t > out_degrees; std::size_t degrees_left; bool allow_self_loops; value_type current; @@ -248,15 +248,15 @@ template < typename RandomGenerator > class undirected_plod_iterator template < typename RandomGenerator, typename Graph > class plod_iterator -: public mpl::if_< +: public std::conditional< is_convertible< typename graph_traits< Graph >::directed_category, - directed_tag >, + directed_tag >::value, out_directed_plod_iterator< RandomGenerator >, undirected_plod_iterator< RandomGenerator > >::type { - typedef typename mpl::if_< + typedef typename std::conditional< is_convertible< typename graph_traits< Graph >::directed_category, - directed_tag >, + directed_tag >::value, out_directed_plod_iterator< RandomGenerator >, undirected_plod_iterator< RandomGenerator > >::type inherited; diff --git a/include/boost/graph/properties.hpp b/include/boost/graph/properties.hpp index 988d31039..1693bbea8 100644 --- a/include/boost/graph/properties.hpp +++ b/include/boost/graph/properties.hpp @@ -23,9 +23,7 @@ #include #include #include -#include -#include -#include +#include namespace boost { @@ -150,15 +148,15 @@ namespace detail template < typename G, typename R, typename T > struct property_kind_from_graph< G, R T::* > { - typedef typename boost::mpl::if_< - boost::is_base_of< T, typename vertex_bundle_type< G >::type >, + typedef typename std::conditional< + boost::is_base_of< T, typename vertex_bundle_type< G >::type >::value, vertex_property_tag, - typename boost::mpl::if_< - boost::is_base_of< T, typename edge_bundle_type< G >::type >, + typename std::conditional< + boost::is_base_of< T, typename edge_bundle_type< G >::type >::value, edge_property_tag, - typename boost::mpl::if_< + typename std::conditional< boost::is_base_of< T, - typename graph_bundle_type< G >::type >, + typename graph_bundle_type< G >::type >::value, graph_property_tag, void >::type >::type >::type type; }; #endif @@ -232,9 +230,9 @@ namespace detail template < class Graph, class Property, class Enable = void > struct property_map -: mpl::if_< is_same< typename detail::property_kind_from_graph< Graph, - Property >::type, - edge_property_tag >, +: std::conditional< is_same< typename detail::property_kind_from_graph< Graph, + Property >::type, + edge_property_tag >::value, detail::edge_property_map< Graph, Property >, detail::vertex_property_map< Graph, Property > >::type { diff --git a/include/boost/graph/property_iter_range.hpp b/include/boost/graph/property_iter_range.hpp index aa8780b37..6b8a4c670 100644 --- a/include/boost/graph/property_iter_range.hpp +++ b/include/boost/graph/property_iter_range.hpp @@ -20,7 +20,7 @@ #include #include -#include +#include #include namespace boost @@ -35,7 +35,7 @@ template < class Graph, class PropertyTag > class graph_property_iter_range typedef typename property_map< Graph, PropertyTag >::const_type const_map_type; typedef typename property_kind< PropertyTag >::type Kind; - typedef typename mpl::if_c< is_same< Kind, vertex_property_tag >::value, + typedef typename std::conditional< is_same< Kind, vertex_property_tag >::value, typename graph_traits< Graph >::vertex_iterator, typename graph_traits< Graph >::edge_iterator >::type iter; diff --git a/include/boost/graph/r_c_shortest_paths.hpp b/include/boost/graph/r_c_shortest_paths.hpp index 12edb43dc..0f8040a2a 100644 --- a/include/boost/graph/r_c_shortest_paths.hpp +++ b/include/boost/graph/r_c_shortest_paths.hpp @@ -8,13 +8,11 @@ #ifndef BOOST_GRAPH_R_C_SHORTEST_PATHS_HPP #define BOOST_GRAPH_R_C_SHORTEST_PATHS_HPP -#include #include #include #include -#include -#include +#include #include #include #include @@ -23,18 +21,16 @@ namespace boost { // r_c_shortest_paths_label struct -template < class Graph, class Resource_Container > +template < class Graph, class ResourceContainer > struct r_c_shortest_paths_label -: public boost::enable_shared_from_this< - r_c_shortest_paths_label< Graph, Resource_Container > > { r_c_shortest_paths_label(const unsigned long n, - const Resource_Container& rc = Resource_Container(), - const boost::shared_ptr< - r_c_shortest_paths_label< Graph, Resource_Container > > + const ResourceContainer& rc = ResourceContainer(), + const std::shared_ptr< + r_c_shortest_paths_label< Graph, ResourceContainer > > pl - = boost::shared_ptr< - r_c_shortest_paths_label< Graph, Resource_Container > >(), + = std::shared_ptr< + r_c_shortest_paths_label< Graph, ResourceContainer > >(), const typename graph_traits< Graph >::edge_descriptor& ed = graph_traits< Graph >::edge_descriptor(), const typename graph_traits< Graph >::vertex_descriptor& vd @@ -58,9 +54,9 @@ struct r_c_shortest_paths_label return *this; } const unsigned long num; - Resource_Container cumulated_resource_consumption; - const boost::shared_ptr< - r_c_shortest_paths_label< Graph, Resource_Container > > + ResourceContainer cumulated_resource_consumption; + const std::shared_ptr< + r_c_shortest_paths_label< Graph, ResourceContainer > > p_pred_label; const typename graph_traits< Graph >::edge_descriptor pred_edge; const typename graph_traits< Graph >::vertex_descriptor resident_vertex; @@ -68,163 +64,124 @@ struct r_c_shortest_paths_label bool b_is_processed; }; // r_c_shortest_paths_label -template < class Graph, class Resource_Container > +template < class Graph, class ResourceContainer > inline bool operator==( - const r_c_shortest_paths_label< Graph, Resource_Container >& l1, - const r_c_shortest_paths_label< Graph, Resource_Container >& l2) + const r_c_shortest_paths_label< Graph, ResourceContainer >& l1, + const r_c_shortest_paths_label< Graph, ResourceContainer >& l2) { return l1.cumulated_resource_consumption == l2.cumulated_resource_consumption; } -template < class Graph, class Resource_Container > +template < class Graph, class ResourceContainer > inline bool operator!=( - const r_c_shortest_paths_label< Graph, Resource_Container >& l1, - const r_c_shortest_paths_label< Graph, Resource_Container >& l2) + const r_c_shortest_paths_label< Graph, ResourceContainer >& l1, + const r_c_shortest_paths_label< Graph, ResourceContainer >& l2) { return !(l1 == l2); } -template < class Graph, class Resource_Container > +template < class Graph, class ResourceContainer > inline bool operator<( - const r_c_shortest_paths_label< Graph, Resource_Container >& l1, - const r_c_shortest_paths_label< Graph, Resource_Container >& l2) + const r_c_shortest_paths_label< Graph, ResourceContainer >& l1, + const r_c_shortest_paths_label< Graph, ResourceContainer >& l2) { return l1.cumulated_resource_consumption < l2.cumulated_resource_consumption; } -template < class Graph, class Resource_Container > +template < class Graph, class ResourceContainer > inline bool operator>( - const r_c_shortest_paths_label< Graph, Resource_Container >& l1, - const r_c_shortest_paths_label< Graph, Resource_Container >& l2) + const r_c_shortest_paths_label< Graph, ResourceContainer >& l1, + const r_c_shortest_paths_label< Graph, ResourceContainer >& l2) { return l2.cumulated_resource_consumption < l1.cumulated_resource_consumption; } -template < class Graph, class Resource_Container > +template < class Graph, class ResourceContainer > inline bool operator<=( - const r_c_shortest_paths_label< Graph, Resource_Container >& l1, - const r_c_shortest_paths_label< Graph, Resource_Container >& l2) + const r_c_shortest_paths_label< Graph, ResourceContainer >& l1, + const r_c_shortest_paths_label< Graph, ResourceContainer >& l2) { return l1 < l2 || l1 == l2; } -template < class Graph, class Resource_Container > +template < class Graph, class ResourceContainer > inline bool operator>=( - const r_c_shortest_paths_label< Graph, Resource_Container >& l1, - const r_c_shortest_paths_label< Graph, Resource_Container >& l2) + const r_c_shortest_paths_label< Graph, ResourceContainer >& l1, + const r_c_shortest_paths_label< Graph, ResourceContainer >& l2) { return l2 < l1 || l1 == l2; } -template < typename Graph, typename Resource_Container > -inline bool operator<( - const boost::shared_ptr< - r_c_shortest_paths_label< Graph, Resource_Container > >& t, - const boost::shared_ptr< - r_c_shortest_paths_label< Graph, Resource_Container > >& u) -{ - return *t < *u; -} - -template < typename Graph, typename Resource_Container > -inline bool operator<=( - const boost::shared_ptr< - r_c_shortest_paths_label< Graph, Resource_Container > >& t, - const boost::shared_ptr< - r_c_shortest_paths_label< Graph, Resource_Container > >& u) -{ - return *t <= *u; -} - -template < typename Graph, typename Resource_Container > -inline bool operator>( - const boost::shared_ptr< - r_c_shortest_paths_label< Graph, Resource_Container > >& t, - const boost::shared_ptr< - r_c_shortest_paths_label< Graph, Resource_Container > >& u) -{ - return *t > *u; -} - -template < typename Graph, typename Resource_Container > -inline bool operator>=( - const boost::shared_ptr< - r_c_shortest_paths_label< Graph, Resource_Container > >& t, - const boost::shared_ptr< - r_c_shortest_paths_label< Graph, Resource_Container > >& u) -{ - return *t >= *u; -} - namespace detail { + // Order by the pointed-to value, not by pointer identity. Works on any + // dereferenceable type. + template < class Pointer > struct deref_greater + { + bool operator()(const Pointer& a, const Pointer& b) const + { + return *a > *b; + } + }; + // r_c_shortest_paths_dispatch function (body/implementation) - template < class Graph, class VertexIndexMap, class EdgeIndexMap, - class Resource_Container, class Resource_Extension_Function, - class Dominance_Function, class Label_Allocator, class Visitor > + template < class Graph, class VertexIndexMap, class ResourceContainer, + class ResourceExtensionFunction, class DominanceFunction, + class LabelAllocator, class Visitor > void r_c_shortest_paths_dispatch(const Graph& g, const VertexIndexMap& vertex_index_map, - const EdgeIndexMap& /*edge_index_map*/, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, // each inner vector corresponds to a pareto-optimal path std::vector< std::vector< typename graph_traits< Graph >::edge_descriptor > >& pareto_optimal_solutions, - std::vector< Resource_Container >& pareto_optimal_resource_containers, + std::vector< ResourceContainer >& pareto_optimal_resource_containers, bool b_all_pareto_optimal_solutions, // to initialize the first label/resource container // and to carry the type information - const Resource_Container& rc, Resource_Extension_Function& ref, - Dominance_Function& dominance, + const ResourceContainer& rc, ResourceExtensionFunction& ref, + DominanceFunction& dominance, // to specify the memory management strategy for the labels - Label_Allocator /*la*/, Visitor vis) + LabelAllocator /*la*/, Visitor vis) { + using edge_descriptor = typename graph_traits< Graph >::edge_descriptor; + pareto_optimal_resource_containers.clear(); pareto_optimal_solutions.clear(); size_t i_label_num = 0; -#if defined(BOOST_NO_CXX11_ALLOCATOR) - typedef typename Label_Allocator::template rebind< - r_c_shortest_paths_label< Graph, Resource_Container > >::other - LAlloc; -#else - typedef typename std::allocator_traits< Label_Allocator >:: - template rebind_alloc< - r_c_shortest_paths_label< Graph, Resource_Container > > - LAlloc; - typedef std::allocator_traits< LAlloc > LTraits; -#endif - LAlloc l_alloc; - typedef boost::shared_ptr< - r_c_shortest_paths_label< Graph, Resource_Container > > - Splabel; - std::priority_queue< Splabel, std::vector< Splabel >, - std::greater< Splabel > > + + using label_type = r_c_shortest_paths_label< Graph, ResourceContainer >; + using label_allocator_type = typename std::allocator_traits< + LabelAllocator >::template rebind_alloc< label_type >; + + label_allocator_type l_alloc; + + using sp_label_type = std::shared_ptr< label_type >; + std::priority_queue< sp_label_type, std::vector< sp_label_type >, + deref_greater< sp_label_type > > unprocessed_labels; - bool b_feasible = true; - Splabel splabel_first_label = boost::allocate_shared< - r_c_shortest_paths_label< Graph, Resource_Container > >(l_alloc, - i_label_num++, rc, - boost::shared_ptr< - r_c_shortest_paths_label< Graph, Resource_Container > >(), - typename graph_traits< Graph >::edge_descriptor(), s); + sp_label_type splabel_first_label = std::allocate_shared< label_type >( + l_alloc, i_label_num++, rc, sp_label_type(), edge_descriptor(), s); unprocessed_labels.push(splabel_first_label); - std::vector< std::list< Splabel > > vec_vertex_labels_data( - num_vertices(g)); - iterator_property_map< - typename std::vector< std::list< Splabel > >::iterator, + + using sp_label_list = std::list< sp_label_type >; + + std::vector< sp_label_list > vec_vertex_labels_data(num_vertices(g)); + iterator_property_map< typename std::vector< sp_label_list >::iterator, VertexIndexMap > vec_vertex_labels(vec_vertex_labels_data.begin(), vertex_index_map); vec_vertex_labels[s].push_back(splabel_first_label); - typedef std::vector< typename std::list< Splabel >::iterator > - vec_last_valid_positions_for_dominance_data_type; + + using vec_last_valid_positions_for_dominance_data_type + = std::vector< typename sp_label_list::iterator >; vec_last_valid_positions_for_dominance_data_type vec_last_valid_positions_for_dominance_data(num_vertices(g)); iterator_property_map< @@ -238,6 +195,7 @@ namespace detail put(vec_last_valid_positions_for_dominance, v, vec_vertex_labels[v].begin()); } + std::vector< size_t > vec_last_valid_index_for_dominance_data( num_vertices(g), 0); iterator_property_map< std::vector< size_t >::iterator, VertexIndexMap > @@ -251,10 +209,12 @@ namespace detail b_vec_vertex_already_checked_for_dominance_data.begin(), vertex_index_map); + auto b_feasible = true; + while (!unprocessed_labels.empty() && vis.on_enter_loop(unprocessed_labels, g)) { - Splabel cur_label = unprocessed_labels.top(); + sp_label_type cur_label = unprocessed_labels.top(); unprocessed_labels.pop(); vis.on_label_popped(*cur_label, g); // an Splabel object in unprocessed_labels and the respective @@ -271,24 +231,20 @@ namespace detail // extended is undominated if (!cur_label->b_is_dominated) { - typename boost::graph_traits< Graph >::vertex_descriptor - i_cur_resident_vertex - = cur_label->resident_vertex; - std::list< Splabel >& list_labels_cur_vertex + auto i_cur_resident_vertex = cur_label->resident_vertex; + auto& list_labels_cur_vertex = get(vec_vertex_labels, i_cur_resident_vertex); if (list_labels_cur_vertex.size() >= 2 && vec_last_valid_index_for_dominance[i_cur_resident_vertex] < list_labels_cur_vertex.size()) { - typename std::list< Splabel >::iterator outer_iter - = list_labels_cur_vertex.begin(); - bool b_outer_iter_at_or_beyond_last_valid_pos_for_dominance + auto outer_iter = list_labels_cur_vertex.begin(); + auto b_outer_iter_at_or_beyond_last_valid_pos_for_dominance = false; while (outer_iter != list_labels_cur_vertex.end()) { - Splabel cur_outer_splabel = *outer_iter; - typename std::list< Splabel >::iterator inner_iter - = outer_iter; + auto cur_outer_splabel = *outer_iter; + auto inner_iter = outer_iter; if (!b_outer_iter_at_or_beyond_last_valid_pos_for_dominance && outer_iter == get(vec_last_valid_positions_for_dominance, @@ -308,17 +264,16 @@ namespace detail i_cur_resident_vertex); ++inner_iter; } - bool b_outer_iter_erased = false; + auto b_outer_iter_erased = false; while (inner_iter != list_labels_cur_vertex.end()) { - Splabel cur_inner_splabel = *inner_iter; + auto cur_inner_splabel = *inner_iter; if (dominance(cur_outer_splabel ->cumulated_resource_consumption, cur_inner_splabel ->cumulated_resource_consumption)) { - typename std::list< Splabel >::iterator buf - = inner_iter; + auto buf = inner_iter; ++inner_iter; list_labels_cur_vertex.erase(buf); if (cur_inner_splabel->b_is_processed) @@ -336,8 +291,7 @@ namespace detail cur_outer_splabel ->cumulated_resource_consumption)) { - typename std::list< Splabel >::iterator buf - = outer_iter; + auto buf = outer_iter; ++outer_iter; list_labels_cur_vertex.erase(buf); b_outer_iter_erased = true; @@ -378,7 +332,7 @@ namespace detail } while (unprocessed_labels.size()) { - Splabel l = unprocessed_labels.top(); + sp_label_type l = unprocessed_labels.top(); unprocessed_labels.pop(); // delete only dominated labels, because nondominated labels // are deleted at the end of the function @@ -393,15 +347,14 @@ namespace detail { cur_label->b_is_processed = true; vis.on_label_not_dominated(*cur_label, g); - typename graph_traits< Graph >::vertex_descriptor cur_vertex - = cur_label->resident_vertex; + auto cur_vertex = cur_label->resident_vertex; typename graph_traits< Graph >::out_edge_iterator oei, oei_end; for (boost::tie(oei, oei_end) = out_edges(cur_vertex, g); oei != oei_end; ++oei) { b_feasible = true; - Splabel new_label = boost::allocate_shared< - r_c_shortest_paths_label< Graph, Resource_Container > >( + auto new_label = std::allocate_shared< + r_c_shortest_paths_label< Graph, ResourceContainer > >( l_alloc, i_label_num++, cur_label->cumulated_resource_consumption, cur_label, *oei, target(*oei, g)); @@ -430,23 +383,24 @@ namespace detail cur_label.reset(); } } - std::list< Splabel > dsplabels = get(vec_vertex_labels, t); - if(!b_all_pareto_optimal_solutions) + auto& dsplabels = get(vec_vertex_labels, t); + + if (!b_all_pareto_optimal_solutions) { - dsplabels.sort(); + dsplabels.sort( + [](const auto& a, const auto& b) { return *a < *b; }); } - typename std::list< Splabel >::const_iterator csi = dsplabels.begin(); - typename std::list< Splabel >::const_iterator csi_end = dsplabels.end(); + // if d could be reached from o if (!dsplabels.empty()) { + auto csi = dsplabels.cbegin(); + auto csi_end = dsplabels.cend(); for (; csi != csi_end; ++csi) { - std::vector< typename graph_traits< Graph >::edge_descriptor > - cur_pareto_optimal_path; - boost::shared_ptr< - r_c_shortest_paths_label< Graph, Resource_Container > > - p_cur_label = *csi; + std::vector< edge_descriptor > cur_pareto_optimal_path; + + auto p_cur_label = *csi; pareto_optimal_resource_containers.push_back( p_cur_label->cumulated_resource_consumption); while (p_cur_label->num != 0) @@ -480,14 +434,10 @@ namespace detail BGL_FORALL_VERTICES_T(i, g, Graph) { - std::list< Splabel >& list_labels_cur_vertex = vec_vertex_labels[i]; - typename std::list< Splabel >::iterator si - = list_labels_cur_vertex.begin(); - const typename std::list< Splabel >::iterator si_end - = list_labels_cur_vertex.end(); - for (; si != si_end; ++si) + auto& list_labels_cur_vertex = vec_vertex_labels[i]; + for (auto& label : list_labels_cur_vertex) { - (*si).reset(); + label.reset(); } } } // r_c_shortest_paths_dispatch @@ -518,70 +468,69 @@ struct default_r_c_shortest_paths_visitor { } template < class Queue, class Graph > - bool on_enter_loop(const Queue& queue, const Graph& graph) + bool on_enter_loop(const Queue&, const Graph&) { return true; } }; // default_r_c_shortest_paths_visitor // default_r_c_shortest_paths_allocator -typedef std::allocator< int > default_r_c_shortest_paths_allocator; +using default_r_c_shortest_paths_allocator = std::allocator< int >; // default_r_c_shortest_paths_allocator +// ---------------------------- New set of overloads -// r_c_shortest_paths functions (handle/interface) +// New r_c_shortest_paths functions (handle/interface) // first overload: // - return all pareto-optimal solutions -// - specify Label_Allocator and Visitor arguments -template < class Graph, class VertexIndexMap, class EdgeIndexMap, - class Resource_Container, class Resource_Extension_Function, - class Dominance_Function, class Label_Allocator, class Visitor > +// - specify LabelAllocator and Visitor arguments +template < class Graph, class VertexIndexMap, class ResourceContainer, + class ResourceExtensionFunction, class DominanceFunction, + class LabelAllocator, class Visitor > void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, - const EdgeIndexMap& edge_index_map, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, // each inner vector corresponds to a pareto-optimal path std::vector< std::vector< typename graph_traits< Graph >::edge_descriptor > >& pareto_optimal_solutions, - std::vector< Resource_Container >& pareto_optimal_resource_containers, + std::vector< ResourceContainer >& pareto_optimal_resource_containers, // to initialize the first label/resource container // and to carry the type information - const Resource_Container& rc, const Resource_Extension_Function& ref, - const Dominance_Function& dominance, + const ResourceContainer& rc, const ResourceExtensionFunction& ref, + const DominanceFunction& dominance, // to specify the memory management strategy for the labels - Label_Allocator la, Visitor vis) + LabelAllocator la, Visitor vis) { - r_c_shortest_paths_dispatch(g, vertex_index_map, edge_index_map, s, t, + r_c_shortest_paths_dispatch(g, vertex_index_map, s, t, pareto_optimal_solutions, pareto_optimal_resource_containers, true, rc, ref, dominance, la, vis); } // second overload: // - return only one pareto-optimal solution -// - specify Label_Allocator and Visitor arguments -template < class Graph, class VertexIndexMap, class EdgeIndexMap, - class Resource_Container, class Resource_Extension_Function, - class Dominance_Function, class Label_Allocator, class Visitor > +// - specify LabelAllocator and Visitor arguments +template < class Graph, class VertexIndexMap, class ResourceContainer, + class ResourceExtensionFunction, class DominanceFunction, + class LabelAllocator, class Visitor > void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, - const EdgeIndexMap& edge_index_map, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, std::vector< typename graph_traits< Graph >::edge_descriptor >& pareto_optimal_solution, - Resource_Container& pareto_optimal_resource_container, + ResourceContainer& pareto_optimal_resource_container, // to initialize the first label/resource container // and to carry the type information - const Resource_Container& rc, const Resource_Extension_Function& ref, - const Dominance_Function& dominance, + const ResourceContainer& rc, const ResourceExtensionFunction& ref, + const DominanceFunction& dominance, // to specify the memory management strategy for the labels - Label_Allocator la, Visitor vis) + LabelAllocator la, Visitor vis) { // each inner vector corresponds to a pareto-optimal path std::vector< std::vector< typename graph_traits< Graph >::edge_descriptor > > pareto_optimal_solutions; - std::vector< Resource_Container > pareto_optimal_resource_containers; - r_c_shortest_paths_dispatch(g, vertex_index_map, edge_index_map, s, t, + std::vector< ResourceContainer > pareto_optimal_resource_containers; + r_c_shortest_paths_dispatch(g, vertex_index_map, s, t, pareto_optimal_solutions, pareto_optimal_resource_containers, false, rc, ref, dominance, la, vis); if (!pareto_optimal_solutions.empty()) @@ -594,25 +543,23 @@ void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, // third overload: // - return all pareto-optimal solutions -// - use default Label_Allocator and Visitor -template < class Graph, class VertexIndexMap, class EdgeIndexMap, - class Resource_Container, class Resource_Extension_Function, - class Dominance_Function > +// - use default LabelAllocator and Visitor +template < class Graph, class VertexIndexMap, class ResourceContainer, + class ResourceExtensionFunction, class DominanceFunction > void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, - const EdgeIndexMap& edge_index_map, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, // each inner vector corresponds to a pareto-optimal path std::vector< std::vector< typename graph_traits< Graph >::edge_descriptor > >& pareto_optimal_solutions, - std::vector< Resource_Container >& pareto_optimal_resource_containers, + std::vector< ResourceContainer >& pareto_optimal_resource_containers, // to initialize the first label/resource container // and to carry the type information - const Resource_Container& rc, const Resource_Extension_Function& ref, - const Dominance_Function& dominance) + const ResourceContainer& rc, const ResourceExtensionFunction& ref, + const DominanceFunction& dominance) { - r_c_shortest_paths_dispatch(g, vertex_index_map, edge_index_map, s, t, + r_c_shortest_paths_dispatch(g, vertex_index_map, s, t, pareto_optimal_solutions, pareto_optimal_resource_containers, true, rc, ref, dominance, default_r_c_shortest_paths_allocator(), default_r_c_shortest_paths_visitor()); @@ -620,28 +567,26 @@ void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, // fourth overload: // - return only one pareto-optimal solution -// - use default Label_Allocator and Visitor -template < class Graph, class VertexIndexMap, class EdgeIndexMap, - class Resource_Container, class Resource_Extension_Function, - class Dominance_Function > +// - use default LabelAllocator and Visitor +template < class Graph, class VertexIndexMap, class ResourceContainer, + class ResourceExtensionFunction, class DominanceFunction > void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, - const EdgeIndexMap& edge_index_map, typename graph_traits< Graph >::vertex_descriptor s, typename graph_traits< Graph >::vertex_descriptor t, std::vector< typename graph_traits< Graph >::edge_descriptor >& pareto_optimal_solution, - Resource_Container& pareto_optimal_resource_container, + ResourceContainer& pareto_optimal_resource_container, // to initialize the first label/resource container // and to carry the type information - const Resource_Container& rc, const Resource_Extension_Function& ref, - const Dominance_Function& dominance) + const ResourceContainer& rc, const ResourceExtensionFunction& ref, + const DominanceFunction& dominance) { // each inner vector corresponds to a pareto-optimal path std::vector< std::vector< typename graph_traits< Graph >::edge_descriptor > > pareto_optimal_solutions; - std::vector< Resource_Container > pareto_optimal_resource_containers; - r_c_shortest_paths_dispatch(g, vertex_index_map, edge_index_map, s, t, + std::vector< ResourceContainer > pareto_optimal_resource_containers; + r_c_shortest_paths_dispatch(g, vertex_index_map, s, t, pareto_optimal_solutions, pareto_optimal_resource_containers, false, rc, ref, dominance, default_r_c_shortest_paths_allocator(), default_r_c_shortest_paths_visitor()); @@ -652,23 +597,133 @@ void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, = pareto_optimal_resource_containers[0]; } } + +// ---------------------------- Old r_c_shortest_paths functions +// (handle/interface) These functions are kept durign the deprecation cycle, but +// their logic falls back to the new functions + +// first overload: +// - return all pareto-optimal solutions +// - specify LabelAllocator and Visitor arguments +template < class Graph, class VertexIndexMap, class EdgeIndexMap, + class ResourceContainer, class ResourceExtensionFunction, + class DominanceFunction, class LabelAllocator, class Visitor > +BOOST_DEPRECATED("edge_index_map is unused; drop it and call the 5-argument " + "r_c_shortest_paths overload. Removal planned for Boost 1.95.") +void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, + const EdgeIndexMap& edge_index_map, + typename graph_traits< Graph >::vertex_descriptor s, + typename graph_traits< Graph >::vertex_descriptor t, + // each inner vector corresponds to a pareto-optimal path + std::vector< + std::vector< typename graph_traits< Graph >::edge_descriptor > >& + pareto_optimal_solutions, + std::vector< ResourceContainer >& pareto_optimal_resource_containers, + // to initialize the first label/resource container + // and to carry the type information + const ResourceContainer& rc, const ResourceExtensionFunction& ref, + const DominanceFunction& dominance, + // to specify the memory management strategy for the labels + LabelAllocator la, Visitor vis) +{ + r_c_shortest_paths(g, vertex_index_map, s, t, pareto_optimal_solutions, + pareto_optimal_resource_containers, rc, ref, dominance, la, vis); +} + +// second overload: +// - return only one pareto-optimal solution +// - specify LabelAllocator and Visitor arguments +template < class Graph, class VertexIndexMap, class EdgeIndexMap, + class ResourceContainer, class ResourceExtensionFunction, + class DominanceFunction, class LabelAllocator, class Visitor > +BOOST_DEPRECATED("edge_index_map is unused; drop it and call the 5-argument " + "r_c_shortest_paths overload. Removal planned for Boost 1.95.") +void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, + const EdgeIndexMap& edge_index_map, + typename graph_traits< Graph >::vertex_descriptor s, + typename graph_traits< Graph >::vertex_descriptor t, + std::vector< typename graph_traits< Graph >::edge_descriptor >& + pareto_optimal_solution, + ResourceContainer& pareto_optimal_resource_container, + // to initialize the first label/resource container + // and to carry the type information + const ResourceContainer& rc, const ResourceExtensionFunction& ref, + const DominanceFunction& dominance, + // to specify the memory management strategy for the labels + LabelAllocator la, Visitor vis) +{ + r_c_shortest_paths(g, vertex_index_map, s, t, pareto_optimal_solution, + pareto_optimal_resource_container, rc, ref, dominance, la, vis); +} + +// third overload: +// - return all pareto-optimal solutions +// - use default LabelAllocator and Visitor +template < class Graph, class VertexIndexMap, class EdgeIndexMap, + class ResourceContainer, class ResourceExtensionFunction, + class DominanceFunction > +BOOST_DEPRECATED("edge_index_map is unused; drop it and call the 5-argument " + "r_c_shortest_paths overload. Removal planned for Boost 1.95.") +void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, + const EdgeIndexMap& edge_index_map, + typename graph_traits< Graph >::vertex_descriptor s, + typename graph_traits< Graph >::vertex_descriptor t, + // each inner vector corresponds to a pareto-optimal path + std::vector< + std::vector< typename graph_traits< Graph >::edge_descriptor > >& + pareto_optimal_solutions, + std::vector< ResourceContainer >& pareto_optimal_resource_containers, + // to initialize the first label/resource container + // and to carry the type information + const ResourceContainer& rc, const ResourceExtensionFunction& ref, + const DominanceFunction& dominance) +{ + r_c_shortest_paths(g, vertex_index_map, s, t, pareto_optimal_solutions, + pareto_optimal_resource_containers, rc, ref, dominance, + default_r_c_shortest_paths_allocator(), + default_r_c_shortest_paths_visitor()); +} + +// fourth overload: +// - return only one pareto-optimal solution +// - use default LabelAllocator and Visitor +template < class Graph, class VertexIndexMap, class EdgeIndexMap, + class ResourceContainer, class ResourceExtensionFunction, + class DominanceFunction > +BOOST_DEPRECATED("edge_index_map is unused; drop it and call the 5-argument " + "r_c_shortest_paths overload. Removal planned for Boost 1.95.") +void r_c_shortest_paths(const Graph& g, const VertexIndexMap& vertex_index_map, + const EdgeIndexMap& edge_index_map, + typename graph_traits< Graph >::vertex_descriptor s, + typename graph_traits< Graph >::vertex_descriptor t, + std::vector< typename graph_traits< Graph >::edge_descriptor >& + pareto_optimal_solution, + ResourceContainer& pareto_optimal_resource_container, + // to initialize the first label/resource container + // and to carry the type information + const ResourceContainer& rc, const ResourceExtensionFunction& ref, + const DominanceFunction& dominance) +{ + r_c_shortest_paths(g, vertex_index_map, s, t, pareto_optimal_solution, + pareto_optimal_resource_container, rc, ref, dominance); +} // r_c_shortest_paths // check_r_c_path function -template < class Graph, class Resource_Container, - class Resource_Extension_Function > +template < class Graph, class ResourceContainer, + class ResourceExtensionFunction > void check_r_c_path(const Graph& g, const std::vector< typename graph_traits< Graph >::edge_descriptor >& ed_vec_path, - const Resource_Container& initial_resource_levels, + const ResourceContainer& initial_resource_levels, // if true, computed accumulated final resource levels must // be equal to desired_final_resource_levels // if false, computed accumulated final resource levels must // be less than or equal to desired_final_resource_levels bool b_result_must_be_equal_to_desired_final_resource_levels, - const Resource_Container& desired_final_resource_levels, - Resource_Container& actual_final_resource_levels, - const Resource_Extension_Function& ref, bool& b_is_a_path_at_all, + const ResourceContainer& desired_final_resource_levels, + ResourceContainer& actual_final_resource_levels, + const ResourceExtensionFunction& ref, bool& b_is_a_path_at_all, bool& b_feasible, bool& b_correctly_extended, typename graph_traits< Graph >::edge_descriptor& ed_last_extended_arc) { @@ -698,7 +753,7 @@ void check_r_c_path(const Graph& g, b_is_a_path_at_all = true; b_feasible = true; b_correctly_extended = false; - Resource_Container current_resource_levels = initial_resource_levels; + ResourceContainer current_resource_levels = initial_resource_levels; actual_final_resource_levels = current_resource_levels; for (size_t i = 0; i < i_size_ed_vec_path; ++i) { diff --git a/include/boost/graph/random.hpp b/include/boost/graph/random.hpp index ea6e58b0b..f99265dc2 100644 --- a/include/boost/graph/random.hpp +++ b/include/boost/graph/random.hpp @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include @@ -152,7 +152,7 @@ void generate_random_graph1(MutableGraph& g, typedef typename boost::graph_traits< MutableGraph >::directed_category dir; - typedef typename mpl::if_< is_convertible< dir, directed_tag >, + typedef typename std::conditional< is_convertible< dir, directed_tag >::value, directedS, undirectedS >::type select; adjacency_list< setS, vecS, select > g2; generate_random_graph1(g2, V, E, gen, true, self_edges); diff --git a/include/boost/graph/random_layout.hpp b/include/boost/graph/random_layout.hpp index 757585ced..3384d7881 100644 --- a/include/boost/graph/random_layout.hpp +++ b/include/boost/graph/random_layout.hpp @@ -14,7 +14,6 @@ #include #include #include -#include #include namespace boost diff --git a/include/boost/graph/reverse_graph.hpp b/include/boost/graph/reverse_graph.hpp index 86bcdc408..b1f7f4ac4 100644 --- a/include/boost/graph/reverse_graph.hpp +++ b/include/boost/graph/reverse_graph.hpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include namespace boost { @@ -477,15 +477,15 @@ struct property_map< reverse_graph< BidirGraph, GRef >, Property > is_edge_prop; typedef boost::is_const< typename boost::remove_reference< GRef >::type > is_ref_const; - typedef typename boost::mpl::if_< is_ref_const, + typedef typename std::conditional< is_ref_const::value, typename property_map< BidirGraph, Property >::const_type, typename property_map< BidirGraph, Property >::type >::type orig_type; typedef typename property_map< BidirGraph, Property >::const_type orig_const_type; - typedef typename boost::mpl::if_< is_edge_prop, + typedef typename std::conditional< is_edge_prop::value, detail::reverse_graph_edge_property_map< orig_type >, orig_type >::type type; - typedef typename boost::mpl::if_< is_edge_prop, + typedef typename std::conditional< is_edge_prop::value, detail::reverse_graph_edge_property_map< orig_const_type >, orig_const_type >::type const_type; }; @@ -499,7 +499,7 @@ struct property_map< const reverse_graph< BidirGraph, GRef >, Property > is_edge_prop; typedef typename property_map< BidirGraph, Property >::const_type orig_const_type; - typedef typename boost::mpl::if_< is_edge_prop, + typedef typename std::conditional< is_edge_prop::value, detail::reverse_graph_edge_property_map< orig_const_type >, orig_const_type >::type const_type; typedef const_type type; @@ -585,11 +585,11 @@ struct property_map< reverse_graph< Graph, GRef >, edge_underlying_t > typedef detail::underlying_edge_desc_map_type< ed > const_type; }; -template < typename T > struct is_reverse_graph : boost::mpl::false_ +template < typename T > struct is_reverse_graph : std::false_type { }; template < typename G, typename R > -struct is_reverse_graph< reverse_graph< G, R > > : boost::mpl::true_ +struct is_reverse_graph< reverse_graph< G, R > > : std::true_type { }; @@ -641,8 +641,8 @@ inline void set_property(const reverse_graph< BidirectionalGraph, GRef >& g, } template < typename BidirectionalGraph, typename GRef, typename Tag > -inline typename boost::mpl::if_< - boost::is_const< typename boost::remove_reference< GRef >::type >, +inline typename std::conditional< + boost::is_const< typename boost::remove_reference< GRef >::type >::value, const typename graph_property< BidirectionalGraph, Tag >::type&, typename graph_property< BidirectionalGraph, Tag >::type& >::type get_property(const reverse_graph< BidirectionalGraph, GRef >& g, Tag tag) diff --git a/include/boost/graph/rmat_graph_generator.hpp b/include/boost/graph/rmat_graph_generator.hpp index 1a2c838fe..4e935adc7 100644 --- a/include/boost/graph/rmat_graph_generator.hpp +++ b/include/boost/graph/rmat_graph_generator.hpp @@ -15,17 +15,15 @@ #include #include #include -#include +#include #include #include #include #include -#include #include #include // #include -using boost::shared_ptr; using boost::uniform_01; // Returns floor(log_2(n)), and -1 when n is 0 @@ -84,7 +82,8 @@ void generate_permutation_vector( template < typename RandomGenerator, typename T > std::pair< T, T > generate_edge( - shared_ptr< uniform_01< RandomGenerator > > prob, T n, unsigned int SCALE, + std::shared_ptr< uniform_01< RandomGenerator > > prob, T n, + unsigned int SCALE, double a, double b, double c, double d) { T u = 0, v = 0; @@ -233,7 +232,7 @@ template < typename RandomGenerator, typename Graph > class rmat_iterator private: // Parameters - shared_ptr< uniform_01< RandomGenerator > > gen; + std::shared_ptr< uniform_01< RandomGenerator > > gen; vertices_size_type n; double a, b, c, d; int edge; @@ -359,7 +358,7 @@ class sorted_rmat_iterator private: // Parameters - shared_ptr< uniform_01< RandomGenerator > > gen; + std::shared_ptr< uniform_01< RandomGenerator > > gen; bool permute_vertices; // Internal data structures @@ -484,7 +483,7 @@ class unique_rmat_iterator private: // Parameters - shared_ptr< uniform_01< RandomGenerator > > gen; + std::shared_ptr< uniform_01< RandomGenerator > > gen; // Internal data structures std::vector< value_type > values; @@ -645,7 +644,7 @@ class sorted_unique_rmat_iterator private: // Parameters - shared_ptr< uniform_01< RandomGenerator > > gen; + std::shared_ptr< uniform_01< RandomGenerator > > gen; bool bidirectional; // Internal data structures @@ -658,6 +657,4 @@ class sorted_unique_rmat_iterator } // end namespace boost -#include BOOST_GRAPH_MPI_INCLUDE() - #endif // BOOST_GRAPH_RMAT_GENERATOR_HPP diff --git a/include/boost/graph/stanford_graph.hpp b/include/boost/graph/stanford_graph.hpp index a3b949e61..2f280e8fa 100644 --- a/include/boost/graph/stanford_graph.hpp +++ b/include/boost/graph/stanford_graph.hpp @@ -50,6 +50,7 @@ extern "C" #include /* graphs based on football scores */ #undef ap /* avoid name clash with BGL parameter */ // ap ==> Vertex::u.I +#undef MAX_N /* redefinition in gb_miles.h below; unused */ #include /* graphs based on logic circuits */ #undef val /* avoid name clash with g++ headerfile stl_tempbuf.h */ // val ==> Vertex::x.I @@ -63,6 +64,7 @@ extern "C" #include /* five-letter-word graphs */ #undef weight /* avoid name clash with BGL parameter */ // weight ==> Vertex::u.I +#undef loc /* avoid name clash with boost/assert/source_location.hpp */ } namespace boost @@ -401,26 +403,26 @@ class sgb_edge_util_map template < class Tag > inline sgb_vertex_util_map< Tag, const typename Tag::type& > get_property_map( - Tag, const sgb_graph_ptr& g, vertex_property_tag) + Tag, const sgb_graph_ptr&, vertex_property_tag) { return sgb_vertex_util_map< Tag, const typename Tag::type& >(); } template < class Tag > inline sgb_vertex_util_map< Tag, typename Tag::type& > get_property_map( - Tag, sgb_graph_ptr& g, vertex_property_tag) + Tag, sgb_graph_ptr&, vertex_property_tag) { return sgb_vertex_util_map< Tag, typename Tag::type& >(); } template < class Tag > inline sgb_edge_util_map< Tag, const typename Tag::type& > get_property_map( - Tag, const sgb_graph_ptr& g, edge_property_tag) + Tag, const sgb_graph_ptr&, edge_property_tag) { return sgb_edge_util_map< Tag, const typename Tag::type& >(); } template < class Tag > inline sgb_edge_util_map< Tag, typename Tag::type& > get_property_map( - Tag, sgb_graph_ptr& g, edge_property_tag) + Tag, sgb_graph_ptr&, edge_property_tag) { return sgb_edge_util_map< Tag, typename Tag::type& >(); } diff --git a/include/boost/graph/stoer_wagner_min_cut.hpp b/include/boost/graph/stoer_wagner_min_cut.hpp index 33ef6e969..560949d11 100644 --- a/include/boost/graph/stoer_wagner_min_cut.hpp +++ b/include/boost/graph/stoer_wagner_min_cut.hpp @@ -20,15 +20,40 @@ #include #include #include +#include #include #include #include +#include + namespace boost { namespace detail { + // Records the phase cut: the last two vertices swept and the reach count of the last. + template < class UndirectedGraph, class KeyMap, class WeightType > + struct mas_phase_recorder : public boost::graph::default_mas_visitor + { + using vertex_descriptor = typename boost::graph_traits< UndirectedGraph >::vertex_descriptor; + + mas_phase_recorder(vertex_descriptor& s, vertex_descriptor& t, WeightType& w, KeyMap keys) + : s_(s), t_(t), w_(w), keys_(keys) {} + + void start_vertex(vertex_descriptor u, const UndirectedGraph&) + { + s_ = t_; + t_ = u; + w_ = get(keys_, u); + } + + vertex_descriptor& s_; + vertex_descriptor& t_; + WeightType& w_; + KeyMap keys_; + }; + /** * \brief Performs a phase of the Stoer-Wagner min-cut algorithm * @@ -95,61 +120,16 @@ namespace detail BOOST_ASSERT(pq.size() >= 2); - vertex_descriptor s - = boost::graph_traits< UndirectedGraph >::null_vertex(); - vertex_descriptor t - = boost::graph_traits< UndirectedGraph >::null_vertex(); - weight_type w; - while (!pq.empty()) - { // while PQ \neq {} do - const vertex_descriptor u = pq.top(); // u = extractmax(PQ) - w = get(keys, u); - pq.pop(); - - s = t; - t = u; - - BGL_FORALL_OUTEDGES_T(u, e, g, UndirectedGraph) - { // foreach (u, v) \in E do - const vertex_descriptor v = get(assignments, target(e, g)); - - if (pq.contains(v)) - { // if v \in PQ then - put(keys, v, - get(keys, v) - + get(weights, - e)); // increasekey(PQ, v, wA(v) + w(u, v)) - pq.update(v); - } - } + // the cut of the phase is the last two vertices the maximum adjacency + // sweep visits and the reach count of the last one + vertex_descriptor s = boost::graph_traits< UndirectedGraph >::null_vertex(); + vertex_descriptor t = boost::graph_traits< UndirectedGraph >::null_vertex(); + weight_type w = weight_type(0); - typename std::set< vertex_descriptor >::const_iterator - assignedVertexIt, - assignedVertexEnd = assignedVertices.end(); - for (assignedVertexIt = assignedVertices.begin(); - assignedVertexIt != assignedVertexEnd; ++assignedVertexIt) - { - const vertex_descriptor uPrime = *assignedVertexIt; + using vis_t = mas_phase_recorder< UndirectedGraph, typename KeyedUpdatablePriorityQueue::key_map, weight_type >; + vis_t recorder(s, t, w, keys); - if (get(assignments, uPrime) == u) - { - BGL_FORALL_OUTEDGES_T(uPrime, e, g, UndirectedGraph) - { // foreach (u, v) \in E do - const vertex_descriptor v - = get(assignments, target(e, g)); - - if (pq.contains(v)) - { // if v \in PQ then - put(keys, v, - get(keys, v) - + get(weights, e)); // increasekey(PQ, v, - // wA(v) + w(u, v)) - pq.update(v); - } - } - } - } - } + boost::graph::mas_detail::mas_sweep(g, weights, recorder, assignments, assignedVertices, pq); return boost::make_tuple(s, t, w); } @@ -262,120 +242,136 @@ namespace detail } } // end `namespace detail` within `namespace boost` -template < class UndirectedGraph, class WeightMap, class ParityMap, - class VertexAssignmentMap, class KeyedUpdatablePriorityQueue, - class IndexMap > -typename boost::property_traits< WeightMap >::value_type stoer_wagner_min_cut( - const UndirectedGraph& g, WeightMap weights, ParityMap parities, - VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue& pq, - IndexMap index_map) -{ - BOOST_CONCEPT_ASSERT((boost::IncidenceGraphConcept< UndirectedGraph >)); - BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept< UndirectedGraph >)); - typedef typename boost::graph_traits< UndirectedGraph >::vertex_descriptor - vertex_descriptor; - typedef typename boost::graph_traits< UndirectedGraph >::vertices_size_type - vertices_size_type; - typedef typename boost::graph_traits< UndirectedGraph >::edge_descriptor - edge_descriptor; - BOOST_CONCEPT_ASSERT((boost::Convertible< - typename boost::graph_traits< UndirectedGraph >::directed_category, - boost::undirected_tag >)); - BOOST_CONCEPT_ASSERT( - (boost::ReadablePropertyMapConcept< WeightMap, edge_descriptor >)); - // typedef typename boost::property_traits::value_type - // weight_type; - BOOST_CONCEPT_ASSERT( - (boost::WritablePropertyMapConcept< ParityMap, vertex_descriptor >)); - // typedef typename boost::property_traits::value_type - // parity_type; - BOOST_CONCEPT_ASSERT( - (boost::ReadWritePropertyMapConcept< VertexAssignmentMap, - vertex_descriptor >)); - BOOST_CONCEPT_ASSERT((boost::Convertible< vertex_descriptor, - typename boost::property_traits< VertexAssignmentMap >::value_type >)); - BOOST_CONCEPT_ASSERT( - (boost::KeyedUpdatableQueueConcept< KeyedUpdatablePriorityQueue >)); - - vertices_size_type n = num_vertices(g); - if (n < 2) - throw boost::bad_graph( - "the input graph must have at least two vertices."); - else if (!pq.empty()) - throw std::invalid_argument( - "the max-priority queue must be empty initially."); - - return detail::stoer_wagner_min_cut( - g, weights, parities, assignments, pq, index_map); -} - namespace graph { + // Fully positional 6-args + template < class UndirectedGraph, class WeightMap, class ParityMap, + class VertexAssignmentMap, class KeyedUpdatablePriorityQueue, + class IndexMap > + typename boost::property_traits< WeightMap >::value_type + stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, + ParityMap parities, VertexAssignmentMap assignments, + KeyedUpdatablePriorityQueue& pq, IndexMap index_map) + { + using vertex_descriptor = typename boost::graph_traits< UndirectedGraph >::vertex_descriptor; + using vertices_size_type = typename boost::graph_traits< UndirectedGraph >::vertices_size_type; + using edge_descriptor = typename boost::graph_traits< UndirectedGraph >::edge_descriptor; + + BOOST_CONCEPT_ASSERT((boost::IncidenceGraphConcept< UndirectedGraph >)); + BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept< UndirectedGraph >)); + BOOST_CONCEPT_ASSERT((boost::Convertible< typename boost::graph_traits< UndirectedGraph >::directed_category, boost::undirected_tag >)); + BOOST_CONCEPT_ASSERT((boost::ReadablePropertyMapConcept< WeightMap, edge_descriptor >)); + BOOST_CONCEPT_ASSERT((boost::WritablePropertyMapConcept< ParityMap, vertex_descriptor >)); + BOOST_CONCEPT_ASSERT((boost::ReadWritePropertyMapConcept< VertexAssignmentMap, vertex_descriptor >)); + BOOST_CONCEPT_ASSERT((boost::Convertible< vertex_descriptor, typename boost::property_traits< VertexAssignmentMap >::value_type >)); + BOOST_CONCEPT_ASSERT((boost::KeyedUpdatableQueueConcept< KeyedUpdatablePriorityQueue >)); + + const vertices_size_type n = num_vertices(g); + if (n < 2) + throw boost::bad_graph("the input graph must have at least two vertices."); + else if (!pq.empty()) + throw std::invalid_argument("the max-priority queue must be empty initially."); + + return boost::detail::stoer_wagner_min_cut(g, weights, parities, assignments, pq, index_map); + } + + // Positional 5-args + template < class UndirectedGraph, class WeightMap, class ParityMap, + class VertexAssignmentMap, class KeyedUpdatablePriorityQueue > + typename boost::property_traits< WeightMap >::value_type + stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, + ParityMap parities, VertexAssignmentMap assignments, + KeyedUpdatablePriorityQueue& pq) + { + return boost::graph::stoer_wagner_min_cut(g, weights, parities, assignments, pq, get(vertex_index, g)); + } + + // Positional 3-args. + template < class UndirectedGraph, class WeightMap, class ParityMap > + typename boost::property_traits< WeightMap >::value_type + stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities) + { + using vertex_descriptor = typename boost::graph_traits< UndirectedGraph >::vertex_descriptor; + using weight_type = typename boost::property_traits< WeightMap >::value_type; + using vertex_index_map_type = typename boost::property_map< UndirectedGraph, boost::vertex_index_t >::const_type; + using distance_map_type = boost::shared_array_property_map< weight_type, vertex_index_map_type >; + using index_in_heap_type = typename std::vector< vertex_descriptor >::size_type; + using index_in_heap_map_type = boost::shared_array_property_map< index_in_heap_type, vertex_index_map_type >; + using priority_queue_type = boost::d_ary_heap_indirect< vertex_descriptor, 4, index_in_heap_map_type, distance_map_type, std::greater< weight_type > >; + using assignment_map_type = boost::shared_array_property_map< vertex_descriptor, vertex_index_map_type >; + + const vertex_index_map_type vertex_index_map = get(boost::vertex_index, g); + distance_map_type distance_map = boost::make_shared_array_property_map(num_vertices(g), weight_type(0), vertex_index_map); + index_in_heap_map_type index_in_heap_map = boost::make_shared_array_property_map(num_vertices(g), index_in_heap_type(-1), vertex_index_map); + priority_queue_type pq(distance_map, index_in_heap_map); + assignment_map_type assignment_map = boost::make_shared_array_property_map(num_vertices(g), vertex_descriptor(), vertex_index_map); + + return boost::graph::stoer_wagner_min_cut(g, weights, parities, assignment_map, pq, vertex_index_map); + } + namespace detail { template < class UndirectedGraph, class WeightMap > struct stoer_wagner_min_cut_impl { - typedef typename boost::property_traits< WeightMap >::value_type - result_type; + using result_type = typename boost::property_traits< WeightMap >::value_type; template < typename ArgPack > - result_type operator()(const UndirectedGraph& g, WeightMap weights, - const ArgPack& arg_pack) const + result_type operator()(const UndirectedGraph& g, WeightMap weights, const ArgPack& arg_pack) const { using namespace boost::graph::keywords; - typedef typename boost::graph_traits< - UndirectedGraph >::vertex_descriptor vertex_descriptor; - typedef typename boost::property_traits< WeightMap >::value_type - weight_type; - - typedef boost::detail::make_priority_queue_from_arg_pack_gen< - boost::graph::keywords::tag::max_priority_queue, - weight_type, vertex_descriptor, - std::greater< weight_type > > - gen_type; + using vertex_descriptor = typename boost::graph_traits< UndirectedGraph >::vertex_descriptor; + using weight_type = typename boost::property_traits< WeightMap >::value_type; + using gen_type = boost::detail::make_priority_queue_from_arg_pack_gen< boost::graph::keywords::tag::max_priority_queue, weight_type, vertex_descriptor, std::greater< weight_type > >; - gen_type gen( - choose_param(get_param(arg_pack, boost::distance_zero_t()), - weight_type(0))); - - typename boost::result_of< gen_type( - const UndirectedGraph&, const ArgPack&) >::type pq - = gen(g, arg_pack); + gen_type gen(choose_param(get_param(arg_pack, boost::distance_zero_t()), weight_type(0))); + typename boost::result_of< gen_type(const UndirectedGraph&, const ArgPack&) >::type pq = gen(g, arg_pack); boost::dummy_property_map dummy_prop; - return boost::stoer_wagner_min_cut(g, weights, + return boost::graph::stoer_wagner_min_cut(g, weights, arg_pack[_parity_map | dummy_prop], - boost::detail::make_property_map_from_arg_pack_gen< - tag::vertex_assignment_map, vertex_descriptor >( - vertex_descriptor())(g, arg_pack), + boost::detail::make_property_map_from_arg_pack_gen< tag::vertex_assignment_map, vertex_descriptor >(vertex_descriptor())(g, arg_pack), pq, - boost::detail::override_const_property( - arg_pack, _vertex_index_map, g, vertex_index)); + boost::detail::override_const_property(arg_pack, _vertex_index_map, g, vertex_index)); } }; } + // Generates the tagged-keyword Boost.Parameter overloads dispatching to stoer_wagner_min_cut_impl. BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(stoer_wagner_min_cut, 2, 4) +} // end `namespace graph` + +// -- deprecated overloads -- + +template < class UndirectedGraph, class WeightMap, class ParityMap, + class VertexAssignmentMap, class KeyedUpdatablePriorityQueue, class IndexMap > +BOOST_DEPRECATED("use the positional boost::graph::stoer_wagner_min_cut. Removal planned for Boost 1.95.") +typename boost::property_traits< WeightMap >::value_type +stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, ParityMap parities, + VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue& pq, IndexMap index_map) +{ + return graph::stoer_wagner_min_cut(g, weights, parities, assignments, pq, index_map); } // Named parameter interface -BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(stoer_wagner_min_cut, 2) -namespace graph +template < class UndirectedGraph, class WeightMap, class P, class T, class R > +BOOST_DEPRECATED("the named parameter interface is deprecated, use the positional boost::graph::stoer_wagner_min_cut. Removal planned for Boost 1.95.") +typename boost::property_traits< WeightMap >::value_type +stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, const bgl_named_params< P, T, R >& params) { - // version without IndexMap kept for backwards compatibility - // (but requires vertex_index_t to be defined in the graph) - // Place after the macro to avoid compilation errors - template < class UndirectedGraph, class WeightMap, class ParityMap, - class VertexAssignmentMap, class KeyedUpdatablePriorityQueue > - typename boost::property_traits< WeightMap >::value_type - stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights, - ParityMap parities, VertexAssignmentMap assignments, - KeyedUpdatablePriorityQueue& pq) - { + using params_type = bgl_named_params< P, T, R >; + // Converts the legacy bgl_named_params into the modern Boost.Parameter arg_pack the forwarding function expects. + BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params) + return graph::stoer_wagner_min_cut_with_named_params(g, weights, arg_pack); +} - return stoer_wagner_min_cut( - g, weights, parities, assignments, pq, get(vertex_index, g)); - } -} // end `namespace graph` +template < class UndirectedGraph, class WeightMap > +BOOST_DEPRECATED("the named parameter interface is deprecated, use the positional boost::graph::stoer_wagner_min_cut. Removal planned for Boost 1.95.") +typename boost::property_traits< WeightMap >::value_type +stoer_wagner_min_cut(const UndirectedGraph& g, WeightMap weights) +{ + // Converts the legacy bgl_named_params into the modern Boost.Parameter arg_pack the forwarding function expects. + BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(boost::no_named_parameters, boost::no_named_parameters()) + return graph::stoer_wagner_min_cut_with_named_params(g, weights, arg_pack); +} } // end `namespace boost` #include diff --git a/include/boost/graph/strong_components.hpp b/include/boost/graph/strong_components.hpp index 18e3f8fad..52b52613f 100644 --- a/include/boost/graph/strong_components.hpp +++ b/include/boost/graph/strong_components.hpp @@ -18,7 +18,6 @@ #include #include #include -#include #include namespace boost @@ -342,6 +341,4 @@ kosaraju_strong_components( } // namespace boost -#include BOOST_GRAPH_MPI_INCLUDE() - #endif // BOOST_GRAPH_STRONG_COMPONENTS_HPP diff --git a/include/boost/graph/subgraph.hpp b/include/boost/graph/subgraph.hpp index 7f8bd809e..21d623036 100644 --- a/include/boost/graph/subgraph.hpp +++ b/include/boost/graph/subgraph.hpp @@ -25,8 +25,7 @@ #include #include #include -#include -#include +#include namespace boost { @@ -207,12 +206,14 @@ template < typename Graph > class subgraph vertex_descriptor global_to_local(vertex_descriptor u_global) const { - vertex_descriptor u_local; - bool in_subgraph; if (is_root()) return u_global; + vertex_descriptor u_local; + bool in_subgraph; boost::tie(u_local, in_subgraph) = this->find_vertex(u_global); - BOOST_ASSERT(in_subgraph == true); + BOOST_ASSERT_MSG(in_subgraph, + "global_to_local: vertex is not in this subgraph. " + "Use find_vertex() to check membership first."); return u_local; } @@ -225,10 +226,15 @@ template < typename Graph > class subgraph edge_descriptor global_to_local(edge_descriptor e_global) const { - return is_root() ? e_global - : (*m_local_edge.find( - get(get(edge_index, root().m_graph), e_global))) - .second; + if (is_root()) + return e_global; + edge_descriptor e_local; + bool in_subgraph; + boost::tie(e_local, in_subgraph) = this->find_edge(e_global); + BOOST_ASSERT_MSG(in_subgraph, + "global_to_local: edge is not in this subgraph. " + "Use find_edge() to check membership first."); + return e_local; } // Is vertex u (of the root graph) contained in this subgraph? @@ -886,8 +892,8 @@ class subgraph_global_property_map typedef property_traits< PropertyMap > Traits; public: - typedef typename mpl::if_< - is_const< typename remove_pointer< GraphPtr >::type >, + typedef typename std::conditional< + is_const< typename remove_pointer< GraphPtr >::type >::value, readable_property_map_tag, typename Traits::category >::type category; typedef typename Traits::value_type value_type; typedef typename Traits::key_type key_type; @@ -919,8 +925,8 @@ class subgraph_local_property_map typedef property_traits< PropertyMap > Traits; public: - typedef typename mpl::if_< - is_const< typename remove_pointer< GraphPtr >::type >, + typedef typename std::conditional< + is_const< typename remove_pointer< GraphPtr >::type >::value, readable_property_map_tag, typename Traits::category >::type category; typedef typename Traits::value_type value_type; typedef typename Traits::key_type key_type; diff --git a/include/boost/graph/topology.hpp b/include/boost/graph/topology.hpp index 73dc3d944..e1117cae8 100644 --- a/include/boost/graph/topology.hpp +++ b/include/boost/graph/topology.hpp @@ -10,14 +10,13 @@ #ifndef BOOST_GRAPH_TOPOLOGY_HPP #define BOOST_GRAPH_TOPOLOGY_HPP -#include +#include #include // For BOOST_STATIC_CONSTANT #include -#include // For root_two -#include +#include #include #include -#include +#include #include @@ -155,7 +154,7 @@ template < std::size_t Dims > class convex_topology for (std::size_t i = 0; i < Dims; ++i) { double diff = b[i] - a[i]; - dist = boost::math::hypot(dist, diff); + dist = std::hypot(dist, diff); } // Exact properties of the distance are not important, as long as // < on what this returns matches real distances; l_2 is used because @@ -209,7 +208,7 @@ template < std::size_t Dims > class convex_topology { double n = 0.; for (std::size_t i = 0; i < Dims; ++i) - n = boost::math::hypot(n, delta[i]); + n = std::hypot(n, delta[i]); return n; } @@ -303,8 +302,8 @@ class hypercube_topology : public convex_topology< Dims > } private: - shared_ptr< RandomNumberGenerator > gen_ptr; - shared_ptr< rand_t > rand; + std::shared_ptr< RandomNumberGenerator > gen_ptr; + std::shared_ptr< rand_t > rand; double scaling; }; @@ -412,8 +411,8 @@ class rectangle_topology : public convex_topology< 2 > } private: - shared_ptr< RandomNumberGenerator > gen_ptr; - shared_ptr< rand_t > rand; + std::shared_ptr< RandomNumberGenerator > gen_ptr; + std::shared_ptr< rand_t > rand; double left, top, right, bottom; }; @@ -476,7 +475,7 @@ class ball_topology : public convex_topology< Dims > BOOST_USING_STD_MAX(); double r = 0.; for (std::size_t i = 0; i < Dims; ++i) - r = boost::math::hypot(r, a[i]); + r = std::hypot(r, a[i]); if (r <= radius) return a; double scaling_factor = radius / r; @@ -490,7 +489,7 @@ class ball_topology : public convex_topology< Dims > { double r = 0.; for (std::size_t i = 0; i < Dims; ++i) - r = boost::math::hypot(r, a[i]); + r = std::hypot(r, a[i]); return radius - r; } @@ -519,8 +518,8 @@ class ball_topology : public convex_topology< Dims > } private: - shared_ptr< RandomNumberGenerator > gen_ptr; - shared_ptr< rand_t > rand; + std::shared_ptr< RandomNumberGenerator > gen_ptr; + std::shared_ptr< rand_t > rand; double radius; }; @@ -560,6 +559,8 @@ template < typename RandomNumberGenerator = minstd_rand > class heart_topology // Circle centered at (500, -500) radius 500*sqrt(2) // Bounding box (-1000, -2000) - (1000, 500*(sqrt(2) - 1)) + static constexpr double root_two = 1.41421356237309504880; // sqrt(2) + struct point { point() @@ -590,11 +591,11 @@ template < typename RandomNumberGenerator = minstd_rand > class heart_topology return false; // Bottom if (p[1] <= -1000) return true; // Diagonal of square - if (boost::math::hypot(p[0] - -500, p[1] - -500) - <= 500. * boost::math::constants::root_two< double >()) + if (std::hypot(p[0] - -500, p[1] - -500) + <= 500. * root_two) return true; // Left circle - if (boost::math::hypot(p[0] - 500, p[1] - -500) - <= 500. * boost::math::constants::root_two< double >()) + if (std::hypot(p[0] - 500, p[1] - -500) + <= 500. * root_two) return true; // Right circle return false; } @@ -635,12 +636,12 @@ template < typename RandomNumberGenerator = minstd_rand > class heart_topology { result[0] = (*rand)() * (1000 - + 1000 * boost::math::constants::root_two< double >()) - - (500 + 500 * boost::math::constants::root_two< double >()); + + 1000 * root_two) + - (500 + 500 * root_two); result[1] = (*rand)() * (2000 + 500 - * (boost::math::constants::root_two< double >() + * (root_two - 1)) - 2000; } while (!in_heart(result)); @@ -655,13 +656,13 @@ template < typename RandomNumberGenerator = minstd_rand > class heart_topology if (segment_within_heart(a, b)) { // Straight line - return boost::math::hypot(b[0] - a[0], b[1] - a[1]); + return std::hypot(b[0] - a[0], b[1] - a[1]); } else { // Straight line bending around (0, 0) - return boost::math::hypot(a[0], a[1]) - + boost::math::hypot(b[0], b[1]); + return std::hypot(a[0], a[1]) + + std::hypot(b[0], b[1]); } } @@ -675,8 +676,8 @@ template < typename RandomNumberGenerator = minstd_rand > class heart_topology } else { - double distance_to_point_a = boost::math::hypot(a[0], a[1]); - double distance_to_point_b = boost::math::hypot(b[0], b[1]); + double distance_to_point_a = std::hypot(a[0], a[1]); + double distance_to_point_b = std::hypot(b[0], b[1]); double location_of_point = distance_to_point_a / (distance_to_point_a + distance_to_point_b); if (fraction < location_of_point) @@ -693,8 +694,8 @@ template < typename RandomNumberGenerator = minstd_rand > class heart_topology } private: - shared_ptr< RandomNumberGenerator > gen_ptr; - shared_ptr< rand_t > rand; + std::shared_ptr< RandomNumberGenerator > gen_ptr; + std::shared_ptr< rand_t > rand; }; } // namespace boost diff --git a/include/boost/graph/two_bit_color_map.hpp b/include/boost/graph/two_bit_color_map.hpp index a80264428..f63889eaa 100644 --- a/include/boost/graph/two_bit_color_map.hpp +++ b/include/boost/graph/two_bit_color_map.hpp @@ -15,8 +15,7 @@ #include #include -#include -#include +#include #include #include #include @@ -45,7 +44,8 @@ template < typename IndexMap = identity_property_map > struct two_bit_color_map { std::size_t n; IndexMap index; - shared_array< unsigned char > data; + // todo : C++17: replace with std::shared_ptr + std::shared_ptr< unsigned char > data; BOOST_STATIC_CONSTANT( int, bits_per_char = std::numeric_limits< unsigned char >::digits); @@ -59,7 +59,8 @@ template < typename IndexMap = identity_property_map > struct two_bit_color_map std::size_t n, const IndexMap& index = IndexMap()) : n(n) , index(index) - , data(new unsigned char[(n + elements_per_char - 1) / elements_per_char]()) + , data(new unsigned char[(n + elements_per_char - 1) / elements_per_char](), + std::default_delete< unsigned char[] >()) { } }; @@ -103,6 +104,4 @@ inline two_bit_color_map< IndexMap > make_two_bit_color_map( } // end namespace boost -#include BOOST_GRAPH_MPI_INCLUDE() - #endif // BOOST_TWO_BIT_COLOR_MAP_HPP diff --git a/include/boost/graph/two_graphs_common_spanning_trees.hpp b/include/boost/graph/two_graphs_common_spanning_trees.hpp index a41dc84b2..f2961ecf1 100644 --- a/include/boost/graph/two_graphs_common_spanning_trees.hpp +++ b/include/boost/graph/two_graphs_common_spanning_trees.hpp @@ -13,16 +13,18 @@ #include -#include #include #include #include #include #include #include +#include #include #include #include +#include +#include namespace boost { @@ -123,14 +125,44 @@ namespace detail InLMap mMap; }; + // Position/edge lookup used by the algorithm below. left maps a position + // index to its edge, right maps an edge back to its position. + template < typename Edge > struct index_bimap + { + using value_type = std::pair< std::size_t, Edge >; + + struct left_type + { + std::vector< Edge > store; + // i is a dense position in [0, n), so unchecked access is safe. + const Edge& operator[](std::size_t i) const { return store[i]; } + } left; + + struct right_type + { + using map_type = std::map< Edge, std::size_t >; + using const_iterator = typename map_type::const_iterator; + map_type store; + std::size_t at(const Edge& e) const { return store.at(e); } + const_iterator find(const Edge& e) const { return store.find(e); } + const_iterator end() const { return store.end(); } + } right; + + void insert(const value_type& v) + { + if (left.store.size() <= v.first) + left.store.resize(v.first + 1); + left.store[v.first] = v.second; + right.store[v.second] = v.first; + } + }; + template < typename Graph, typename Func, typename Seq, typename Map > void rec_two_graphs_common_spanning_trees(const Graph& iG, - bimap< bimaps::set_of< int >, - bimaps::set_of< typename graph_traits< Graph >::edge_descriptor > > + index_bimap< typename graph_traits< Graph >::edge_descriptor > iG_bimap, Map aiG_inL, Map diG, const Graph& vG, - bimap< bimaps::set_of< int >, - bimaps::set_of< typename graph_traits< Graph >::edge_descriptor > > + index_bimap< typename graph_traits< Graph >::edge_descriptor > vG_bimap, Map avG_inL, Map dvG, Func func, Seq inL) { @@ -179,11 +211,11 @@ namespace detail seq_size_type m; for (seq_size_type j = 0; j < inL.size() && !found; ++j) { - if (!inL[j] && !get(diG, iG_bimap.left.at(j)) - && !get(dvG, vG_bimap.left.at(j))) + if (!inL[j] && !get(diG, iG_bimap.left[j]) + && !get(dvG, vG_bimap.left[j])) { - put(aiG_inL, iG_bimap.left.at(j), true); - put(avG_inL, vG_bimap.left.at(j), true); + put(aiG_inL, iG_bimap.left[j], true); + put(avG_inL, vG_bimap.left[j], true); undirected_dfs( make_filtered_graph(iG, @@ -222,8 +254,8 @@ namespace detail iG_buf.pop(); while (!vG_buf.empty()) vG_buf.pop(); - put(aiG_inL, iG_bimap.left.at(j), false); - put(avG_inL, vG_bimap.left.at(j), false); + put(aiG_inL, iG_bimap.left[j], false); + put(avG_inL, vG_bimap.left[j], false); } } } @@ -234,12 +266,12 @@ namespace detail std::stack< edge_descriptor > iG_buf_copy, vG_buf_copy; for (seq_size_type j = 0; j < inL.size(); ++j) { - if (!inL[j] && !get(diG, iG_bimap.left.at(j)) - && !get(dvG, vG_bimap.left.at(j))) + if (!inL[j] && !get(diG, iG_bimap.left[j]) + && !get(dvG, vG_bimap.left[j])) { - put(aiG_inL, iG_bimap.left.at(j), true); - put(avG_inL, vG_bimap.left.at(j), true); + put(aiG_inL, iG_bimap.left[j], true); + put(avG_inL, vG_bimap.left[j], true); undirected_dfs( make_filtered_graph(iG, @@ -274,14 +306,14 @@ namespace detail iG_buf.pop(); while (!vG_buf.empty()) vG_buf.pop(); - put(diG, iG_bimap.left.at(j), true); - put(dvG, vG_bimap.left.at(j), true); - iG_buf_copy.push(iG_bimap.left.at(j)); - vG_buf_copy.push(vG_bimap.left.at(j)); + put(diG, iG_bimap.left[j], true); + put(dvG, vG_bimap.left[j], true); + iG_buf_copy.push(iG_bimap.left[j]); + vG_buf_copy.push(vG_bimap.left[j]); } - put(aiG_inL, iG_bimap.left.at(j), false); - put(avG_inL, vG_bimap.left.at(j), false); + put(aiG_inL, iG_bimap.left[j], false); + put(avG_inL, vG_bimap.left[j], false); } } @@ -294,7 +326,7 @@ namespace detail { put(diG, iG_buf_copy.top(), false); put(dvG, - vG_bimap.left.at(iG_bimap.right.at(iG_buf_copy.top())), + vG_bimap.left[iG_bimap.right.at(iG_buf_copy.top())], false); iG_buf_copy.pop(); } @@ -302,17 +334,17 @@ namespace detail { put(dvG, vG_buf_copy.top(), false); put(diG, - iG_bimap.left.at(vG_bimap.right.at(vG_buf_copy.top())), + iG_bimap.left[vG_bimap.right.at(vG_buf_copy.top())], false); vG_buf_copy.pop(); } inL[m] = false; - put(aiG_inL, iG_bimap.left.at(m), false); - put(avG_inL, vG_bimap.left.at(m), false); + put(aiG_inL, iG_bimap.left[m], false); + put(avG_inL, vG_bimap.left[m], false); - put(diG, iG_bimap.left.at(m), true); - put(dvG, vG_bimap.left.at(m), true); + put(diG, iG_bimap.left[m], true); + put(dvG, vG_bimap.left[m], true); std::map< vertex_descriptor, edge_descriptor > tree_map; std::map< vertex_descriptor, vertex_descriptor > pred_map; @@ -382,7 +414,7 @@ namespace detail { put(aiG_inL, iG_buf.top(), true); put(avG_inL, - vG_bimap.left.at(iG_bimap.right.at(iG_buf.top())), + vG_bimap.left[iG_bimap.right.at(iG_buf.top())], true); undirected_dfs( @@ -427,7 +459,7 @@ namespace detail put(aiG_inL, iG_buf.top(), false); put(avG_inL, - vG_bimap.left.at(iG_bimap.right.at(iG_buf.top())), + vG_bimap.left[iG_bimap.right.at(iG_buf.top())], false); } iG_buf.pop(); @@ -438,7 +470,7 @@ namespace detail { put(avG_inL, vG_buf.top(), true); put(aiG_inL, - iG_bimap.left.at(vG_bimap.right.at(vG_buf.top())), + iG_bimap.left[vG_bimap.right.at(vG_buf.top())], true); undirected_dfs( @@ -483,7 +515,7 @@ namespace detail put(avG_inL, vG_buf.top(), false); put(aiG_inL, - iG_bimap.left.at(vG_bimap.right.at(vG_buf.top())), + iG_bimap.left[vG_bimap.right.at(vG_buf.top())], false); } vG_buf.pop(); @@ -496,10 +528,7 @@ namespace detail { inL[iG_bimap.right.at(iG_buf_copy.top())] = true; put(aiG_inL, iG_buf_copy.top(), true); - put(avG_inL, - vG_bimap.left.at( - iG_bimap.right.at(iG_buf_copy.top())), - true); + put(avG_inL, vG_bimap.left[ iG_bimap.right.at(iG_buf_copy.top())], true); iG_buf.push(iG_buf_copy.top()); iG_buf_copy.pop(); } @@ -507,10 +536,7 @@ namespace detail { inL[vG_bimap.right.at(vG_buf_copy.top())] = true; put(avG_inL, vG_buf_copy.top(), true); - put(aiG_inL, - iG_bimap.left.at( - vG_bimap.right.at(vG_buf_copy.top())), - true); + put(aiG_inL, iG_bimap.left[ vG_bimap.right.at(vG_buf_copy.top())], true); vG_buf.push(vG_buf_copy.top()); vG_buf_copy.pop(); } @@ -524,24 +550,20 @@ namespace detail { inL[iG_bimap.right.at(iG_buf.top())] = false; put(aiG_inL, iG_buf.top(), false); - put(avG_inL, - vG_bimap.left.at(iG_bimap.right.at(iG_buf.top())), - false); + put(avG_inL, vG_bimap.left[iG_bimap.right.at(iG_buf.top())], false); iG_buf.pop(); } while (!vG_buf.empty()) { inL[vG_bimap.right.at(vG_buf.top())] = false; put(avG_inL, vG_buf.top(), false); - put(aiG_inL, - iG_bimap.left.at(vG_bimap.right.at(vG_buf.top())), - false); + put(aiG_inL, iG_bimap.left[vG_bimap.right.at(vG_buf.top())], false); vG_buf.pop(); } } - put(diG, iG_bimap.left.at(m), false); - put(dvG, vG_bimap.left.at(m), false); + put(diG, iG_bimap.left[m], false); + put(dvG, vG_bimap.left[m], false); } } } @@ -559,8 +581,8 @@ template < typename Coll, typename Seq > struct tree_collector typedef typename Coll::value_type coll_value_type; typedef typename Seq::value_type seq_value_type; - BOOST_STATIC_ASSERT((is_same< coll_value_type, Seq >::value)); - BOOST_STATIC_ASSERT((is_same< seq_value_type, bool >::value)); + static_assert(std::is_same< coll_value_type, Seq >::value, "Collector value type must match the sequence type"); + static_assert(std::is_same< seq_value_type, bool >::value, "Sequence value type must be bool"); tree_collector(Coll& seqs) : mSeqs(seqs) {} @@ -595,13 +617,13 @@ two_graphs_common_spanning_trees(const Graph& iG, Order iG_map, const Graph& vG, typedef typename Order::value_type order_value_type; typedef typename Order::size_type order_size_type; - BOOST_STATIC_ASSERT((is_same< order_value_type, edge_descriptor >::value)); + static_assert(std::is_same< order_value_type, edge_descriptor >::value, "Order value type must be the graph's edge descriptor type"); BOOST_CONCEPT_ASSERT((Convertible< order_size_type, edges_size_type >)); BOOST_CONCEPT_ASSERT((Convertible< seq_size_type, edges_size_type >)); - BOOST_STATIC_ASSERT((is_same< seq_value_type, bool >::value)); + static_assert(std::is_same< seq_value_type, bool >::value, "Sequence value type must be bool"); - BOOST_STATIC_ASSERT((is_same< directed_category, undirected_tag >::value)); + static_assert(std::is_same< directed_category, undirected_tag >::value, "The graph must be unidirected."); if (num_vertices(iG) != num_vertices(vG)) return; @@ -612,10 +634,8 @@ two_graphs_common_spanning_trees(const Graph& iG, Order iG_map, const Graph& vG, if (iG_map.size() != num_edges(iG) || vG_map.size() != num_edges(vG)) return; - typedef bimaps::bimap< bimaps::set_of< int >, - bimaps::set_of< order_value_type > > - bimap_type; - typedef typename bimap_type::value_type bimap_value; + using bimap_type = detail::index_bimap< order_value_type >; + using bimap_value = typename bimap_type::value_type; bimap_type iG_bimap, vG_bimap; for (order_size_type i = 0; i < iG_map.size(); ++i) @@ -698,13 +718,13 @@ two_graphs_common_spanning_trees(const Graph& iG, Order iG_map, const Graph& vG, { if (inL[i]) { - put(aiG_inL, iG_bimap.left.at(i), true); - put(avG_inL, vG_bimap.left.at(i), true); + put(aiG_inL, iG_bimap.left[i], true); + put(avG_inL, vG_bimap.left[i], true); } else { - put(aiG_inL, iG_bimap.left.at(i), false); - put(avG_inL, vG_bimap.left.at(i), false); + put(aiG_inL, iG_bimap.left[i], false); + put(avG_inL, vG_bimap.left[i], false); } } @@ -751,8 +771,8 @@ two_graphs_common_spanning_trees(const Graph& iG, Order iG_map, const Graph& vG, { if (!inL[j]) { - put(aiG_inL, iG_bimap.left.at(j), true); - put(avG_inL, vG_bimap.left.at(j), true); + put(aiG_inL, iG_bimap.left[j], true); + put(avG_inL, vG_bimap.left[j], true); undirected_dfs( make_filtered_graph(iG, @@ -787,12 +807,12 @@ two_graphs_common_spanning_trees(const Graph& iG, Order iG_map, const Graph& vG, iG_buf.pop(); while (!vG_buf.empty()) vG_buf.pop(); - put(diG, iG_bimap.left.at(j), true); - put(dvG, vG_bimap.left.at(j), true); + put(diG, iG_bimap.left[j], true); + put(dvG, vG_bimap.left[j], true); } - put(aiG_inL, iG_bimap.left.at(j), false); - put(avG_inL, vG_bimap.left.at(j), false); + put(aiG_inL, iG_bimap.left[j], false); + put(avG_inL, vG_bimap.left[j], false); } } diff --git a/include/boost/graph/undirected_graph.hpp b/include/boost/graph/undirected_graph.hpp index ec1bbbba6..14af857f7 100644 --- a/include/boost/graph/undirected_graph.hpp +++ b/include/boost/graph/undirected_graph.hpp @@ -12,7 +12,6 @@ #include #include #include -#include namespace boost { diff --git a/include/boost/graph/use_mpi.hpp b/include/boost/graph/use_mpi.hpp deleted file mode 100644 index b77f9c0b5..000000000 --- a/include/boost/graph/use_mpi.hpp +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (C) 2004-2009 The Trustees of Indiana University. - -// Use, modification and distribution is subject to the Boost Software -// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -// Authors: Nick Edmonds -// Andrew Lumsdaine - -#ifndef BOOST_GRAPH_USE_MPI_HPP -#define BOOST_GRAPH_USE_MPI_HPP - -#define BOOST_GRAPH_USE_MPI - -#endif // BOOST_GRAPH_USE_MPI_HPP diff --git a/include/boost/graph/vector_as_graph.hpp b/include/boost/graph/vector_as_graph.hpp index 1797dac4c..6f463e47c 100644 --- a/include/boost/graph/vector_as_graph.hpp +++ b/include/boost/graph/vector_as_graph.hpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/include/boost/graph/vf2_sub_graph_iso.hpp b/include/boost/graph/vf2_sub_graph_iso.hpp index 77f7496bd..4c0ff1637 100644 --- a/include/boost/graph/vf2_sub_graph_iso.hpp +++ b/include/boost/graph/vf2_sub_graph_iso.hpp @@ -32,7 +32,7 @@ #include // for always_equivalent #include #include -#include +#include #include #include #include @@ -450,21 +450,21 @@ namespace detail // test terminal set counts when testing for: // - graph sub-graph monomorphism, or inline bool comp_term_sets(graph1_size_type a, graph2_size_type b, - boost::mpl::int_< subgraph_mono >) const + std::integral_constant< int, subgraph_mono >) const { return a <= b; } // - graph sub-graph isomorphism, or inline bool comp_term_sets(graph1_size_type a, graph2_size_type b, - boost::mpl::int_< subgraph_iso >) const + std::integral_constant< int, subgraph_iso >) const { return a <= b; } // - graph isomorphism inline bool comp_term_sets(graph1_size_type a, graph2_size_type b, - boost::mpl::int_< isomorphism >) const + std::integral_constant< int, isomorphism >) const { return a == b; } @@ -652,22 +652,22 @@ namespace detail if (problem_selection != subgraph_mono) { // subgraph_iso and isomorphism return comp_term_sets(term_in1_count, term_in2_count, - boost::mpl::int_< problem_selection >()) + std::integral_constant< int, problem_selection >()) && comp_term_sets(term_out1_count, term_out2_count, - boost::mpl::int_< problem_selection >()) + std::integral_constant< int, problem_selection >()) && comp_term_sets(rest1_count, rest2_count, - boost::mpl::int_< problem_selection >()); + std::integral_constant< int, problem_selection >()); } else { // subgraph_mono return comp_term_sets(term_in1_count, term_in2_count, - boost::mpl::int_< problem_selection >()) + std::integral_constant< int, problem_selection >()) && comp_term_sets(term_out1_count, term_out2_count, - boost::mpl::int_< problem_selection >()) + std::integral_constant< int, problem_selection >()) && comp_term_sets( term_in1_count + term_out1_count + rest1_count, term_in2_count + term_out2_count + rest2_count, - boost::mpl::int_< problem_selection >()); + std::integral_constant< int, problem_selection >()); } } @@ -718,13 +718,13 @@ namespace detail return comp_term_sets(boost::get< 0 >(term1), boost::get< 0 >(term2), - boost::mpl::int_< problem_selection >()) + std::integral_constant< int, problem_selection >()) && comp_term_sets(boost::get< 1 >(term1), boost::get< 1 >(term2), - boost::mpl::int_< problem_selection >()) + std::integral_constant< int, problem_selection >()) && comp_term_sets(boost::get< 2 >(term1), boost::get< 2 >(term2), - boost::mpl::int_< problem_selection >()); + std::integral_constant< int, problem_selection >()); } // Calls the user_callback with a graph (sub)graph mapping diff --git a/include/boost/graph/visitors.hpp b/include/boost/graph/visitors.hpp index 534794b6a..2a24fe1da 100644 --- a/include/boost/graph/visitors.hpp +++ b/include/boost/graph/visitors.hpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -59,13 +59,6 @@ namespace detail on_edge_not_minimized_num }; - template < typename Event, typename Visitor > - struct functor_to_visitor : Visitor - { - typedef Event event_filter; - functor_to_visitor(const Visitor& visitor) : Visitor(visitor) {} - }; - } // namespace detail struct on_no_event @@ -220,13 +213,13 @@ struct null_visitor : public base_visitor< null_visitor > namespace detail { template < class Visitor, class T, class Graph > - inline void invoke_dispatch(Visitor& v, T x, Graph& g, mpl::true_) + inline void invoke_dispatch(Visitor& v, T x, Graph& g, std::true_type) { v(x, g); } template < class Visitor, class T, class Graph > - inline void invoke_dispatch(Visitor&, T, Graph&, mpl::false_) + inline void invoke_dispatch(Visitor&, T, Graph&, std::false_type) { } } // namespace detail @@ -236,7 +229,7 @@ inline void invoke_visitors( std::pair< Visitor, Rest >& vlist, T x, Graph& g, Tag tag) { typedef typename Visitor::event_filter Category; - typedef typename is_same< Category, Tag >::type IsSameTag; + typedef typename std::is_same< Category, Tag >::type IsSameTag; detail::invoke_dispatch(vlist.first, x, g, IsSameTag()); invoke_visitors(vlist.second, x, g, tag); } @@ -244,7 +237,7 @@ template < class Visitor, class T, class Graph, class Tag > inline void invoke_visitors(Visitor& v, T x, Graph& g, Tag) { typedef typename Visitor::event_filter Category; - typedef typename is_same< Category, Tag >::type IsSameTag; + typedef typename std::is_same< Category, Tag >::type IsSameTag; detail::invoke_dispatch(v, x, g, IsSameTag()); } @@ -395,9 +388,11 @@ template < typename PropertyMap, typename EventTag > struct property_put * Creates a property_put functor which just sets a given value to a vertex or * edge. * + * The third argument is an unnamed event filter tag, used only to select the + * event the returned functor responds to. + * * @param property_map Given writeable property map * @param value Fixed value of the map - * @param tag Event Filter * @return The functor. */ @@ -409,20 +404,6 @@ inline property_put< PropertyMap, EventTag > put_property( return property_put< PropertyMap, EventTag >(property_map, value); } -#define BOOST_GRAPH_EVENT_STUB(Event, Kind) \ - typedef ::boost::Event Event##_type; \ - template < typename Visitor > \ - Kind##_visitor< std::pair< \ - detail::functor_to_visitor< Event##_type, Visitor >, Visitors > > \ - do_##Event(Visitor visitor) \ - { \ - typedef std::pair< \ - detail::functor_to_visitor< Event##_type, Visitor >, Visitors > \ - visitor_list; \ - typedef Kind##_visitor< visitor_list > result_type; \ - return result_type(visitor_list(visitor, m_vis)); \ - } - } /* namespace boost */ #endif diff --git a/include/boost/pending/container_traits.hpp b/include/boost/pending/container_traits.hpp index 8bf113a3e..9fcfa945e 100644 --- a/include/boost/pending/container_traits.hpp +++ b/include/boost/pending/container_traits.hpp @@ -22,22 +22,8 @@ #include #include #include - -#ifndef BOOST_NO_CXX11_HDR_UNORDERED_SET #include -#endif - -#ifndef BOOST_NO_CXX11_HDR_UNORDERED_MAP #include -#endif - -#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES -#define BOOST_PENDING_FWD_TYPE(type) const type& -#define BOOST_PENDING_FWD_VALUE(type, var) (var) -#else -#define BOOST_PENDING_FWD_TYPE(type) type&& -#define BOOST_PENDING_FWD_VALUE(type, var) (std::forward< type >((var))) -#endif // The content of this file is in 'graph_detail' because otherwise // there will be name clashes with @@ -366,6 +352,7 @@ namespace graph_detail { return unstable_tag(); } + template < class Key, class Eq, class Hash, class Alloc > unordered_multiset_tag container_category( const boost::unordered_multiset< Key, Eq, Hash, Alloc >&) @@ -394,31 +381,27 @@ namespace graph_detail return unstable_tag(); } -#ifndef BOOST_NO_CXX11_HDR_UNORDERED_SET template < class Key, class Eq, class Hash, class Alloc > struct container_traits< std::unordered_set< Key, Eq, Hash, Alloc > > { typedef unordered_set_tag category; typedef unstable_tag iterator_stability; }; -#endif -#ifndef BOOST_NO_CXX11_HDR_UNORDERED_MAP + template < class Key, class T, class Eq, class Hash, class Alloc > struct container_traits< std::unordered_map< Key, T, Eq, Hash, Alloc > > { typedef unordered_map_tag category; typedef unstable_tag iterator_stability; }; -#endif -#ifndef BOOST_NO_CXX11_HDR_UNORDERED_SET + template < class Key, class Eq, class Hash, class Alloc > struct container_traits< std::unordered_multiset< Key, Eq, Hash, Alloc > > { typedef unordered_multiset_tag category; typedef unstable_tag iterator_stability; }; -#endif -#ifndef BOOST_NO_CXX11_HDR_UNORDERED_MAP + template < class Key, class T, class Eq, class Hash, class Alloc > struct container_traits< std::unordered_multimap< Key, T, Eq, Hash, Alloc > > @@ -426,77 +409,62 @@ namespace graph_detail typedef unordered_multimap_tag category; typedef unstable_tag iterator_stability; }; -#endif -#ifndef BOOST_NO_CXX11_HDR_UNORDERED_SET + template < class Key, class Eq, class Hash, class Alloc > unordered_set_tag container_category( const std::unordered_set< Key, Eq, Hash, Alloc >&) { return unordered_set_tag(); } -#endif -#ifndef BOOST_NO_CXX11_HDR_UNORDERED_MAP template < class Key, class T, class Eq, class Hash, class Alloc > unordered_map_tag container_category( const std::unordered_map< Key, T, Eq, Hash, Alloc >&) { return unordered_map_tag(); } -#endif -#ifndef BOOST_NO_CXX11_HDR_UNORDERED_SET template < class Key, class Eq, class Hash, class Alloc > unstable_tag iterator_stability( const std::unordered_set< Key, Eq, Hash, Alloc >&) { return unstable_tag(); } -#endif -#ifndef BOOST_NO_CXX11_HDR_UNORDERED_MAP template < class Key, class T, class Eq, class Hash, class Alloc > unstable_tag iterator_stability( const std::unordered_map< Key, T, Eq, Hash, Alloc >&) { return unstable_tag(); } -#endif -#ifndef BOOST_NO_CXX11_HDR_UNORDERED_SET + template < class Key, class Eq, class Hash, class Alloc > unordered_multiset_tag container_category( const std::unordered_multiset< Key, Eq, Hash, Alloc >&) { return unordered_multiset_tag(); } -#endif -#ifndef BOOST_NO_CXX11_HDR_UNORDERED_MAP template < class Key, class T, class Eq, class Hash, class Alloc > unordered_multimap_tag container_category( const std::unordered_multimap< Key, T, Eq, Hash, Alloc >&) { return unordered_multimap_tag(); } -#endif -#ifndef BOOST_NO_CXX11_HDR_UNORDERED_SET template < class Key, class Eq, class Hash, class Alloc > unstable_tag iterator_stability( const std::unordered_multiset< Key, Eq, Hash, Alloc >&) { return unstable_tag(); } -#endif -#ifndef BOOST_NO_CXX11_HDR_UNORDERED_MAP template < class Key, class T, class Eq, class Hash, class Alloc > unstable_tag iterator_stability( const std::unordered_multimap< Key, T, Eq, Hash, Alloc >&) { return unstable_tag(); } -#endif //=========================================================================== // Generalized Container Functions @@ -569,42 +537,42 @@ namespace graph_detail // Push template < class Container, class T > std::pair< typename Container::iterator, bool > push_dispatch( - Container& c, BOOST_PENDING_FWD_TYPE(T) v, back_insertion_sequence_tag) + Container& c, T&& v, back_insertion_sequence_tag) { - c.push_back(BOOST_PENDING_FWD_VALUE(T, v)); + c.push_back(std::forward< T >(v)); return std::make_pair(boost::prior(c.end()), true); } template < class Container, class T > std::pair< typename Container::iterator, bool > push_dispatch( - Container& c, BOOST_PENDING_FWD_TYPE(T) v, front_insertion_sequence_tag) + Container& c, T&& v, front_insertion_sequence_tag) { - c.push_front(BOOST_PENDING_FWD_VALUE(T, v)); + c.push_front(std::forward< T >(v)); return std::make_pair(c.begin(), true); } template < class AssociativeContainer, class T > std::pair< typename AssociativeContainer::iterator, bool > push_dispatch( - AssociativeContainer& c, BOOST_PENDING_FWD_TYPE(T) v, + AssociativeContainer& c, T&& v, unique_associative_container_tag) { - return c.insert(BOOST_PENDING_FWD_VALUE(T, v)); + return c.insert(std::forward< T >(v)); } template < class AssociativeContainer, class T > std::pair< typename AssociativeContainer::iterator, bool > push_dispatch( - AssociativeContainer& c, BOOST_PENDING_FWD_TYPE(T) v, + AssociativeContainer& c, T&& v, multiple_associative_container_tag) { - return std::make_pair(c.insert(BOOST_PENDING_FWD_VALUE(T, v)), true); + return std::make_pair(c.insert(std::forward< T >(v)), true); } template < class Container, class T > std::pair< typename Container::iterator, bool > push( - Container& c, BOOST_PENDING_FWD_TYPE(T) v) + Container& c, T&& v) { return push_dispatch( - c, BOOST_PENDING_FWD_VALUE(T, v), container_category(c)); + c, std::forward< T >(v), container_category(c)); } // Find @@ -688,7 +656,5 @@ namespace graph_detail } } // namespace boost::graph_detail -#undef BOOST_PENDING_FWD_TYPE -#undef BOOST_PENDING_FWD_VALUE #endif // BOOST_GRAPH_DETAIL_CONTAINER_TRAITS_H diff --git a/include/boost/pending/property.hpp b/include/boost/pending/property.hpp index 6b4ee07f6..85cc5440a 100644 --- a/include/boost/pending/property.hpp +++ b/include/boost/pending/property.hpp @@ -7,9 +7,8 @@ #define BOOST_PROPERTY_HPP #include -#include -#include #include +#include #include #include #include @@ -256,10 +255,10 @@ template < typename T, typename Tag > struct lookup_one_property< const T, Tag > // instead with a nested kind type and num. Also, we may want to // switch BGL back to using class types for properties at some point. -template < class P > struct has_property : boost::mpl::true_ +template < class P > struct has_property : std::true_type { }; -template <> struct has_property< no_property > : boost::mpl::false_ +template <> struct has_property< no_property > : std::false_type { }; @@ -294,7 +293,8 @@ namespace detail /** This trait returns true if T is no_property. */ template < typename T > - struct is_no_property : mpl::bool_< is_same< T, no_property >::value > + struct is_no_property + : std::integral_constant< bool, is_same< T, no_property >::value > { }; @@ -358,7 +358,7 @@ namespace detail typedef typename boost::function_traits< F >::arg1_type a1; typedef typename boost::remove_reference< a1 >::type non_ref; typedef typename non_ref::next_type nx; - typedef typename boost::mpl::if_< boost::is_const< non_ref >, + typedef typename std::conditional< boost::is_const< non_ref >::value, boost::add_const< nx >, nx >::type with_const; typedef typename boost::add_reference< with_const >::type type; }; diff --git a/include/boost/pending/property_serialize.hpp b/include/boost/pending/property_serialize.hpp index cbdc163a4..a6119198c 100644 --- a/include/boost/pending/property_serialize.hpp +++ b/include/boost/pending/property_serialize.hpp @@ -7,9 +7,7 @@ #define BOOST_PROPERTY_SERIALIZE_HPP #include -#include -#include -#include +#include namespace boost { @@ -22,78 +20,10 @@ template < class Archive, class Tag, class T, class Base > void serialize( Archive& ar, property< Tag, T, Base >& prop, const unsigned int /*version*/) { - ar& serialization::make_nvp("property_value", prop.m_value); - ar& serialization::make_nvp("property_base", prop.m_base); + ar& boost::make_nvp("property_value", prop.m_value); + ar& boost::make_nvp("property_base", prop.m_base); } -#ifdef BOOST_GRAPH_USE_MPI - -// Setting the serialization properties of boost::property<> and -// boost::no_property to is_bitwise_serializable, object_serializable, -// track_never only when BOOST_GRAPH_USE_MPI is defined is dubious. -// -// This changes the serialization format of these classes, and hence -// of boost::adjacency_list, depending on whether BOOST_GRAPH_USE_MPI -// is defined. -// -// These serialization properties should probably be set in either case. -// -// Unfortunately, doing that now will change the serialization format -// of boost::adjacency_list in the non-MPI case, and could potentially -// break software that reads files serialized with an older release. - -namespace mpi -{ - - // forward declaration, to avoid including mpi - template < typename T > struct is_mpi_datatype; - - template < typename Tag, typename T, typename Base > - struct is_mpi_datatype< property< Tag, T, Base > > - : mpl::and_< is_mpi_datatype< T >, is_mpi_datatype< Base > > - { - }; -} - -namespace serialization -{ - template < typename Tag, typename T, typename Base > - struct is_bitwise_serializable< property< Tag, T, Base > > - : mpl::and_< is_bitwise_serializable< T >, is_bitwise_serializable< Base > > - { - }; - - template < typename Tag, typename T, typename Base > - struct implementation_level< property< Tag, T, Base > > - : mpl::int_< object_serializable > - { - }; - - template < typename Tag, typename T, typename Base > - struct tracking_level< property< Tag, T, Base > > : mpl::int_< track_never > - { - }; - -} -#endif // BOOST_GRAPH_USE_MPI - } // end namespace boost -#ifdef BOOST_GRAPH_USE_MPI -namespace boost -{ -namespace mpi -{ - template <> struct is_mpi_datatype< boost::no_property > : mpl::true_ - { - }; - -} -} // end namespace boost::mpi - -BOOST_IS_BITWISE_SERIALIZABLE(boost::no_property) -BOOST_CLASS_IMPLEMENTATION(boost::no_property, object_serializable) -BOOST_CLASS_TRACKING(boost::no_property, track_never) -#endif // BOOST_GRAPH_USE_MPI - #endif // BOOST_PROPERTY_SERIALIZE_HPP diff --git a/index.html b/index.html index be9e08221..b5ab23e3b 100644 --- a/index.html +++ b/index.html @@ -1,21 +1,16 @@ - + +Copyright (c) 2004 Trustees of Indiana University. +Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +--> + + - + Automatic redirection failed, please go to -doc/index.html. -
    -

    © Copyright Beman Dawes, 2001

    -

    Distributed under the Boost Software License, Version 1.0. (See accompanying -file LICENSE_1_0.txt or copy -at www.boost.org/LICENSE_1_0.txt)

    +doc/html/index.html - \ No newline at end of file + diff --git a/src/graphml.cpp b/src/graphml.cpp index af930fad9..1cefe6ea1 100644 --- a/src/graphml.cpp +++ b/src/graphml.cpp @@ -11,13 +11,11 @@ // Tiago de Paula Peixoto #define BOOST_GRAPH_SOURCE -#include -#include #include #include #include -#include -#include +#include +#include #include #include #include @@ -27,72 +25,100 @@ using namespace boost; namespace { +namespace rapidxml = boost::graph::detail::rapidxml; +using xml_node = rapidxml::xml_node< char >; +using xml_attribute = rapidxml::xml_attribute< char >; +using xml_document = rapidxml::xml_document< char >; + +// Value of an attribute, or a fallback when it is absent. +std::string attr_value(const xml_node* node, const char* name, const std::string& fallback) +{ + if (const xml_attribute* a = node->first_attribute(name)) + return std::string(a->value(), a->value_size()); + return fallback; +} + +// Value of an attribute that must be present; throws parse_error otherwise. +std::string require_attr(const xml_node* node, const char* name) +{ + if (const xml_attribute* a = node->first_attribute(name)) + return std::string(a->value(), a->value_size()); + BOOST_THROW_EXCEPTION(parse_error(std::string("missing required attribute: ") + name)); +} + +// Text content of an element. +std::string node_text(const xml_node* node) +{ + return std::string(node->value(), node->value_size()); +} + class graphml_reader { public: graphml_reader(mutate_graph& g) : m_g(g) {} - static boost::property_tree::ptree::path_type path(const std::string& str) - { - return boost::property_tree::ptree::path_type(str, '/'); - } - - void get_graphs(const boost::property_tree::ptree& top, + void get_graphs(const xml_node* top, size_t desired_idx /* or -1 for all */, bool is_root, - std::vector< const boost::property_tree::ptree* >& result) + std::vector< const xml_node* >& result) { - using boost::property_tree::ptree; size_t current_idx = 0; bool is_first = is_root; - BOOST_FOREACH (const ptree::value_type& n, top) + for (const xml_node* n = top->first_node("graph"); n; n = n->next_sibling("graph")) { - if (n.first == "graph") + if (current_idx == desired_idx || desired_idx == (size_t)(-1)) { - if (current_idx == desired_idx || desired_idx == (size_t)(-1)) + result.push_back(n); + if (is_first) { - result.push_back(&n.second); - if (is_first) + is_first = false; + for (const xml_node* data = n->first_node("data"); data; data = data->next_sibling("data")) { - is_first = false; - BOOST_FOREACH (const ptree::value_type& attr, n.second) - { - if (attr.first != "data") - continue; - std::string key = attr.second.get< std::string >( - path("/key")); - std::string value = attr.second.get_value(""); - handle_graph_property(key, value); - } + std::string key = require_attr(data, "key"); + std::string value = node_text(data); + handle_graph_property(key, value); } - - get_graphs(n.second, (size_t)(-1), false, result); - if (desired_idx != (size_t)(-1)) - break; } - ++current_idx; + + get_graphs(n, (size_t)(-1), false, result); + if (desired_idx != (size_t)(-1)) + break; } + ++current_idx; } } void run(std::istream& in, size_t desired_idx) { - using boost::property_tree::ptree; - ptree pt; - read_xml(in, pt, - boost::property_tree::xml_parser::no_comments - | boost::property_tree::xml_parser::trim_whitespace); - ptree gml = pt.get_child(path("graphml")); + // rapidxml parses in place, so load the whole stream into a buffer + // that outlives the document, and zero-terminate it. + std::vector< char > buffer( + (std::istreambuf_iterator< char >(in)), + std::istreambuf_iterator< char >()); + buffer.push_back('\0'); + + xml_document doc; + try + { + // no_comments | trim_whitespace, as the old property_tree call used. + constexpr int flags = rapidxml::parse_normalize_whitespace | rapidxml::parse_trim_whitespace; + doc.parse< flags >(&buffer[0]); + } + catch (const rapidxml::parse_error& e) + { + BOOST_THROW_EXCEPTION(parse_error(e.what())); + } + + const xml_node* gml = doc.first_node("graphml"); + if (!gml) + BOOST_THROW_EXCEPTION(parse_error("no graphml element found")); + // Search for attributes - BOOST_FOREACH (const ptree::value_type& child, gml) + for (const xml_node* child = gml->first_node("key"); child; child = child->next_sibling("key")) { - if (child.first != "key") - continue; - std::string id = child.second.get(path("/id"), ""); - std::string for_ = child.second.get(path("/for"), ""); - std::string name - = child.second.get(path("/attr.name"), ""); - std::string type - = child.second.get(path("/attr.type"), ""); + std::string id = attr_value(child, "id", ""); + std::string for_ = attr_value(child, "for", ""); + std::string name = attr_value(child, "attr.name", ""); + std::string type = attr_value(child, "attr.type", ""); key_kind kind = all_key; if (for_ == "graph") kind = graph_key; @@ -118,52 +144,38 @@ class graphml_reader m_keys[id] = kind; m_key_name[id] = name; m_key_type[id] = type; - boost::optional< std::string > default_ - = child.second.get_optional< std::string >(path("default")); - if (default_) - m_key_default[id] = default_.get(); + if (const xml_node* default_ = child->first_node("default")) + m_key_default[id] = node_text(default_); } // Search for graphs - std::vector< const ptree* > graphs; + std::vector< const xml_node* > graphs; handle_graph(); get_graphs(gml, desired_idx, true, graphs); - BOOST_FOREACH (const ptree* gr, graphs) + for (const xml_node* gr : graphs) { // Search for nodes - BOOST_FOREACH (const ptree::value_type& node, *gr) + for (const xml_node* node = gr->first_node("node"); node; node = node->next_sibling("node")) { - if (node.first != "node") - continue; - std::string id - = node.second.get< std::string >(path("/id")); + std::string id = require_attr(node, "id"); handle_vertex(id); - BOOST_FOREACH (const ptree::value_type& attr, node.second) + for (const xml_node* data = node->first_node("data"); data; data = data->next_sibling("data")) { - if (attr.first != "data") - continue; - std::string key - = attr.second.get< std::string >(path("/key")); - std::string value = attr.second.get_value(""); + std::string key = require_attr(data, "key"); + std::string value = node_text(data); handle_node_property(key, id, value); } } } - BOOST_FOREACH (const ptree* gr, graphs) + for (const xml_node* gr : graphs) { bool default_directed - = gr->get< std::string >(path("/edgedefault")) - == "directed"; + = require_attr(gr, "edgedefault") == "directed"; // Search for edges - BOOST_FOREACH (const ptree::value_type& edge, *gr) + for (const xml_node* edge = gr->first_node("edge"); edge; edge = edge->next_sibling("edge")) { - if (edge.first != "edge") - continue; - std::string source - = edge.second.get< std::string >(path("/source")); - std::string target - = edge.second.get< std::string >(path("/target")); - std::string local_directed - = edge.second.get(path("/directed"), ""); + std::string source = require_attr(edge, "source"); + std::string target = require_attr(edge, "target"); + std::string local_directed = attr_value(edge, "directed", ""); bool is_directed = (local_directed.empty() ? default_directed : local_directed == "true"); @@ -180,13 +192,10 @@ class graphml_reader } size_t old_edges_size = m_edge.size(); handle_edge(source, target); - BOOST_FOREACH (const ptree::value_type& attr, edge.second) + for (const xml_node* data = edge->first_node("data"); data; data = data->next_sibling("data")) { - if (attr.first != "data") - continue; - std::string key - = attr.second.get< std::string >(path("/key")); - std::string value = attr.second.get_value(""); + std::string key = require_attr(data, "key"); + std::string value = node_text(data); handle_edge_property(key, old_edges_size, value); } } diff --git a/src/read_graphviz_new.cpp b/src/read_graphviz_new.cpp index 99fc81bc4..00ca3b1a2 100644 --- a/src/read_graphviz_new.cpp +++ b/src/read_graphviz_new.cpp @@ -32,8 +32,8 @@ #include #include #include -#include #include +#include #include #include // for std::exception #include @@ -260,7 +260,13 @@ namespace read_graphviz_detail if (found) { std::string str = results[1].str(); - std::string str_lower = boost::algorithm::to_lower_copy(str); + std::string str_lower = str; + std::transform( + str_lower.begin(), + str_lower.end(), + str_lower.begin(), + [](unsigned char c) { return static_cast< char >(std::tolower(c)); } + ); begin = results.suffix().first; if (str_lower == "strict") { diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index d05a0a7ef..b068df84b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -32,13 +32,10 @@ alias graph_test_regular : [ run test_graphs.cpp ] [ run index_graph.cpp ] # TODO: Make this part of the test_graphs framework [ run labeled_graph.cpp ] - [ run finish_edge_bug.cpp ] - [ run transitive_closure_test.cpp /boost/timer//boost_timer ] - [ run transitive_closure_test2.cpp ] + [ run transitive_closure_test.cpp ] [ compile adj_list_cc.cpp ] - #[ run adj_list_invalidation.cpp ] [ run adj_list_edge_list_set.cpp ] [ run adj_list_loops.cpp ] [ compile adj_matrix_cc.cpp ] @@ -47,11 +44,13 @@ alias graph_test_regular : [ run bellman-test.cpp ] [ run betweenness_centrality_test.cpp : 100 ] [ run bidir_remove_edge.cpp ] + [ compile-fail bidir_vec_remove_edge.cpp ] [ run bipartite_test.cpp ] [ run csr_graph_test.cpp : : : : : release ] [ run dag_longest_paths.cpp ] [ run dfs.cpp ] [ run undirected_dfs.cpp ] + [ run undirected_dfs_visitor.cpp ] [ compile dfs_cc.cpp ] [ compile dijkstra_cc.cpp ] @@ -79,8 +78,8 @@ alias graph_test_regular : [ run graph.cpp : : : TEST=8 : graph_8 ] [ run graph.cpp : : : TEST=9 : graph_9 ] [ compile graph_concepts.cpp ] - [ run graphviz_test.cpp - /boost/graph//boost_graph : --log_level=all ] + [ run graphviz_test.cpp /boost/graph//boost_graph : --log_level=all ] + [ run graphviz_round_trip_test.cpp /boost/graph//boost_graph ] [ run metis_test.cpp : $(METIS_INPUT_FILE) ] [ run gursoy_atun_layout_test.cpp : : : [ requires cxx11_noexcept cxx11_rvalue_references sfinae_expr cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_hdr_tuple cxx11_hdr_initializer_list cxx11_hdr_chrono cxx11_thread_local cxx11_constexpr cxx11_nullptr cxx11_numeric_limits cxx11_decltype cxx11_hdr_array cxx11_hdr_atomic cxx11_hdr_type_traits cxx11_allocator cxx11_explicit_conversion_operators ] ] [ run layout_test.cpp : : : always_show_run_output intel:off [ requires cxx11_noexcept cxx11_rvalue_references sfinae_expr cxx11_auto_declarations cxx11_lambdas cxx11_unified_initialization_syntax cxx11_hdr_tuple cxx11_hdr_initializer_list cxx11_hdr_chrono cxx11_thread_local cxx11_constexpr cxx11_nullptr cxx11_numeric_limits cxx11_decltype cxx11_hdr_array cxx11_hdr_atomic cxx11_hdr_type_traits cxx11_allocator cxx11_explicit_conversion_operators ] ] @@ -97,8 +96,9 @@ alias graph_test_regular : [ run subgraph_bundled.cpp ] [ run subgraph_add.cpp : $(TEST_DIR) ] [ run subgraph_props.cpp ] + [ run subgraph_global_local.cpp ] - [ run isomorphism.cpp ] + [ run isomorphism.cpp : $(TEST_DIR) ] [ run adjacency_matrix_test.cpp ] [ compile vector_graph_cc.cpp ] [ compile copy.cpp ] @@ -131,10 +131,13 @@ alias graph_test_regular : [ run make_maximal_planar_test.cpp ] [ run named_vertices_test.cpp ] [ run r_c_shortest_paths_test.cpp ] + [ run r_c_shortest_paths_test_old.cpp ] + [ run rcsp_custom_vertex_id_old.cpp ] [ run rcsp_custom_vertex_id.cpp ] [ run rcsp_single_solution.cpp ] + [ run rcsp_single_solution_old.cpp ] [ run is_straight_line_draw_test.cpp ] - [ run metric_tsp_approx.cpp /boost/timer//boost_timer : metric_tsp_approx.graph : : ] + [ run metric_tsp_approx.cpp /boost/timer//boost_timer ] [ compile dimacs.cpp ] [ run bron_kerbosch_all_cliques.cpp ] [ run tiernan_all_cycles.cpp ] @@ -143,6 +146,7 @@ alias graph_test_regular : [ run mean_geodesic.cpp ] [ run eccentricity.cpp ] [ run clustering_coefficient.cpp ] + [ run bc_clustering_test.cpp ] [ run core_numbers_test.cpp ] [ run louvain_quality_function_test.cpp ] [ run louvain_clustering_test.cpp ] @@ -158,10 +162,12 @@ alias graph_test_regular : [ run incremental_components_test.cpp ] [ run two_graphs_common_spanning_trees_test.cpp ] [ run random_spanning_tree_test.cpp /boost/graph//boost_graph ] - [ run random_matching_test.cpp : 1000 1020 ] + [ run random_matching_test.cpp ] [ run graphml_test.cpp /boost/graph//boost_graph : : "graphml_test.xml" ] - [ run mas_test.cpp : $(TEST_DIR) ] + [ run mas_test.cpp ] + [ run mas_test_old.cpp : $(TEST_DIR) ] [ run stoer_wagner_test.cpp : $(TEST_DIR) ] + [ run stoer_wagner_test_old.cpp : $(TEST_DIR) ] [ compile filtered_graph_properties_dijkstra.cpp ] [ run vf2_sub_graph_iso_test.cpp ] [ run vf2_sub_graph_iso_test_2.cpp ] diff --git a/test/adj_list_invalidation.cpp b/test/adj_list_invalidation.cpp deleted file mode 100644 index 3ee7bcc26..000000000 --- a/test/adj_list_invalidation.cpp +++ /dev/null @@ -1,150 +0,0 @@ -// (C) Copyright Andrew Sutton 2009 -// -// Use, modification and distribution are subject to the -// Boost Software License, Version 1.0 (See accompanying file -// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) - -/*********************************************************** - -IMPORTANT: this file should not be tested - it creates invalid graphs/sequences -which *do* crash at runtime - this seems to be the intent, but it's not -clear why or whether the file should be retained. - -***********************************************************/ - -#include -#include -#include - -#include "typestr.hpp" - -using namespace std; -using namespace boost; - -// The purpose of this test is simply to provide a testing ground for the -// invalidation of iterators and descriptors. - -template < typename Graph > void make_graph(Graph& g) -{ - // Build a simple (barbell) graph. - typedef typename graph_traits< Graph >::vertex_descriptor Vertex; - Vertex u = add_vertex(10, g); - Vertex v = add_vertex(20, g); - add_edge(u, v, 100, g); -} - -// Invalid iterators and descriptors will cause a segfault. -template < typename Graph, typename Iterator, typename Descriptor > -void test(Graph& g, Iterator i, Descriptor d, string const& str) -{ - int x; - cout << "... " << str << " iter" << endl; - x = g[*i]; - // cout << "... " << x << endl; - cout << "... " << str << " desc" << endl; - x = g[d]; - // cout << "... " << x << endl; -} - -template < typename Graph > void invalidate_edges() -{ - typedef typename graph_traits< Graph >::edge_descriptor Edge; - typedef typename graph_traits< Graph >::edge_iterator EdgeIterator; - - Graph g; - make_graph(g); - - // The actual test. These are valid here. - EdgeIterator i = edges(g).first; - Edge e = *i; - - // Add a vertex, see what breaks. - add_vertex(g); - test(g, i, e, "edges"); -}; - -template < typename Graph > void invalidate_vertices() -{ - typedef typename graph_traits< Graph >::vertex_descriptor Vertex; - typedef typename graph_traits< Graph >::vertex_iterator VertexIterator; - - Graph g; - make_graph(g); - - // The actual test. These are valid here. - VertexIterator i = vertices(g).first; - Vertex v = *i; - - // Add a vertex, see what breaks. - add_vertex(g); - test(g, i, v, "vertices"); -} - -template < typename Graph > void invalidate_out_edges() -{ - typedef typename graph_traits< Graph >::edge_descriptor Edge; - typedef typename graph_traits< Graph >::out_edge_iterator OutIterator; - - Graph g; - make_graph(g); - - // The actual test. These are valid here. - OutIterator i = out_edges(*vertices(g).first, g).first; - Edge e = *i; - - // Add a vertex, see what breaks. - add_vertex(g); - test(g, i, e, "out edges"); -} - -template < typename Graph > void invalidate_adj_verts() -{ - typedef typename graph_traits< Graph >::vertex_descriptor Vertex; - typedef typename graph_traits< Graph >::adjacency_iterator AdjIterator; - - Graph g; - make_graph(g); - - // The actual test. These are valid here. - AdjIterator i = adjacent_vertices(*vertices(g).first, g).first; - Vertex v = *i; - - // Add a vertex, see what breaks. - add_vertex(g); - test(g, i, v, "adjacent vertices"); -} - -int main() -{ - typedef adjacency_list< vecS, vecS, undirectedS, int, int > VVU; - cout << "vecS vecS undirectedS" << endl; - invalidate_vertices< VVU >(); - invalidate_edges< VVU >(); - invalidate_out_edges< VVU >(); - invalidate_adj_verts< VVU >(); - - typedef adjacency_list< vecS, vecS, bidirectionalS, int, int > VVB; - cout << "vecS vecS bidirectionals" << endl; - invalidate_vertices< VVB >(); - invalidate_edges< VVB >(); - invalidate_out_edges< VVB >(); - invalidate_adj_verts< VVB >(); - - // If you comment out the tests before this, then adj_verts test will - // run without segfaulting - at least under gcc-4.3. Not really sure why, - // but I'm guessing it's still not generating valid results, and shouldn't - // be taken as an indicator of stability. - typedef adjacency_list< vecS, vecS, directedS, int, int > VVD; - cout << "vecS vecS directedS" << endl; - invalidate_vertices< VVD >(); - // invalidate_edges(); - // invalidate_out_edges(); - // invalidate_adj_verts(); - - typedef adjacency_list< listS, vecS, directedS, int, int > LVD; - cout << "listS vecS directedS" << endl; - invalidate_vertices< LVD >(); - // invalidate_edges(); - // invalidate_out_edges(); - // invalidate_adj_verts(); -} diff --git a/test/all_planar_input_files_test.cpp b/test/all_planar_input_files_test.cpp index 769b3f05d..dc22ddb03 100644 --- a/test/all_planar_input_files_test.cpp +++ b/test/all_planar_input_files_test.cpp @@ -30,7 +30,6 @@ This test needs to be linked against Boost.Filesystem. #include #include #include -#include #include #include @@ -73,7 +72,14 @@ void read_dimacs(Graph& g, const std::string& filename) continue; std::vector< std::string > v; - split(v, buffer, is_any_of(" \t\n")); + for (std::string::size_type start = 0;;) + { + std::string::size_type pos = s.find_first_of(" \t\n", start); + v.push_back(s.substr(start, pos - start)); + if (pos == std::string::npos) + break; + start = pos + 1; + } if (v[0] == "p") { diff --git a/test/astar_search_test.cpp b/test/astar_search_test.cpp index 756f0cdca..2d81e8278 100644 --- a/test/astar_search_test.cpp +++ b/test/astar_search_test.cpp @@ -3,6 +3,7 @@ // //======================================================================= // Copyright (c) 2004 Kristopher Beevers +// Copyright (c) 2026 Arnaud Becheler // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -12,85 +13,36 @@ #include #include -#include -#include +#include #include #include #include -#include +#include #include // for sqrt -#include - -using namespace boost; -using namespace std; // auxiliary types struct location { float y, x; // lat, long }; + struct my_float { float v; explicit my_float(float v = float()) : v(v) {} }; -typedef my_float cost; -ostream& operator<<(ostream& o, my_float f) { return o << f.v; } + +using cost = my_float; my_float operator+(my_float a, my_float b) { return my_float(a.v + b.v); } bool operator==(my_float a, my_float b) { return a.v == b.v; } bool operator<(my_float a, my_float b) { return a.v < b.v; } -template < class Name, class LocMap > class city_writer -{ -public: - city_writer(Name n, LocMap l, float _minx, float _maxx, float _miny, - float _maxy, unsigned int _ptx, unsigned int _pty) - : name(n) - , loc(l) - , minx(_minx) - , maxx(_maxx) - , miny(_miny) - , maxy(_maxy) - , ptx(_ptx) - , pty(_pty) - { - } - template < class Vertex > - void operator()(ostream& out, const Vertex& v) const - { - float px = 1 - (loc[v].x - minx) / (maxx - minx); - float py = (loc[v].y - miny) / (maxy - miny); - out << "[label=\"" << name[v] << "\", pos=\"" - << static_cast< unsigned int >(ptx * px) << "," - << static_cast< unsigned int >(pty * py) << "\", fontsize=\"11\"]"; - } - -private: - Name name; - LocMap loc; - float minx, maxx, miny, maxy; - unsigned int ptx, pty; -}; - -template < class WeightMap > class time_writer -{ -public: - time_writer(WeightMap w) : wm(w) {} - template < class Edge > void operator()(ostream& out, const Edge& e) const - { - out << "[label=\"" << wm[e] << "\", fontsize=\"11\"]"; - } - -private: - WeightMap wm; -}; - // euclidean distance heuristic template < class Graph, class CostType, class LocMap > -class distance_heuristic : public astar_heuristic< Graph, CostType > +class distance_heuristic : public boost::astar_heuristic< Graph, CostType > { public: - typedef typename graph_traits< Graph >::vertex_descriptor Vertex; + using Vertex = typename boost::graph_traits< Graph >::vertex_descriptor; distance_heuristic(LocMap l, Vertex goal) : m_location(l), m_goal(goal) {} CostType operator()(Vertex u) { @@ -124,17 +76,16 @@ class astar_goal_visitor : public boost::default_astar_visitor Vertex m_goal; }; -int main(int, char**) +int main() { - // specify some types - typedef adjacency_list< listS, vecS, undirectedS, no_property, - property< edge_weight_t, cost > > - mygraph_t; - typedef property_map< mygraph_t, edge_weight_t >::type WeightMap; - typedef mygraph_t::vertex_descriptor vertex; - typedef mygraph_t::edge_descriptor edge_descriptor; - typedef std::pair< int, int > edge; + using mygraph_t = boost::adjacency_list< boost::listS, boost::vecS, + boost::undirectedS, boost::no_property, + boost::property< boost::edge_weight_t, cost > >; + using WeightMap = boost::property_map< mygraph_t, boost::edge_weight_t >::type; + using vertex = mygraph_t::vertex_descriptor; + using edge_descriptor = mygraph_t::edge_descriptor; + using edge = std::pair< int, int >; // specify data enum nodes @@ -154,9 +105,6 @@ int main(int, char**) NewYork, N }; - const char* name[] = { "Troy", "Lake Placid", "Plattsburgh", "Massena", - "Watertown", "Utica", "Syracuse", "Rochester", "Buffalo", "Ithaca", - "Binghamton", "Woodstock", "New York" }; location locations[] = { // lat/long { 42.73, 73.68 }, { 44.28, 73.99 }, { 44.70, 73.46 }, { 44.93, 74.89 }, { 43.97, 75.91 }, { 43.10, 75.23 }, { 43.04, 76.14 }, { 43.17, 77.61 }, @@ -185,60 +133,75 @@ int main(int, char**) // create graph mygraph_t g(N); - WeightMap weightmap = get(edge_weight, g); + WeightMap weightmap = boost::get(boost::edge_weight, g); for (std::size_t j = 0; j < num_edges; ++j) { edge_descriptor e; bool inserted; boost::tie(e, inserted) - = add_edge(edge_array[j].first, edge_array[j].second, g); + = boost::add_edge(edge_array[j].first, edge_array[j].second, g); weightmap[e] = weights[j]; } - // pick random start/goal - boost::minstd_rand gen(time(0)); - vertex start = gen() % num_vertices(g); - vertex goal = gen() % num_vertices(g); + // Troy to Buffalo has a unique shortest path of 309 minutes + vertex start = Troy; + vertex goal = Buffalo; + constexpr float expected_time = 309.0f; - cout << "Start vertex: " << name[start] << endl; - cout << "Goal vertex: " << name[goal] << endl; - - vector< mygraph_t::vertex_descriptor > p(num_vertices(g)); - vector< cost > d(num_vertices(g)); + std::vector< mygraph_t::vertex_descriptor > p(boost::num_vertices(g)); + std::vector< cost > d(boost::num_vertices(g)); boost::property_map< mygraph_t, boost::vertex_index_t >::const_type idx - = get(boost::vertex_index, g); + = boost::get(boost::vertex_index, g); + bool found = false; try { // call astar named parameter interface - astar_search(g, start, + boost::astar_search(g, start, distance_heuristic< mygraph_t, cost, location* >(locations, goal), - predecessor_map(make_iterator_property_map(p.begin(), idx)) - .distance_map(make_iterator_property_map(d.begin(), idx)) + boost::predecessor_map( + boost::make_iterator_property_map(p.begin(), idx)) + .distance_map(boost::make_iterator_property_map(d.begin(), idx)) .visitor(astar_goal_visitor< vertex >(goal)) .distance_inf(my_float((std::numeric_limits< float >::max)()))); } - catch (found_goal fg) - { // found a path to the goal - list< vertex > shortest_path; - for (vertex v = goal;; v = p[v]) + catch (found_goal const&) + { + found = true; + } + + // the goal is reachable and the reported cost is optimal + BOOST_TEST(found); + BOOST_TEST_EQ(d[goal].v, expected_time); + + // the predecessor path is connected and its weights sum to the distance + std::list< vertex > shortest_path; + for (vertex v = goal;; v = p[v]) + { + shortest_path.push_front(v); + if (p[v] == v) + break; + } + BOOST_TEST(shortest_path.front() == start); + BOOST_TEST(shortest_path.back() == goal); + + cost path_weight; + bool first = true; + vertex prev = start; + for (vertex v : shortest_path) + { + if (!first) { - shortest_path.push_front(v); - if (p[v] == v) - break; + std::pair< edge_descriptor, bool > e = boost::edge(prev, v, g); + BOOST_TEST(e.second); + if (e.second) + path_weight = path_weight + weightmap[e.first]; } - cout << "Shortest path from " << name[start] << " to " << name[goal] - << ": "; - list< vertex >::iterator spi = shortest_path.begin(); - cout << name[start]; - for (++spi; spi != shortest_path.end(); ++spi) - cout << " -> " << name[*spi]; - cout << endl << "Total travel time: " << d[goal] << endl; - return 0; + prev = v; + first = false; } + BOOST_TEST_EQ(path_weight.v, d[goal].v); - cout << "Didn't find a path from " << name[start] << "to" << name[goal] - << "!" << endl; - return 0; + return boost::report_errors(); } diff --git a/test/bc_clustering_test.cpp b/test/bc_clustering_test.cpp new file mode 100644 index 000000000..15729ca55 --- /dev/null +++ b/test/bc_clustering_test.cpp @@ -0,0 +1,55 @@ +// Copyright (C) 2026 Arnaud Becheler +// +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + +struct EdgeCentrality +{ + double centrality; +}; + +using Graph = boost::adjacency_list< boost::vecS, boost::vecS, + boost::undirectedS, boost::no_property, EdgeCentrality >; + +struct stop_after_first_removal +{ + int calls = 0; + template < typename Edge, typename G > + bool operator()(double, Edge, const G&) + { + return calls++ > 0; + } +}; + +int main() +{ + Graph g(6); + boost::add_edge(0, 1, g); + boost::add_edge(1, 2, g); + boost::add_edge(0, 2, g); + boost::add_edge(3, 4, g); + boost::add_edge(4, 5, g); + boost::add_edge(3, 5, g); + boost::add_edge(2, 3, g); + + auto done = stop_after_first_removal(); + auto centrality_map = boost::get(&EdgeCentrality::centrality, g); + boost::betweenness_centrality_clustering(g, done, centrality_map); + + auto bridge = boost::edge(2, 3, g); + BOOST_TEST(!bridge.second); + BOOST_TEST_EQ(boost::num_edges(g), 6u); + + std::vector< int > component(boost::num_vertices(g)); + auto component_map = &component[0]; + BOOST_TEST_EQ(boost::connected_components(g, component_map), 2); + + return boost::report_errors(); +} diff --git a/test/betweenness_centrality_test.cpp b/test/betweenness_centrality_test.cpp index 8a2a02453..3cc1fd8da 100644 --- a/test/betweenness_centrality_test.cpp +++ b/test/betweenness_centrality_test.cpp @@ -237,7 +237,7 @@ void randomly_add_edges(MutableGraph& g, double edge_probability) typedef typename graph_traits< MutableGraph >::directed_category directed_category; - minstd_rand gen; + minstd_rand gen(42); uniform_01< minstd_rand, double > rand_gen(gen); typedef typename graph_traits< MutableGraph >::vertex_descriptor vertex; diff --git a/test/bfs.cpp b/test/bfs.cpp index a3dfad126..be5f45af2 100644 --- a/test/bfs.cpp +++ b/test/bfs.cpp @@ -134,7 +134,7 @@ template < class Graph > struct bfs_test typename Traits::edges_size_type j; typename Traits::vertex_iterator ui, ui_end; - boost::mt19937 gen; + boost::mt19937 gen(42); for (i = 0; i < max_V; ++i) for (j = 0; j < i * i; ++j) diff --git a/test/biconnected_components_test.cpp b/test/biconnected_components_test.cpp index 0990b4ed6..aaead5237 100644 --- a/test/biconnected_components_test.cpp +++ b/test/biconnected_components_test.cpp @@ -123,14 +123,12 @@ int main(int argc, char* argv[]) { std::size_t n = 100; std::size_t m = 500; - std::size_t seed = 1; + std::size_t seed = 42; if (argc > 1) n = lexical_cast< std::size_t >(argv[1]); if (argc > 2) m = lexical_cast< std::size_t >(argv[2]); - if (argc > 3) - seed = lexical_cast< std::size_t >(argv[3]); { Graph g(n); diff --git a/test/bidir_vec_remove_edge.cpp b/test/bidir_vec_remove_edge.cpp index ae662b124..10773e469 100644 --- a/test/bidir_vec_remove_edge.cpp +++ b/test/bidir_vec_remove_edge.cpp @@ -3,56 +3,21 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -// NOTE: This test illustrates a longstanding bug in the -// adjacency_list class template. We do not test it because it will -// cause problems until we have time to fix the bug. Annoying? Yes. +// Compile-fail test: remove_edge() must be rejected at compile time when the +// EdgeList of an adjacency_list is vecS. Removing an edge from a vector-backed +// edge list would renumber every stored edge index past the removal point, so +// adjacency_list guards each remove_edge overload with a static assertion +// instead of supporting the operation. This test pins that guard (see +// test/Jamfile.v2, [ compile-fail bidir_vec_remove_edge.cpp ]). -#include #include -#include -struct edge_prop +int main() { - int weight; -}; - -int main(int, char*[]) -{ - { - typedef boost::adjacency_list< boost::vecS, boost::vecS, - boost::bidirectionalS, boost::no_property, edge_prop, - boost::no_property, boost::vecS > - graph; - typedef boost::graph_traits< graph >::edge_descriptor edge; - - graph g(2); - - edge_prop p1 = { 42 }; - edge_prop p2 = { 17 }; - add_edge(0, 1, p1, g); - add_edge(1, 0, p2, g); - - edge e1 = boost::edge(0, 1, g).first; - edge e2 = boost::edge(1, 0, g).first; - BOOST_TEST(num_edges(g) == 2); - BOOST_TEST(g[e1].weight == 42); - BOOST_TEST(g[e2].weight == 17); - remove_edge(e1, g); - BOOST_TEST(num_edges(g) == 1); - - // e2 has been invalidated, so grab it again - bool b2; - boost::tie(e2, b2) = boost::edge(1, 0, g); - BOOST_TEST(b2); - BOOST_TEST(g[e2].weight == 17); - - /* Now remove the other edge. Here, the fact that - * stored_ra_edge_iterator keeps an index but does not update it - * when edges are removed. So, this will be incorrect but the - * error may not always show up (use an STL debug mode to see the - * error for sure.) - */ - remove_edge(e2, g); - } - return boost::report_errors(); + using graph = boost::adjacency_list< boost::vecS, boost::vecS, + boost::bidirectionalS, boost::no_property, boost::no_property, + boost::no_property, boost::vecS >; + graph g(2); + add_edge(0, 1, g); + remove_edge(0, 1, g); // must not compile } diff --git a/test/bipartite_test.cpp b/test/bipartite_test.cpp index f6082e299..f9444072a 100644 --- a/test/bipartite_test.cpp +++ b/test/bipartite_test.cpp @@ -113,7 +113,7 @@ void check_bipartite(const Graph& g, IndexMap index_map, bool is_bipartite) } } -int main(int argc, char** argv) +int main() { typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS > diff --git a/test/boykov_kolmogorov_max_flow_test.cpp b/test/boykov_kolmogorov_max_flow_test.cpp index 9e0ce7b34..d9e7437b6 100644 --- a/test/boykov_kolmogorov_max_flow_test.cpp +++ b/test/boykov_kolmogorov_max_flow_test.cpp @@ -589,14 +589,12 @@ int main(int argc, char* argv[]) { int n_verts = 10; int n_edges = 500; - std::size_t seed = 1; + std::size_t seed = 42; if (argc > 1) n_verts = lexical_cast< int >(argv[1]); if (argc > 2) n_edges = lexical_cast< int >(argv[2]); - if (argc > 3) - seed = lexical_cast< std::size_t >(argv[3]); // we need at least 2 vertices to create src and sink in random graphs // this case is also caught in boykov_kolmogorov_max_flow diff --git a/test/bron_kerbosch_all_cliques.cpp b/test/bron_kerbosch_all_cliques.cpp index 949069a96..0a0967dd1 100644 --- a/test/bron_kerbosch_all_cliques.cpp +++ b/test/bron_kerbosch_all_cliques.cpp @@ -56,7 +56,7 @@ template < typename Graph > void test() static const size_t N = 20; static const double P = 0.1; - boost::minstd_rand rng; + boost::minstd_rand rng(42); Graph g(er(rng, N, P), er(), N); renumber_indices(g); print_edges(g, get(vertex_index, g)); diff --git a/test/csr_graph_test.cpp b/test/csr_graph_test.cpp index 2bf426331..7a553bab2 100644 --- a/test/csr_graph_test.cpp +++ b/test/csr_graph_test.cpp @@ -19,16 +19,15 @@ #include #include #include +#include #include // for ignore_unused_variable_warning #include #include #include -#include #include #include #include #include -#include #include // Algorithms to test against @@ -228,7 +227,7 @@ template < typename OrigGraph > void graph_test(const OrigGraph& g) std::vector< std::size_t > targets(num_edges(g2)); std::size_t idx = 0; // Edges actually sorted - BGL_FORALL_EDGES(e, g2, CSRGraphT) + for(const auto& e : boost::make_iterator_range(edges(g2))) { sources[idx] = source(e, g2); targets[idx] = target(e, g2); @@ -245,7 +244,8 @@ template < typename OrigGraph > void graph_test(const OrigGraph& g) std::vector< std::size_t > targets(num_edges(g2)); std::size_t idx = 0; // Edges reverse-sorted - BGL_FORALL_EDGES(e, g2, CSRGraphT) + + for(const auto& e : boost::make_iterator_range(edges(g2))) { sources[num_edges(g2) - 1 - idx] = source(e, g2); targets[num_edges(g2) - 1 - idx] = target(e, g2); @@ -263,13 +263,14 @@ template < typename OrigGraph > void graph_test(const OrigGraph& g) std::size_t idx = 0; // Edges scrambled using Fisher-Yates shuffle (Durstenfeld variant) from // Wikipedia - BGL_FORALL_EDGES(e, g2, CSRGraphT) + + for(const auto& e : boost::make_iterator_range(edges(g2))) { sources[idx] = source(e, g2); targets[idx] = target(e, g2); ++idx; } - boost::minstd_rand gen(1); + boost::minstd_rand gen(42); if (num_edges(g) != 0) { for (std::size_t i = num_edges(g) - 1; i > 0; --i) @@ -405,16 +406,15 @@ void test_vertex_and_edge_properties() .weight_map(get(&Edge::weight, g)) .edge_centrality_map(get(&Edge::centrality, g))); - BGL_FORALL_VERTICES(v, g, CSRGraphWithPropsT) - BOOST_TEST(g[v].centrality == centrality[v]); + + for(const auto& v : boost::make_iterator_range(vertices(g))) { + BOOST_TEST(g[v].centrality == centrality[v]); + } } -int main(int argc, char* argv[]) +int main() { - // Optionally accept a seed value - int seed = int(std::time(0)); - if (argc > 1) - seed = boost::lexical_cast< int >(argv[1]); + int seed = 42; std::cout << "Seed = " << seed << std::endl; { diff --git a/test/cuthill_mckee_ordering.cpp b/test/cuthill_mckee_ordering.cpp index b7880713a..43dbddeee 100644 --- a/test/cuthill_mckee_ordering.cpp +++ b/test/cuthill_mckee_ordering.cpp @@ -2,6 +2,7 @@ // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // Doug Gregor, D. Kevin McGrath +// Copyright (c) 2026 Arnaud Becheler // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -10,38 +11,23 @@ #include #include -#include #include #include #include #include +#include -/* - Sample Output - original bandwidth: 8 - Reverse Cuthill-McKee ordering starting at: 6 - 8 3 0 9 2 5 1 4 7 6 - bandwidth: 4 - Reverse Cuthill-McKee ordering starting at: 0 - 9 1 4 6 7 2 8 5 3 0 - bandwidth: 4 - Reverse Cuthill-McKee ordering: - 0 8 5 7 3 6 4 2 1 9 - bandwidth: 4 - */ -int main(int, char*[]) +int main() { using namespace boost; - using namespace std; - typedef adjacency_list< vecS, vecS, undirectedS, + using Graph = adjacency_list< vecS, vecS, undirectedS, property< vertex_color_t, default_color_type, - property< vertex_degree_t, int > > > - Graph; - typedef graph_traits< Graph >::vertex_descriptor Vertex; - typedef graph_traits< Graph >::vertices_size_type size_type; + property< vertex_degree_t, int > > >; + using Vertex = graph_traits< Graph >::vertex_descriptor; + using size_type = graph_traits< Graph >::vertices_size_type; - typedef std::pair< std::size_t, std::size_t > Pair; - Pair edges[14] = { Pair(0, 3), // a-d + using Pair = std::pair< std::size_t, std::size_t >; + constexpr Pair edges[14] = { Pair(0, 3), // a-d Pair(0, 5), // a-f Pair(1, 2), // b-c Pair(1, 4), // b-e @@ -66,72 +52,61 @@ int main(int, char*[]) for (boost::tie(ui, ui_end) = vertices(G); ui != ui_end; ++ui) deg[*ui] = degree(*ui, G); - property_map< Graph, vertex_index_t >::type index_map - = get(vertex_index, G); + property_map< Graph, vertex_index_t >::type index_map = get(vertex_index, G); - std::cout << "original bandwidth: " << bandwidth(G) << std::endl; + const size_type n = num_vertices(G); + auto assert_valid_permutation + = [&index_map, n](const std::vector< Vertex >& order) { + BOOST_TEST(order.size() == n); + std::vector< bool > seen(n, false); + for (std::size_t k = 0; k < order.size(); ++k) + { + size_type idx = index_map[order[k]]; + BOOST_TEST(idx < n); + if (idx < n) + { + BOOST_TEST(!seen[idx]); + seen[idx] = true; + } + } + for (size_type k = 0; k < n; ++k) + BOOST_TEST(seen[k]); + }; + const size_type original_bw = bandwidth(G); std::vector< Vertex > inv_perm(num_vertices(G)); std::vector< size_type > perm(num_vertices(G)); + { - Vertex s = vertex(6, G); // reverse cuthill_mckee_ordering - cuthill_mckee_ordering(G, s, inv_perm.rbegin(), get(vertex_color, G), - get(vertex_degree, G)); - cout << "Reverse Cuthill-McKee ordering starting at: " << s << endl; - cout << " "; - for (std::vector< Vertex >::const_iterator i = inv_perm.begin(); - i != inv_perm.end(); ++i) - cout << index_map[*i] << " "; - cout << endl; - + Vertex s = vertex(6, G); + cuthill_mckee_ordering(G, s, inv_perm.rbegin(), get(vertex_color, G), get(vertex_degree, G)); for (size_type c = 0; c != inv_perm.size(); ++c) perm[index_map[inv_perm[c]]] = c; - std::cout << " bandwidth: " - << bandwidth(G, - make_iterator_property_map( - &perm[0], index_map, perm[0])) - << std::endl; + size_type bw = bandwidth(G, make_iterator_property_map(&perm[0], index_map, perm[0])); + assert_valid_permutation(inv_perm); + BOOST_TEST(bw <= original_bw); } + { - Vertex s = vertex(0, G); // reverse cuthill_mckee_ordering - cuthill_mckee_ordering(G, s, inv_perm.rbegin(), get(vertex_color, G), - get(vertex_degree, G)); - cout << "Reverse Cuthill-McKee ordering starting at: " << s << endl; - cout << " "; - for (std::vector< Vertex >::const_iterator i = inv_perm.begin(); - i != inv_perm.end(); ++i) - cout << index_map[*i] << " "; - cout << endl; - + Vertex s = vertex(0, G); + cuthill_mckee_ordering(G, s, inv_perm.rbegin(), get(vertex_color, G), get(vertex_degree, G)); for (size_type c = 0; c != inv_perm.size(); ++c) perm[index_map[inv_perm[c]]] = c; - std::cout << " bandwidth: " - << bandwidth(G, - make_iterator_property_map( - &perm[0], index_map, perm[0])) - << std::endl; + size_type bw = bandwidth(G, make_iterator_property_map(&perm[0], index_map, perm[0])); + assert_valid_permutation(inv_perm); + BOOST_TEST(bw <= original_bw); } { // reverse cuthill_mckee_ordering cuthill_mckee_ordering(G, inv_perm.rbegin()); - - cout << "Reverse Cuthill-McKee ordering:" << endl; - cout << " "; - for (std::vector< Vertex >::const_iterator i = inv_perm.begin(); - i != inv_perm.end(); ++i) - cout << index_map[*i] << " "; - cout << endl; - for (size_type c = 0; c != inv_perm.size(); ++c) perm[index_map[inv_perm[c]]] = c; - std::cout << " bandwidth: " - << bandwidth(G, - make_iterator_property_map( - &perm[0], index_map, perm[0])) - << std::endl; + size_type bw = bandwidth(G, make_iterator_property_map(&perm[0], index_map, perm[0])); + assert_valid_permutation(inv_perm); + BOOST_TEST(bw <= original_bw); } - return 0; + return boost::report_errors(); } diff --git a/test/delete_edge.cpp b/test/delete_edge.cpp index 2abbfc764..044135630 100644 --- a/test/delete_edge.cpp +++ b/test/delete_edge.cpp @@ -14,7 +14,7 @@ #include -int main(int argc, char* argv[]) +int main() { typedef int Vertex; typedef int Edge; diff --git a/test/dfs.cpp b/test/dfs.cpp index 64d500f9a..90e337e0f 100644 --- a/test/dfs.cpp +++ b/test/dfs.cpp @@ -120,7 +120,7 @@ template < typename Graph > struct dfs_test typename Traits::edges_size_type j; typename Traits::vertex_iterator vi, vi_end, ui, ui_end; - boost::mt19937 gen; + boost::mt19937 gen(42); for (i = 0; i < max_V; ++i) for (j = 0; j < i * i; ++j) @@ -184,6 +184,34 @@ template < typename Graph > struct dfs_test } }; +// regression guard: finish_edge must fire once per edge (it once never did) +struct finish_edge_counter : boost::dfs_visitor<> +{ + explicit finish_edge_counter(std::size_t& count) : m_count(&count) {} + template < class Edge, class Graph > void finish_edge(Edge, Graph&) const + { + ++*m_count; + } + std::size_t* m_count; +}; + +void test_finish_edge_is_called() +{ + using graph_t = boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS >; + graph_t g; + graph_t::vertex_descriptor a = boost::add_vertex(g); + graph_t::vertex_descriptor b = boost::add_vertex(g); + graph_t::vertex_descriptor c = boost::add_vertex(g); + boost::add_edge(a, b, g); + boost::add_edge(b, c, g); + boost::add_edge(c, a, g); + boost::add_edge(a, c, g); + + std::size_t finish_edge_calls = 0; + boost::depth_first_search(g, boost::visitor(finish_edge_counter(finish_edge_calls))); + BOOST_TEST_EQ(finish_edge_calls, boost::num_edges(g)); +} + // usage: dfs.exe [max-vertices=15] int main(int argc, char* argv[]) @@ -202,5 +230,7 @@ int main(int argc, char* argv[]) boost::property< boost::vertex_color_t, boost::default_color_type > > >::go(max_V); + test_finish_edge_is_called(); + return boost::report_errors(); } diff --git a/test/dijkstra_heap_performance.cpp b/test/dijkstra_heap_performance.cpp index 89aaa38bc..6c6b9ed0b 100644 --- a/test/dijkstra_heap_performance.cpp +++ b/test/dijkstra_heap_performance.cpp @@ -84,7 +84,7 @@ int main(int argc, char* argv[]) { unsigned n = (argc > 1 ? lexical_cast< unsigned >(argv[1]) : 10000u); unsigned m = (argc > 2 ? lexical_cast< unsigned >(argv[2]) : 10 * n); - int seed = (argc > 3 ? lexical_cast< int >(argv[3]) : 1); + int seed = 42; // Build random graph typedef adjacency_list< vecS, vecS, directedS, no_property, diff --git a/test/dijkstra_no_color_map_compare.cpp b/test/dijkstra_no_color_map_compare.cpp index 0762b2069..5cd9863aa 100644 --- a/test/dijkstra_no_color_map_compare.cpp +++ b/test/dijkstra_no_color_map_compare.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #ifdef BOOST_MSVC @@ -81,7 +80,7 @@ int main(int argc, char* argv[]) int vertices_to_create = 10; int edges_to_create = 500; - std::size_t random_seed = std::time(0); + std::size_t random_seed = 42; if (argc > 1) { @@ -93,11 +92,6 @@ int main(int argc, char* argv[]) edges_to_create = lexical_cast< int >(argv[2]); } - if (argc > 3) - { - random_seed = lexical_cast< std::size_t >(argv[3]); - } - minstd_rand generator(random_seed); // Set up graph diff --git a/test/finish_edge_bug.cpp b/test/finish_edge_bug.cpp deleted file mode 100644 index 34b9530bb..000000000 --- a/test/finish_edge_bug.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Author: Alex Lauser - -// Output (Note that 'finish_edge' is never printed): -// The example graph: -// 0 --> 1 2 -// 1 --> 2 -// 2 --> 0 - -#include -#include -#include -#include -#include - -template < typename graph_t > struct TalkativeVisitor : boost::dfs_visitor<> -{ - typedef typename boost::graph_traits< graph_t >::vertex_descriptor - vertex_descriptor; - typedef typename boost::graph_traits< graph_t >::edge_descriptor - edge_descriptor; - - // // Commented out to avoid clutter of the output. - // void discover_vertex(vertex_descriptor u, const graph_t&) { // check! - // std::cout << "discover_vertex: " << u << std::endl; - // } - // void finish_vertex(vertex_descriptor u, const graph_t&) { // check! - // std::cout << "finish_vertex: " << u << std::endl; - // } - // void initialize_vertex(vertex_descriptor u, const graph_t&) { // check! - // std::cout << "initialize_vertex: " << u << std::endl; - // } - // void start_vertex(vertex_descriptor u, const graph_t&) { // check! - // std::cout << "start_vertex: " << u << std::endl; - // } - // void examine_edge(edge_descriptor u, const graph_t&) { // check! - // std::cout << "examine_edge: " << u << std::endl; - // } - // void tree_edge(edge_descriptor u, const graph_t&) { // check! - // std::cout << "tree_edge: " << u << std::endl; - // } - // void back_edge(edge_descriptor u, const graph_t&) { // check! - // std::cout << "back_edge: " << u << std::endl; - // } - // void forward_or_cross_edge(edge_descriptor u, const graph_t&) { // check! - // std::cout << "forward_or_cross_edge: " << u << std::endl; - // } - void finish_edge(edge_descriptor u, const graph_t&) - { // uncalled! - std::cout << "finish_edge: " << u << std::endl; - } -}; - -template < typename t > -std::ostream& operator<<(std::ostream& os, const std::pair< t, t >& x) -{ - return os << "(" << x.first << ", " << x.second << ")"; -} - -int main(int, char*[]) -{ - using namespace boost; - - typedef adjacency_list< vecS, vecS, directedS > Graph; - Graph G; - - typedef graph_traits< - adjacency_list< vecS, vecS, directedS > >::vertex_descriptor Vertex; - Vertex a = add_vertex(G); - Vertex b = add_vertex(G); - Vertex c = add_vertex(G); - - add_edge(a, b, G); - add_edge(b, c, G); - add_edge(c, a, G); - add_edge(a, c, G); - - std::cout << "The example graph:" << std::endl; - print_graph(G); - - std::vector< default_color_type > color(num_vertices(G)); - depth_first_search(G, visitor(TalkativeVisitor< Graph >())); - - return 0; -} diff --git a/test/floyd_warshall_test.cpp b/test/floyd_warshall_test.cpp index 0cc99ca9f..527eefbf1 100644 --- a/test/floyd_warshall_test.cpp +++ b/test/floyd_warshall_test.cpp @@ -28,7 +28,7 @@ template < typename T > inline const T& my_min(const T& x, const T& y) template < typename Graph > bool acceptance_test(Graph& g, int vec, int e) { - boost::minstd_rand ran(vec); + boost::minstd_rand ran(42); { typename boost::property_map< Graph, boost::vertex_name_t >::type index @@ -226,7 +226,7 @@ template < typename Graph > bool acceptance_test(Graph& g, int vec, int e) template < typename Graph > bool acceptance_test2(Graph& g, int vec, int e) { - boost::minstd_rand ran(vec); + boost::minstd_rand ran(42); { diff --git a/test/generator_test.cpp b/test/generator_test.cpp index 340d1954d..d7b9293bf 100644 --- a/test/generator_test.cpp +++ b/test/generator_test.cpp @@ -20,14 +20,14 @@ using namespace boost; -int main(int argc, char** argv) +int main() { typedef rand48 RandomGenerator; typedef adjacency_list< vecS, vecS, directedS > Graph; - RandomGenerator gen; + RandomGenerator gen(42); size_t N = 100; size_t M = 1000; diff --git a/test/graph.cpp b/test/graph.cpp index 596c3a7d6..7d4d9383d 100644 --- a/test/graph.cpp +++ b/test/graph.cpp @@ -178,7 +178,7 @@ int main(int, char*[]) add_vertex(current_vertex_id++, g); // also need to test EdgeIterator graph constructor -JGS - mt19937 gen; + mt19937 gen(42); for (j = 0; j < 10; ++j) { diff --git a/test/graphml_test.cpp b/test/graphml_test.cpp index 540fb093a..1b1b9468b 100644 --- a/test/graphml_test.cpp +++ b/test/graphml_test.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2026 Arnaud Becheler // Copyright (C) 2006 Tiago de Paula Peixoto // // Boost Software License - Version 1.0 - August 17th, 2003 @@ -31,74 +32,170 @@ #include #include #include +#include #include -using namespace std; -using namespace boost; +// Direct check of the entity escaping applied on the write path. +void test_encode_char_entities() +{ + using boost::detail::graphml::encode_char_entities; + // Empty stays empty. + BOOST_TEST_EQ(encode_char_entities(""), std::string("")); + // Ordinary text passes through untouched. + BOOST_TEST_EQ(encode_char_entities("plain text"), std::string("plain text")); + // An all-spaces value keeps its length via a leading numeric entity. + BOOST_TEST_EQ(encode_char_entities(" "), std::string(" ")); + // Each reserved character maps to its named entity. + BOOST_TEST_EQ(encode_char_entities("<>&\"'"), std::string("<>&"'")); + // Reserved characters are escaped in place among ordinary ones. + BOOST_TEST_EQ(encode_char_entities("ac&d\"e'f"), std::string("a<b>c&d"e'f")); +} -int main(int argc, char** argv) +// A value carrying all five reserved characters survives a write then read. +void test_special_chars_round_trip() { - typedef adjacency_list< vecS, vecS, directedS, - property< vertex_color_t, int, property< vertex_name_t, string > >, - property< edge_weight_t, double >, property< graph_name_t, string > > - graph_t; + using graph_t = boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS, boost::property< boost::vertex_name_t, std::string > >; + + const std::string special = "ac&d\"e'f"; + + graph_t g; + auto v = boost::add_vertex(g); + boost::put(boost::vertex_name_t(), g, v, special); + + boost::dynamic_properties dp; + dp.property("name", boost::get(boost::vertex_name_t(), g)); + + std::ostringstream out; + boost::write_graphml(out, g, dp); + + graph_t g2; + boost::dynamic_properties dp2; + dp2.property("name", boost::get(boost::vertex_name_t(), g2)); + std::istringstream in(out.str()); + boost::read_graphml(in, g2, dp2); + + auto round_tripped = boost::get(boost::vertex_name_t(), g2, boost::vertex(0, g2)); + BOOST_TEST_EQ(boost::num_vertices(g2), std::size_t(1)); + BOOST_TEST_EQ(round_tripped, special); +} + +// A required XML attribute that is absent raises parse_error. +void test_missing_required_attribute() +{ + using graph_t = boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS >; + + // The lone edge omits its mandatory source attribute. + const std::string malformed = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + graph_t g; - dynamic_properties dp; - dp.property("foo", get(vertex_color_t(), g)); - dp.property("weight", get(edge_weight_t(), g)); - dp.property("name", get(vertex_name_t(), g)); - boost::ref_property_map< graph_t*, std::string > gname( - get_property(g, graph_name)); + boost::dynamic_properties dp; + std::istringstream in(malformed); + BOOST_TEST_THROWS(boost::read_graphml(in, g, dp), boost::parse_error); +} + +// Ill-formed XML and a missing graphml root both raise parse_error. +void test_malformed_documents() +{ + using graph_t = boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS >; + + // Mismatched tags make the underlying XML parser fail. + const std::string ill_formed = ""; + { + graph_t g; + boost::dynamic_properties dp; + std::istringstream in(ill_formed); + BOOST_TEST_THROWS(boost::read_graphml(in, g, dp), boost::parse_error); + } + + // Well-formed XML whose root is not graphml has no graph to read. + const std::string no_graphml = "\n\n"; + { + graph_t g; + boost::dynamic_properties dp; + std::istringstream in(no_graphml); + BOOST_TEST_THROWS(boost::read_graphml(in, g, dp), boost::parse_error); + } +} + +int main(int, char** argv) +{ + test_encode_char_entities(); + test_special_chars_round_trip(); + test_missing_required_attribute(); + test_malformed_documents(); + + using graph_t = boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS, + boost::property< boost::vertex_color_t, int, boost::property< boost::vertex_name_t, std::string > >, + boost::property< boost::edge_weight_t, double >, boost::property< boost::graph_name_t, std::string > >; + graph_t g; + boost::dynamic_properties dp; + dp.property("foo", boost::get(boost::vertex_color_t(), g)); + dp.property("weight", boost::get(boost::edge_weight_t(), g)); + dp.property("name", boost::get(boost::vertex_name_t(), g)); + boost::ref_property_map< graph_t*, std::string > gname(boost::get_property(g, boost::graph_name)); dp.property("description", gname); - ifstream ifile(argv[1]); - read_graphml(ifile, g, dp); + std::ifstream ifile(argv[1]); + boost::read_graphml(ifile, g, dp); ifile.close(); - BOOST_TEST(num_vertices(g) == 9); - BOOST_TEST(num_edges(g) == 9); - BOOST_TEST(get(vertex_color_t(), g, vertex(2, g)) == 100); - BOOST_TEST(get(vertex_color_t(), g, vertex(3, g)) == 42); - BOOST_TEST(std::abs(get(edge_weight_t(), g, - edge(vertex(0, g), vertex(1, g), g).first) - - 0.0) - < 0.00001); - BOOST_TEST(std::abs(get(edge_weight_t(), g, - edge(vertex(1, g), vertex(2, g), g).first) - - 0.8) - < 0.00001); - BOOST_TEST(get("description", dp, &g) == "Root graph."); - - ofstream ofile("graphml_test_out.xml"); - write_graphml(ofile, g, dp); + BOOST_TEST(boost::num_vertices(g) == 9); + BOOST_TEST(boost::num_edges(g) == 9); + BOOST_TEST(boost::get(boost::vertex_color_t(), g, boost::vertex(2, g)) == 100); + BOOST_TEST(boost::get(boost::vertex_color_t(), g, boost::vertex(3, g)) == 42); + + auto edge_01 = boost::edge(boost::vertex(0, g), boost::vertex(1, g), g).first; + auto weight_01 = boost::get(boost::edge_weight_t(), g, edge_01); + BOOST_TEST(std::abs(weight_01 - 0.0) < 0.00001); + + auto edge_12 = boost::edge(boost::vertex(1, g), boost::vertex(2, g), g).first; + auto weight_12 = boost::get(boost::edge_weight_t(), g, edge_12); + BOOST_TEST(std::abs(weight_12 - 0.8) < 0.00001); + + BOOST_TEST(boost::get("description", dp, &g) == "Root graph."); + + std::ofstream ofile("graphml_test_out.xml"); + boost::write_graphml(ofile, g, dp); ofile.close(); graph_t g2; - dynamic_properties dp2; - dp2.property("foo", get(vertex_color_t(), g2)); - dp2.property("weight", get(edge_weight_t(), g2)); - dp2.property("name", get(vertex_name_t(), g2)); - boost::ref_property_map< graph_t*, std::string > gname2( - get_property(g2, graph_name)); + boost::dynamic_properties dp2; + dp2.property("foo", boost::get(boost::vertex_color_t(), g2)); + dp2.property("weight", boost::get(boost::edge_weight_t(), g2)); + dp2.property("name", boost::get(boost::vertex_name_t(), g2)); + boost::ref_property_map< graph_t*, std::string > gname2(boost::get_property(g2, boost::graph_name)); dp2.property("description", gname2); ifile.open("graphml_test_out.xml"); - read_graphml(ifile, g2, dp2); + boost::read_graphml(ifile, g2, dp2); ifile.close(); - BOOST_TEST(num_vertices(g) == num_vertices(g2)); - BOOST_TEST(num_edges(g) == num_edges(g2)); - BOOST_TEST(get("description", dp, &g) == get("description", dp2, &g2)); + BOOST_TEST(boost::num_vertices(g) == boost::num_vertices(g2)); + BOOST_TEST(boost::num_edges(g) == boost::num_edges(g2)); + BOOST_TEST(boost::get("description", dp, &g) == boost::get("description", dp2, &g2)); - graph_traits< graph_t >::vertex_iterator v, v_end; - for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) - BOOST_TEST( - get(vertex_color_t(), g, *v) == get(vertex_color_t(), g2, *v)); + boost::graph_traits< graph_t >::vertex_iterator v, v_end; + for (boost::tie(v, v_end) = boost::vertices(g); v != v_end; ++v) + { + auto color_1 = boost::get(boost::vertex_color_t(), g, *v); + auto color_2 = boost::get(boost::vertex_color_t(), g2, *v); + BOOST_TEST(color_1 == color_2); + } - graph_traits< graph_t >::edge_iterator e, e_end; - for (boost::tie(e, e_end) = edges(g); e != e_end; ++e) - BOOST_TEST( - std::abs(get(edge_weight_t(), g, *e) - get(edge_weight_t(), g2, *e)) - < 0.00001); + boost::graph_traits< graph_t >::edge_iterator e, e_end; + for (boost::tie(e, e_end) = boost::edges(g); e != e_end; ++e) + { + auto weight_1 = boost::get(boost::edge_weight_t(), g, *e); + auto weight_2 = boost::get(boost::edge_weight_t(), g2, *e); + BOOST_TEST(std::abs(weight_1 - weight_2) < 0.00001); + } return boost::report_errors(); } diff --git a/test/graphviz_round_trip_test.cpp b/test/graphviz_round_trip_test.cpp new file mode 100644 index 000000000..f761882a8 --- /dev/null +++ b/test/graphviz_round_trip_test.cpp @@ -0,0 +1,123 @@ +// Copyright (C) 2026 Arnaud Becheler +// +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Round-trips a graph through write_graphviz_dp and read_graphviz. The vertex +// and edge string values are chosen to straddle the DOT quoting boundary in +// escape_dot_string, so a writer that mis-quotes produces DOT that re-reads +// into different values and fails the comparison. + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + +struct vertex_props +{ + std::string node_id; + std::string label; +}; + +struct edge_props +{ + std::string elabel; +}; + +using graph_t = boost::adjacency_list< boost::vecS, boost::vecS, + boost::directedS, vertex_props, edge_props >; + +// First four are valid unquoted DOT ids/numerals +// the rest force quoting or escaping: space, embedded quote, digit-led +// identifier, multi-dot numeral, a lone dash, and a leading non-id character. +const std::vector< std::string >& boundary_labels() +{ + static const std::vector< std::string > labels = { "plain", "id_123", "42", + "-3.14", "has space", "has\"quote", "9lives", "1.2.3", "-", "@home" }; + return labels; +} + +graph_t make_graph() +{ + const std::vector< std::string >& labels = boundary_labels(); + graph_t g; + std::vector< graph_t::vertex_descriptor > added; + added.reserve(labels.size()); + for (std::size_t i = 0; i < labels.size(); ++i) + { + graph_t::vertex_descriptor vd = boost::add_vertex(g); + g[vd].node_id = "n" + std::to_string(i); + g[vd].label = labels[i]; + added.push_back(vd); + } + for (std::size_t i = 1; i < added.size(); ++i) + { + graph_t::edge_descriptor ed + = boost::add_edge(added[i - 1], added[i], g).first; + g[ed].elabel = "e " + std::to_string(i); // space forces quoting + } + return g; +} + +std::map< std::string, std::string > labels_by_id(const graph_t& g) +{ + std::map< std::string, std::string > m; + graph_t::vertex_iterator it, end; + for (boost::tie(it, end) = boost::vertices(g); it != end; ++it) + m[g[*it].node_id] = g[*it].label; + return m; +} + +std::multiset< std::string > edges_repr(const graph_t& g) +{ + std::multiset< std::string > s; + graph_t::edge_iterator it, end; + for (boost::tie(it, end) = boost::edges(g); it != end; ++it) + { + const std::string src = g[boost::source(*it, g)].node_id; + const std::string tgt = g[boost::target(*it, g)].node_id; + s.insert(src + "->" + tgt + ":" + g[*it].elabel); + } + return s; +} + +boost::dynamic_properties make_properties(graph_t& g) +{ + boost::dynamic_properties dp; + dp.property("node_id", boost::get(&vertex_props::node_id, g)); + dp.property("label", boost::get(&vertex_props::label, g)); + dp.property("elabel", boost::get(&edge_props::elabel, g)); + return dp; +} + +} // namespace + +int main() +{ + graph_t g = make_graph(); + boost::dynamic_properties dp = make_properties(g); + + std::ostringstream out; + boost::write_graphviz_dp(out, g, dp, std::string("node_id")); + const std::string text = out.str(); + + graph_t g2; + boost::dynamic_properties dp2 = make_properties(g2); + const bool ok = boost::read_graphviz(text.begin(), text.end(), g2, dp2, "node_id"); + BOOST_TEST(ok); + + BOOST_TEST(boost::num_vertices(g) == boost::num_vertices(g2)); + BOOST_TEST(boost::num_edges(g) == boost::num_edges(g2)); + BOOST_TEST(labels_by_id(g) == labels_by_id(g2)); + BOOST_TEST(edges_repr(g) == edges_repr(g2)); + + return boost::report_errors(); +} diff --git a/test/graphviz_test.cpp b/test/graphviz_test.cpp index a2ea63747..41ff89047 100644 --- a/test/graphviz_test.cpp +++ b/test/graphviz_test.cpp @@ -30,10 +30,10 @@ typedef std::map< edge_t, Weight > expected_weights_t; struct Fixture { - std::string graphviz_text; - size_t correct_num_vertices; - expected_masses_t masses; - expected_weights_t weights; + std::string graphviz_text = {}; + size_t correct_num_vertices = 0; + expected_masses_t masses = {}; + expected_weights_t weights = {}; }; namespace Samples diff --git a/test/grid_graph_test.cpp b/test/grid_graph_test.cpp index 7faff8df2..de0e9a0c2 100644 --- a/test/grid_graph_test.cpp +++ b/test/grid_graph_test.cpp @@ -10,9 +10,8 @@ #include #include #include -#include -#include +#include #include #include #include @@ -100,7 +99,8 @@ template < unsigned int Dims > void do_test(minstd_rand& generator) // Verify all vertices are within bounds vertices_size_type vertex_count = 0; - BOOST_FOREACH (vertex_descriptor current_vertex, vertices(graph)) + for (vertex_descriptor current_vertex : + boost::make_iterator_range(vertices(graph))) { vertices_size_type current_index @@ -118,8 +118,8 @@ template < unsigned int Dims > void do_test(minstd_rand& generator) edges_size_type out_edge_count = 0; std::set< vertices_size_type > target_vertices; - BOOST_FOREACH ( - edge_descriptor out_edge, out_edges(current_vertex, graph)) + for (edge_descriptor out_edge : + boost::make_iterator_range(out_edges(current_vertex, graph))) { target_vertices.insert( @@ -133,7 +133,8 @@ template < unsigned int Dims > void do_test(minstd_rand& generator) // Verify in-edges of this vertex edges_size_type in_edge_count = 0; - BOOST_FOREACH (edge_descriptor in_edge, in_edges(current_vertex, graph)) + for (edge_descriptor in_edge : + boost::make_iterator_range(in_edges(current_vertex, graph))) { BOOST_TEST(target_vertices.count(get(boost::vertex_index, graph, @@ -153,8 +154,8 @@ template < unsigned int Dims > void do_test(minstd_rand& generator) // Verify adjacent vertices to this vertex vertices_size_type adjacent_count = 0; - BOOST_FOREACH (vertex_descriptor adjacent_vertex, - adjacent_vertices(current_vertex, graph)) + for (vertex_descriptor adjacent_vertex : boost::make_iterator_range( + adjacent_vertices(current_vertex, graph))) { BOOST_TEST(target_vertices.count( @@ -168,7 +169,8 @@ template < unsigned int Dims > void do_test(minstd_rand& generator) // Verify that this vertex is not listed as connected to any // vertices outside of its adjacent vertices. - BOOST_FOREACH (vertex_descriptor unconnected_vertex, vertices(graph)) + for (vertex_descriptor unconnected_vertex : + boost::make_iterator_range(vertices(graph))) { vertices_size_type unconnected_index @@ -193,7 +195,8 @@ template < unsigned int Dims > void do_test(minstd_rand& generator) // Verify all edges are within bounds edges_size_type edge_count = 0; - BOOST_FOREACH (edge_descriptor current_edge, edges(graph)) + for (edge_descriptor current_edge : + boost::make_iterator_range(edges(graph))) { vertices_size_type source_index @@ -222,15 +225,9 @@ template < unsigned int Dims > void do_test(minstd_rand& generator) BOOST_TEST(edge_count == num_edges(graph)); } -int main(int argc, char* argv[]) +int main() { - - std::size_t random_seed = std::time(0); - - if (argc > 1) - { - random_seed = lexical_cast< std::size_t >(argv[1]); - } + std::size_t random_seed = 42; minstd_rand generator(random_seed); diff --git a/test/gursoy_atun_layout_test.cpp b/test/gursoy_atun_layout_test.cpp index d7d578fdb..58ba4a230 100644 --- a/test/gursoy_atun_layout_test.cpp +++ b/test/gursoy_atun_layout_test.cpp @@ -1,4 +1,5 @@ // Copyright 2004 The Trustees of Indiana University. +// Copyright (c) 2026 Arnaud Becheler // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -7,146 +8,102 @@ // Authors: Jeremiah Willcock // Douglas Gregor // Andrew Lumsdaine -#include -#include "boost/graph/adjacency_list.hpp" -#include "boost/graph/random.hpp" -#include "boost/graph/graphviz.hpp" -#include "boost/random/mersenne_twister.hpp" -#include "boost/random/linear_congruential.hpp" -#include "boost/random/uniform_01.hpp" -#include -#include -#include - -#if 0 -#include -#include -#endif -using namespace boost; - -template < class Property, class Vertex > struct position_writer -{ - const Property& property; - - position_writer(const Property& property) : property(property) {} - - void operator()(std::ostream& os, const Vertex& v) const - { - os << "[pos=\"" << int(property[v][0]) << "," << int(property[v][1]) - << "\"]"; - } -}; -struct graph_writer -{ - void operator()(std::ostream& os) const - { - os << "node [shape=point, width=\".01\", height=\".01\", " - "fixedsize=\"true\"]" - << std::endl; - } -}; - -int main(int, char*[]) +#include +#include +#include + +#include +#include +#include +#include +#include + +using graph_type = boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS, boost::no_property, boost::property< boost::edge_weight_t, double > >; +using vertex_index_map = boost::property_map< graph_type, boost::vertex_index_t >::type; +using topology = boost::heart_topology<>; +using point = topology::point_type; +using position_map = boost::iterator_property_map< std::vector< point >::iterator, vertex_index_map, point, point& >; + +// Builds the 20x20 weighted grid Gursoy and Atun used +void build_grid(graph_type& g) { - // Generate a graph structured like a grid, cylinder, or torus; lay it out - // in a square grid; and output it in dot format - - typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS, - boost::no_property, boost::property< boost::edge_weight_t, double > > - graph_type; - typedef boost::graph_traits< graph_type >::vertex_descriptor - vertex_descriptor; - // boost::mt19937 rng; - // boost::generate_random_graph(graph, 100, 600, rng, false, false); - -#if 1 - graph_type graph; - - // Make grid, like Gursoy and Atun used + using vertex_descriptor = boost::graph_traits< graph_type >::vertex_descriptor; + constexpr int grid_size = 20; std::map< int, std::map< int, vertex_descriptor > > verts; - const int grid_size = 20; - boost::minstd_rand edge_weight_gen; - boost::uniform_01< boost::minstd_rand > random_edge_weight(edge_weight_gen); + std::mt19937 engine(42); + std::uniform_real_distribution< double > dist(0.0, 1.0); + auto random_edge_weight = [&] { return dist(engine); }; + for (int i = 0; i < grid_size; ++i) for (int j = 0; j < grid_size; ++j) - verts[i][j] = add_vertex(graph); + verts[i][j] = boost::add_vertex(g); + for (int i = 0; i < grid_size; ++i) { for (int j = 0; j < grid_size; ++j) { if (i != 0) - add_edge( - verts[i][j], verts[i - 1][j], random_edge_weight(), graph); + boost::add_edge(verts[i][j], verts[i - 1][j], random_edge_weight(), g); if (j != 0) - add_edge( - verts[i][j], verts[i][j - 1], random_edge_weight(), graph); -#if 0 - // Uncomment parts of this to get a cylinder or torus - if (i == 0) - add_edge(verts[0][j], verts[grid_size-1][j], random_edge_weight(), - graph); - if (j == 0) - add_edge(verts[i][0], verts[i][grid_size-1], random_edge_weight(), - graph); -#endif + boost::add_edge(verts[i][j], verts[i][j - 1], random_edge_weight(), g); } } -#else - using namespace boost; +} -#if 0 - int n = 10000; - double alpha = 0.4; - double beta = 50; - minstd_rand gen; - graph_type graph(plod_iterator(gen, n, alpha, beta), - plod_iterator(), - n); -#else - int n = 1000; - int k = 6; - double p = 0.001; - minstd_rand gen; - graph_type graph(small_world_iterator< minstd_rand >(gen, n, k, p), - small_world_iterator< minstd_rand >(n, k), n); -#endif -#endif - // boost::read_graphviz(stdin, graph); +// Positions are heuristic, so we assert invariants instead of exact coordinates +// every point finite, inside the bounds, not all collapsed in one spot. +bool layout_is_valid(const std::vector< point >& pos) +{ + constexpr double eps = 1e-6; + constexpr double y_min = -2000.0; + // The heart's two circles bulge past the square to x = +-500(1 + sqrt2) + // and up to y = 500(sqrt2 - 1) and the square's tip reaches y = -2000. + const double x_max = 500.0 * (1.0 + std::sqrt(2.0)); + const double x_min = -x_max; + const double y_max = 500.0 * (std::sqrt(2.0) - 1.0); + double min_x = pos[0][0], max_x = pos[0][0], min_y = pos[0][1], max_y = pos[0][1]; + + for (const point& p : pos) + { + if (!std::isfinite(p[0]) || !std::isfinite(p[1])) + return false; + if (p[0] < x_min - eps || p[0] > x_max + eps) + return false; + if (p[1] < y_min - eps || p[1] > y_max + eps) + return false; + min_x = std::min(min_x, p[0]); + max_x = std::max(max_x, p[0]); + min_y = std::min(min_y, p[1]); + max_y = std::max(max_y, p[1]); + } + constexpr double spread_threshold = 1.0; + return (max_x - min_x) > spread_threshold || (max_y - min_y) > spread_threshold; +} - typedef boost::property_map< graph_type, boost::vertex_index_t >::type - VertexIndexMap; - VertexIndexMap vertex_index = get(boost::vertex_index_t(), graph); +int main() +{ + graph_type g; + build_grid(g); - typedef boost::heart_topology<> topology; + auto index_map = boost::get(boost::vertex_index, g); + std::vector< point > positions(boost::num_vertices(g)); + position_map position(positions.begin(), index_map); topology space; - typedef topology::point_type point; - std::vector< point > position_vector(num_vertices(graph)); - typedef boost::iterator_property_map< std::vector< point >::iterator, - VertexIndexMap, point, point& > - Position; - Position position(position_vector.begin(), vertex_index); - - boost::gursoy_atun_layout(graph, space, position); - -#if 0 - std::cerr << "--------Unweighted layout--------\n"; - boost::write_graphviz(std::cout, graph, - position_writer(position), - boost::default_writer(), - graph_writer()); -#endif - - boost::gursoy_atun_layout( - graph, space, position, weight_map(get(boost::edge_weight, graph))); - -#if 0 - std::cerr << "--------Weighted layout--------\n"; - boost::write_graphviz(std::cout, graph, - position_writer(position), - boost::default_writer(), - graph_writer()); -#endif - return 0; + // unweighted layout uses BFS hop distances + boost::gursoy_atun_layout(g, space, position); + BOOST_TEST(layout_is_valid(positions)); + + // weighted layout uses Dijkstra distances over the edge weights + auto edge_weights = boost::get(boost::edge_weight, g); + const int nsteps = static_cast< int >(boost::num_vertices(g)); + const double diameter_initial = std::sqrt(static_cast< double >(boost::num_vertices(g))); + const double diameter_final = 1.0; + const double learning_initial = 0.8; + const double learning_final = 0.2; + boost::gursoy_atun_layout(g, space, position, nsteps, diameter_initial, diameter_final, learning_initial, learning_final, index_map, edge_weights); + BOOST_TEST(layout_is_valid(positions)); + + return boost::report_errors(); } diff --git a/test/hawick_circuits.cpp b/test/hawick_circuits.cpp index c2fbe639c..6c9a74254 100644 --- a/test/hawick_circuits.cpp +++ b/test/hawick_circuits.cpp @@ -6,6 +6,8 @@ #include "cycle_test.hpp" #include +#include +#include #include struct call_hawick_circuits @@ -32,6 +34,18 @@ struct call_hawick_unique_circuits } }; +struct not_copyable +{ + not_copyable() { } + not_copyable(not_copyable const&) = delete; + + template < typename Path, typename Graph > + void cycle(Path const&, Graph const&) + { + + } +}; + int main() { // The last two arguments to cycle_test() are the expected (correct) @@ -62,6 +76,24 @@ int main() cycle_test(call_hawick_unique_circuits(ml), nc3[ml], nc4[ml]); } + // Make sure we can pass a reference_wrapper to the algorithm. + { + typedef boost::adjacency_list Graph; + typedef std::pair Pair; + Pair edges[3] = { + Pair(0, 1), // a->b + Pair(1, 2), // b->c + Pair(2, 0), // c->a + }; + + Graph G(3); + for (int i = 0; i < 3; ++i) + add_edge(edges[i].first, edges[i].second, G); + + not_copyable visitor; + boost::hawick_circuits(G, std::ref(visitor)); + } + std::cout << "\n\n"; return boost::report_errors(); } diff --git a/test/incremental_components_test.cpp b/test/incremental_components_test.cpp index df833be9f..ed386efc1 100644 --- a/test/incremental_components_test.cpp +++ b/test/incremental_components_test.cpp @@ -10,15 +10,14 @@ #include #include #include -#include -#include #include #include #include #include #include #include +#include #include using namespace boost; @@ -69,20 +68,21 @@ template < typename Graph > void test_graph(const Graph& graph) // Create a reverse-lookup map for vertex indices std::vector< vertex_descriptor > reverse_index_map(num_vertices(graph)); - BOOST_FOREACH (vertex_descriptor vertex, vertices(graph)) + for (vertex_descriptor vertex : + boost::make_iterator_range(vertices(graph))) { reverse_index_map[get(get(boost::vertex_index, graph), vertex)] = vertex; } // Verify that components are really connected - BOOST_FOREACH (vertices_size_type component_index, vertex_components) + for (vertices_size_type component_index : vertex_components) { std::set< vertex_descriptor > component_vertices; - BOOST_FOREACH ( - vertices_size_type child_index, vertex_components[component_index]) + for (vertices_size_type child_index : + boost::make_iterator_range(vertex_components[component_index])) { vertex_descriptor child_vertex = reverse_index_map[child_index]; @@ -92,7 +92,7 @@ template < typename Graph > void test_graph(const Graph& graph) // Verify that children are connected to each other in some // manner, but not to vertices outside their component. - BOOST_FOREACH (vertex_descriptor child_vertex, component_vertices) + for (vertex_descriptor child_vertex : component_vertices) { // Skip orphan vertices @@ -105,8 +105,8 @@ template < typename Graph > void test_graph(const Graph& graph) // another vertex in the component. bool edge_exists = false; - BOOST_FOREACH ( - edge_descriptor child_edge, out_edges(child_vertex, graph)) + for (edge_descriptor child_edge : + boost::make_iterator_range(out_edges(child_vertex, graph))) { if (component_vertices.count(target(child_edge, graph)) > 0) @@ -128,7 +128,7 @@ template < typename Graph > void test_graph(const Graph& graph) int main(int argc, char* argv[]) { std::size_t vertices_to_generate = 100, edges_to_generate = 50, - random_seed = std::time(0); + random_seed = 42; // Parse command-line arguments @@ -142,11 +142,6 @@ int main(int argc, char* argv[]) edges_to_generate = lexical_cast< std::size_t >(argv[2]); } - if (argc > 3) - { - random_seed = lexical_cast< std::size_t >(argv[3]); - } - minstd_rand generator(random_seed); // Generate random vector and list graphs @@ -162,8 +157,8 @@ int main(int argc, char* argv[]) // Assign indices to list_graph's vertices graph_traits< ListGraph >::vertices_size_type index = 0; - BOOST_FOREACH (graph_traits< ListGraph >::vertex_descriptor vertex, - vertices(list_graph)) + for (graph_traits< ListGraph >::vertex_descriptor vertex : + boost::make_iterator_range(vertices(list_graph))) { put(get(boost::vertex_index, list_graph), vertex, index++); } diff --git a/test/isomorphism.cpp b/test/isomorphism.cpp index d5d2ec914..c79b7e4a7 100644 --- a/test/isomorphism.cpp +++ b/test/isomorphism.cpp @@ -29,9 +29,7 @@ #include #include #include -#include -#define BOOST_GRAPH_USE_SPIRIT_PARSER #include #include @@ -75,7 +73,7 @@ randomly_permute_graph(const Graph1& g1, Graph2& g2) typedef typename graph_traits< Graph2 >::vertex_descriptor vertex2; typedef typename graph_traits< Graph1 >::edge_iterator edge_iterator; - random_generator_type gen; + random_generator_type gen(42); // Decide new order std::vector< vertex1 > orig_vertices; @@ -101,7 +99,7 @@ template < typename Graph > void generate_random_digraph(Graph& g, double edge_probability) { typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator; - random_generator_type random_gen; + random_generator_type random_gen(42); boost::uniform_real< double > distrib(0.0, 1.0); boost::variate_generator< random_generator_type&, boost::uniform_real< double > > @@ -293,7 +291,7 @@ void test_colored_isomorphism(int n, double edge_probability) std::fill(colors.begin(), midpoint, 0); std::fill(midpoint, colors.end(), 1); - random_generator_type gen; + random_generator_type gen(42); std::shuffle(colors.begin(), colors.end(), gen); @@ -421,13 +419,13 @@ void loadGraphFromDOT(const std::string& filename, Graph& g) -void test_github_issue_428() +void test_github_issue_428(const std::string& data_dir) { using Graph = boost::adjacency_list; Graph g0; Graph g1; - loadGraphFromDOT("github-428-0.dot", g0); - loadGraphFromDOT("github-428-1.dot", g1); + loadGraphFromDOT(data_dir + "/github-428-0.dot", g0); + loadGraphFromDOT(data_dir + "/github-428-1.dot", g1); const bool iso = boost::isomorphism(g0, g1); BOOST_TEST(iso); @@ -435,11 +433,14 @@ void test_github_issue_428() int main(int argc, char* argv[]) { - int n = argc < 3 ? 30 : boost::lexical_cast< int >(argv[1]); - double edge_prob = argc < 3 ? 0.45 : boost::lexical_cast< double >(argv[2]); + // b2 passes the test directory (TEST_DIR) so the issue-428 data files are + // found regardless of the working directory the test runs from. + const std::string data_dir = argc >= 2 ? argv[1] : "."; + const int n = 30; + const double edge_prob = 0.45; test_isomorphism(n, edge_prob); test_colored_isomorphism(n, edge_prob); - test_github_issue_428(); + test_github_issue_428(data_dir); return boost::report_errors(); } diff --git a/test/johnson-test.cpp b/test/johnson-test.cpp index 6f9c5604b..50ca1214f 100644 --- a/test/johnson-test.cpp +++ b/test/johnson-test.cpp @@ -1,55 +1,39 @@ //======================================================================= // Copyright 2002 Indiana University. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek +// Copyright (c) 2026 Arnaud Becheler // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= -/* Expected Output - 0 1 2 3 4 5 6 7 8 9 - 0 0 99 111 123 103 107 125 105 111 123 - 1 99 0 12 24 4 8 26 6 12 24 - 2 111 12 0 12 16 20 24 18 24 26 - 3 123 24 12 0 28 30 12 30 26 14 - 4 103 4 16 28 0 4 22 2 8 20 - 5 107 8 20 30 4 0 18 6 4 16 - 6 125 26 24 12 22 18 0 24 14 2 - 7 105 6 18 30 2 6 24 0 10 22 - 8 111 12 24 26 8 4 14 10 0 12 - 9 123 24 26 14 20 16 2 22 12 0 -*/ - #include #include -#include #include -#include #include #include -#include #include +#include int main() { using namespace boost; - typedef adjacency_list< vecS, vecS, undirectedS, no_property, - property< edge_weight_t, int, property< edge_weight2_t, int > > > - Graph; - const int V = 10; - typedef std::pair< int, int > Edge; - Edge edge_array[] = { Edge(0, 1), Edge(1, 2), Edge(2, 3), Edge(1, 4), - Edge(2, 5), Edge(3, 6), Edge(4, 5), Edge(5, 6), Edge(4, 7), Edge(5, 8), - Edge(6, 9), Edge(7, 8), Edge(8, 9) }; + using Graph = adjacency_list< vecS, vecS, undirectedS, no_property, + property< edge_weight_t, int, property< edge_weight2_t, int > > >; + constexpr int V = 10; + using Edge = std::pair< int, int >; + constexpr Edge edge_array[] = { Edge(0, 1), Edge(1, 2), Edge(2, 3), + Edge(1, 4), Edge(2, 5), Edge(3, 6), Edge(4, 5), Edge(5, 6), Edge(4, 7), + Edge(5, 8), Edge(6, 9), Edge(7, 8), Edge(8, 9) }; - const std::size_t E = sizeof(edge_array) / sizeof(Edge); + constexpr std::size_t E = sizeof(edge_array) / sizeof(Edge); Graph g(edge_array, edge_array + E, V); property_map< Graph, edge_weight_t >::type w = get(edge_weight, g); - int weights[] = { 99, 12, 12, 4, 99, 12, 4, 99, 2, 4, 2, 99, 12 }; - int* wp = weights; + constexpr int weights[] = { 99, 12, 12, 4, 99, 12, 4, 99, 2, 4, 2, 99, 12 }; + const int* wp = weights; graph_traits< Graph >::edge_iterator e, e_end; for (boost::tie(e, e_end) = edges(g); e != e_end; ++e) @@ -59,19 +43,22 @@ int main() int D[V][V]; johnson_all_pairs_shortest_paths(g, D, distance_map(&d[0])); - std::cout << std::setw(5) << " "; - for (int k = 0; k < 10; ++k) - std::cout << std::setw(5) << k; - std::cout << std::endl; - for (int i = 0; i < 10; ++i) - { - std::cout << std::setw(5) << i; - for (int j = 0; j < 10; ++j) - { - std::cout << std::setw(5) << D[i][j]; - } - std::cout << std::endl; - } + constexpr int expected[V][V] = { + { 0, 99, 111, 123, 103, 107, 125, 105, 111, 123 }, + { 99, 0, 12, 24, 4, 8, 26, 6, 12, 24 }, + { 111, 12, 0, 12, 16, 20, 24, 18, 24, 26 }, + { 123, 24, 12, 0, 28, 30, 12, 30, 26, 14 }, + { 103, 4, 16, 28, 0, 4, 22, 2, 8, 20 }, + { 107, 8, 20, 30, 4, 0, 18, 6, 4, 16 }, + { 125, 26, 24, 12, 22, 18, 0, 24, 14, 2 }, + { 105, 6, 18, 30, 2, 6, 24, 0, 10, 22 }, + { 111, 12, 24, 26, 8, 4, 14, 10, 0, 12 }, + { 123, 24, 26, 14, 20, 16, 2, 22, 12, 0 }, + }; + + for (int i = 0; i < V; ++i) + for (int j = 0; j < V; ++j) + BOOST_TEST_EQ(D[i][j], expected[i][j]); - return 0; + return boost::report_errors(); } diff --git a/test/layout_test.cpp b/test/layout_test.cpp index 52b07647e..2108ac87b 100644 --- a/test/layout_test.cpp +++ b/test/layout_test.cpp @@ -230,7 +230,7 @@ template < typename Graph > void test_cube(Graph*) dump_graph_layout("cube", g, get(vertex_position, g)); - minstd_rand gen; + minstd_rand gen(42); typedef square_topology<> Topology; Topology topology(gen, 50.0); std::vector< Topology::point_difference_type > displacements( @@ -291,7 +291,7 @@ template < typename Graph > void test_triangular(Graph*) std::cerr << std::endl; typedef square_topology<> Topology; - minstd_rand gen; + minstd_rand gen(42); Topology topology(gen, 50.0); Topology::point_type origin; origin[0] = origin[1] = 50.0; @@ -371,7 +371,7 @@ template < typename Graph > void test_disconnected(Graph*) kamada_kawai_done()); BOOST_TEST(!ok); - minstd_rand gen; + minstd_rand gen(42); rectangle_topology<> rect_top(gen, -25, -25, 25, 25); random_graph_layout(g, get(vertex_position, g), rect_top); diff --git a/test/louvain_clustering_test.cpp b/test/louvain_clustering_test.cpp index 2eb77b033..65830f7f5 100644 --- a/test/louvain_clustering_test.cpp +++ b/test/louvain_clustering_test.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/test/mas_sw_maxflow_oracle.hpp b/test/mas_sw_maxflow_oracle.hpp new file mode 100644 index 000000000..18c3672a4 --- /dev/null +++ b/test/mas_sw_maxflow_oracle.hpp @@ -0,0 +1,146 @@ +// Copyright Arnaud Becheler 2026. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or the copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Shared helpers for the maximum_adjacency_search and stoer_wagner_min_cut +// characterization tests: a curated set of small graphs each with its known +// global min cut, plus a push_relabel_max_flow oracle used to cross-check the +// MAS legal ordering property. + +#ifndef BOOST_GRAPH_TEST_MAS_SW_MAXFLOW_ORACLE_HPP +#define BOOST_GRAPH_TEST_MAS_SW_MAXFLOW_ORACLE_HPP + +#include +#include + +#include +#include +#include +#include + +namespace mas_sw_oracle +{ + +using undirected_graph = boost::adjacency_list< + boost::vecS, + boost::vecS, + boost::undirectedS, + boost::no_property, + boost::property< boost::edge_weight_t, int > +>; + +using weight_map_type = boost::property_map< undirected_graph, boost::edge_weight_t >::type; +using weight_type = boost::property_traits< weight_map_type >::value_type; +using vertex_descriptor = boost::graph_traits< undirected_graph >::vertex_descriptor; +using edge_descriptor = boost::graph_traits< undirected_graph >::edge_descriptor; + +// Directed network used only by the max-flow oracle. +using flow_traits = boost::adjacency_list_traits< boost::vecS, boost::vecS, boost::directedS >; +using flow_graph = boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS, + boost::no_property, + boost::property< boost::edge_capacity_t, weight_type, + boost::property< boost::edge_residual_capacity_t, weight_type, + boost::property< boost::edge_reverse_t, flow_traits::edge_descriptor > > > >; + +// Minimum u-v cut of the undirected graph via max-flow. +inline weight_type undirected_min_cut(const undirected_graph& g, vertex_descriptor u, vertex_descriptor v) +{ + flow_graph fg(num_vertices(g)); + auto capacity_map = get(boost::edge_capacity, fg); + auto reverse_edge_map = get(boost::edge_reverse, fg); + auto weight_map = get(boost::edge_weight, g); + + boost::graph_traits< undirected_graph >::edge_iterator ei, ei_end; + for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) + { + // read the undirected edge and its weight + const vertex_descriptor a = source(*ei, g); + const vertex_descriptor b = target(*ei, g); + const weight_type w = get(weight_map, *ei); + // arc a to b at capacity w, paired with a zero capacity reverse + const auto a_to_b = add_edge(a, b, fg).first; + const auto a_to_b_reverse = add_edge(b, a, fg).first; + put(capacity_map, a_to_b, w); + put(capacity_map, a_to_b_reverse, 0); + put(reverse_edge_map, a_to_b, a_to_b_reverse); + put(reverse_edge_map, a_to_b_reverse, a_to_b); + // opposite arc b to a, its own capacity w and zero capacity reverse + const auto b_to_a = add_edge(b, a, fg).first; + const auto b_to_a_reverse = add_edge(a, b, fg).first; + put(capacity_map, b_to_a, w); + put(capacity_map, b_to_a_reverse, 0); + put(reverse_edge_map, b_to_a, b_to_a_reverse); + put(reverse_edge_map, b_to_a_reverse, b_to_a); + } + return boost::push_relabel_max_flow(fg, u, v); +} + +inline weight_type weighted_degree(const undirected_graph& g, vertex_descriptor v) +{ + auto weight_map = get(boost::edge_weight, g); + weight_type sum = 0; + boost::graph_traits< undirected_graph >::out_edge_iterator oi, oi_end; + for (boost::tie(oi, oi_end) = out_edges(v, g); oi != oi_end; ++oi) sum += get(weight_map, *oi); + return sum; +} + +struct weighted_edge +{ + std::size_t u; + std::size_t v; + weight_type w; +}; + +// Build an undirected weighted graph from an explicit edge list. +inline undirected_graph make_weighted_graph(std::size_t n, std::initializer_list< weighted_edge > edges) +{ + undirected_graph g(n); + auto weight_map = get(boost::edge_weight, g); + for (const weighted_edge& e : edges) + { + const auto ed = add_edge(e.u, e.v, g).first; + put(weight_map, ed, e.w); + } + return g; +} + +inline bool is_connected(const undirected_graph& g) +{ + std::vector< std::size_t > component(num_vertices(g)); + auto components_map = boost::make_iterator_property_map(component.begin(), get(boost::vertex_index, g)); + return boost::connected_components(g, components_map) == 1U; +} + +// A curated graph together with its known global minimum cut. +struct curated_graph +{ + undirected_graph graph; + weight_type min_cut; +}; + +// Deterministic set of small graphs, each chosen to trigger a specific +// condition inside maximum_adjacency_search and stoer_wagner_min_cut. +inline std::vector< curated_graph > curated_graphs() +{ + std::vector< curated_graph > graphs; + // path: every cut is a single edge, min is the lightest + graphs.push_back({ make_weighted_graph(4, { { 0, 1, 3 }, { 1, 2, 1 }, { 2, 3, 2 } }), 1 }); + // triangle: min cut isolates the lowest weighted degree vertex + graphs.push_back({ make_weighted_graph(3, { { 0, 1, 2 }, { 0, 2, 6 }, { 1, 2, 7 } }), 8 }); + // two triangles joined by a light bridge (issue 286) + graphs.push_back({ make_weighted_graph(6, { { 0, 1, 10 }, { 0, 2, 10 }, { 1, 2, 10 }, { 3, 4, 10 }, { 3, 5, 10 }, { 4, 5, 10 }, { 0, 3, 1 } }), 1 }); + // multigraph: parallel edge weights must sum + graphs.push_back({ make_weighted_graph(3, { { 0, 1, 3 }, { 1, 2, 1 }, { 1, 2, 1 }, { 2, 0, 1 } }), 3 }); + // cycle with equal weights: ties in the reach counts + graphs.push_back({ make_weighted_graph(4, { { 0, 1, 1 }, { 1, 2, 1 }, { 2, 3, 1 }, { 3, 0, 1 } }), 2 }); + // star with one heavy spoke: min cut isolates the lightest leaf + graphs.push_back({ make_weighted_graph(5, { { 0, 1, 1 }, { 0, 2, 1 }, { 0, 3, 1 }, { 0, 4, 5 } }), 1 }); + // Stoer Wagner 1997 example + graphs.push_back({ make_weighted_graph(8, { { 0, 1, 2 }, { 1, 2, 3 }, { 2, 3, 4 }, { 0, 4, 3 }, { 1, 4, 2 }, { 1, 5, 2 }, { 2, 6, 2 }, { 3, 6, 2 }, { 3, 7, 2 }, { 4, 5, 3 }, { 5, 6, 1 }, { 6, 7, 3 } }), 4 }); + return graphs; +} + +} // namespace mas_sw_oracle + +#endif // BOOST_GRAPH_TEST_MAS_SW_MAXFLOW_ORACLE_HPP diff --git a/test/mas_test.cpp b/test/mas_test.cpp index 8aaf73294..a1d265eff 100644 --- a/test/mas_test.cpp +++ b/test/mas_test.cpp @@ -1,43 +1,38 @@ -// Copyright Fernando Vilas 2012. -// Based on stoer_wagner_test.cpp by Daniel Trebbien. +// Copyright Fernando Vilas 2012. +// Based on stoer_wagner_test.cpp by Daniel Trebbien. +// Copyright Arnaud Becheler 2026. // Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or the copy at -// http://www.boost.org/LICENSE_1_0.txt) +// (See accompanying file LICENSE_1_0.txt or the copy at +// http://www.boost.org/LICENSE_1_0.txt) -#include -#include +#include +#include #include -#include +#include +#include #include +#include #include #include #include #include #include -#include #include #include #include -#include #include +#include #include -#include -#include -#include -#include +#include "mas_sw_maxflow_oracle.hpp" -typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS, - boost::no_property, boost::property< boost::edge_weight_t, int > > - undirected_graph; -typedef boost::property_map< undirected_graph, boost::edge_weight_t >::type - weight_map_type; -typedef boost::property_traits< weight_map_type >::value_type weight_type; +using mas_sw_oracle::undirected_graph; +using mas_sw_oracle::weight_map_type; +using mas_sw_oracle::weight_type; +using mas_sw_oracle::vertex_descriptor; +using mas_sw_oracle::edge_descriptor; -typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS > - undirected_unweighted_graph; - -std::string test_dir; +using undirected_unweighted_graph = boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS >; struct edge_t { @@ -46,17 +41,17 @@ struct edge_t }; template < typename Graph, typename KeyedUpdatablePriorityQueue > -class mas_test_visitor : public boost::default_mas_visitor +class mas_test_visitor : public boost::graph::default_mas_visitor { public: - typedef typename boost::graph_traits< Graph >::vertex_descriptor - vertex_descriptor; - typedef typename KeyedUpdatablePriorityQueue::key_type weight_type; + using vertex_descriptor = typename boost::graph_traits< Graph >::vertex_descriptor; + using weight_type = typename KeyedUpdatablePriorityQueue::key_type; explicit mas_test_visitor(KeyedUpdatablePriorityQueue& pq) - : m_pq_(pq), - vertex_visit_order_(boost::make_shared< std::vector< vertex_descriptor > >()), - vertex_weights_when_visited_(boost::make_shared< std::vector< weight_type > >()) + : + m_pq_(pq), + vertex_visit_order_(std::make_shared< std::vector< vertex_descriptor > >()), + vertex_weights_when_visited_(std::make_shared< std::vector< weight_type > >()) {} void clear() @@ -65,527 +60,515 @@ class mas_test_visitor : public boost::default_mas_visitor vertex_weights_when_visited_->clear(); } - void start_vertex(vertex_descriptor u, const Graph& g) + void start_vertex(vertex_descriptor u, const Graph&) { vertex_visit_order_->push_back(u); - const weight_type u_weight = get(m_pq_.keys(), u); vertex_weights_when_visited_->push_back(u_weight); } - const std::vector& vertex_visit_order() const { - return *vertex_visit_order_; - } + const std::vector< vertex_descriptor >& vertex_visit_order() const { return *vertex_visit_order_; } - const std::vector& vertex_weights_when_visited() const { - return *vertex_weights_when_visited_; - } + const std::vector< weight_type >& vertex_weights_when_visited() const { return *vertex_weights_when_visited_; } private: const KeyedUpdatablePriorityQueue& m_pq_; - boost::shared_ptr< std::vector< vertex_descriptor > > vertex_visit_order_; - boost::shared_ptr< std::vector< weight_type > > vertex_weights_when_visited_; + std::shared_ptr< std::vector< vertex_descriptor > > vertex_visit_order_; + std::shared_ptr< std::vector< weight_type > > vertex_weights_when_visited_; }; // the example from Stoer & Wagner (1997) -// Check various implementations of the ArgPack where -// the weights are provided in it, and one case where -// they are not. +// run through the positional and convenience interfaces, with an explicit +// weight map and with a constant weight map. void test0() { - typedef boost::graph_traits< undirected_graph >::vertex_descriptor - vertex_descriptor; - typedef boost::graph_traits< undirected_graph >::edge_descriptor - edge_descriptor; + using vertex_descriptor = boost::graph_traits< undirected_graph >::vertex_descriptor; + using edge_descriptor = boost::graph_traits< undirected_graph >::edge_descriptor; + using distances_type = boost::shared_array_property_map< weight_type, boost::property_map< undirected_graph, boost::vertex_index_t >::const_type >; + using index_in_heap_type = std::vector< vertex_descriptor >::size_type; + using indices_in_heap_type = boost::shared_array_property_map< index_in_heap_type, boost::property_map< undirected_graph, boost::vertex_index_t >::const_type >; + using maxheap_type = boost::d_ary_heap_indirect< vertex_descriptor, 22, indices_in_heap_type, distances_type, std::greater< weight_type > >; - boost::array< edge_t, 12 > edge_list = { { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 0, 4 }, { 1, 4 }, { 1, 5 }, - { 2, 6 }, { 3, 6 }, { 3, 7 }, { 4, 5 }, { 5, 6 }, { 6, 7 } } }; - const boost::array ws = { 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 1, 3 }; - const std::size_t vertices_count = 8; + constexpr std::size_t vertices_count = 8; + boost::array< edge_t, 12 > edge_list = { { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 0, 4 }, { 1, 4 }, { 1, 5 }, { 2, 6 }, { 3, 6 }, { 3, 7 }, { 4, 5 }, { 5, 6 }, { 6, 7 } } }; + const boost::array< weight_type, 12 > ws = { 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 1, 3 }; undirected_graph g(edge_list.cbegin(), edge_list.cend(), ws.cbegin(), vertices_count, ws.size()); + + auto weight_map = get(boost::edge_weight, g); + auto id_map = get(boost::vertex_index, g); + auto distances_map = boost::make_shared_array_property_map(num_vertices(g), static_cast< weight_type >(0), id_map); + auto indices_map = boost::make_shared_array_property_map(num_vertices(g), static_cast< index_in_heap_type >(-1), id_map); + + maxheap_type pq(distances_map, indices_map); + mas_test_visitor< undirected_graph, maxheap_type > test_vis(pq); - weight_map_type weights = get(boost::edge_weight, g); - - std::map< vertex_descriptor, vertex_descriptor > assignment; - boost::associative_property_map< - std::map< vertex_descriptor, vertex_descriptor > > - assignments(assignment); - - typedef boost::shared_array_property_map< weight_type, - boost::property_map< undirected_graph, - boost::vertex_index_t >::const_type > - distances_type; - distances_type distances = boost::make_shared_array_property_map( - num_vertices(g), weight_type(0), get(boost::vertex_index, g)); - typedef std::vector< vertex_descriptor >::size_type index_in_heap_type; - typedef boost::shared_array_property_map< index_in_heap_type, - boost::property_map< undirected_graph, - boost::vertex_index_t >::const_type > - indicesInHeap_type; - indicesInHeap_type indicesInHeap = boost::make_shared_array_property_map( - num_vertices(g), index_in_heap_type(-1), get(boost::vertex_index, g)); - boost::d_ary_heap_indirect< vertex_descriptor, 22, indicesInHeap_type, - distances_type, std::greater< weight_type > > - pq(distances, indicesInHeap); - - mas_test_visitor< undirected_graph, - boost::d_ary_heap_indirect< vertex_descriptor, 22, indicesInHeap_type, - distances_type, std::greater< weight_type > > > - test_vis(pq); - - boost::maximum_adjacency_search(g, - boost::weight_map(weights) - .visitor(test_vis) - .root_vertex(*vertices(g).first) - .vertex_assignment_map(assignments) - .max_priority_queue(pq)); + // fully positional: weight map, visitor, start vertex, priority queue + boost::graph::maximum_adjacency_search(g, weight_map, test_vis, *vertices(g).first, pq); const boost::array< vertex_descriptor, vertices_count > expected_vertex_order1 = { 0, 4, 1, 5, 2, 3, 6, 7 }; const boost::array< weight_type, vertices_count > expected_weights_when_visited1 = { 9, 3, 4, 5, 3, 4, 5, 5 }; - BOOST_TEST_ALL_EQ( - test_vis.vertex_visit_order().begin(), - test_vis.vertex_visit_order().end(), - expected_vertex_order1.cbegin(), - expected_vertex_order1.cend() - ); - - BOOST_TEST_ALL_EQ( - test_vis.vertex_weights_when_visited().begin(), - test_vis.vertex_weights_when_visited().end(), - expected_weights_when_visited1.cbegin(), - expected_weights_when_visited1.cend() - ); - - test_vis.clear(); - - boost::maximum_adjacency_search(g, - boost::weight_map(weights) - .visitor(test_vis) - .root_vertex(*vertices(g).first) - .max_priority_queue(pq)); - - BOOST_TEST_ALL_EQ( - test_vis.vertex_visit_order().begin(), - test_vis.vertex_visit_order().end(), - expected_vertex_order1.cbegin(), - expected_vertex_order1.cend() - ); - - BOOST_TEST_ALL_EQ( - test_vis.vertex_weights_when_visited().begin(), - test_vis.vertex_weights_when_visited().end(), - expected_weights_when_visited1.cbegin(), - expected_weights_when_visited1.cend() - ); - - test_vis.clear(); - - boost::maximum_adjacency_search( - g, boost::weight_map(weights).visitor(test_vis).max_priority_queue(pq)); + BOOST_TEST_ALL_EQ(test_vis.vertex_visit_order().begin(), + test_vis.vertex_visit_order().end(), + expected_vertex_order1.cbegin(), + expected_vertex_order1.cend()); - BOOST_TEST_ALL_EQ( - test_vis.vertex_visit_order().begin(), - test_vis.vertex_visit_order().end(), - expected_vertex_order1.cbegin(), - expected_vertex_order1.cend() - ); + BOOST_TEST_ALL_EQ(test_vis.vertex_weights_when_visited().begin(), + test_vis.vertex_weights_when_visited().end(), + expected_weights_when_visited1.cbegin(), + expected_weights_when_visited1.cend()); - BOOST_TEST_ALL_EQ( - test_vis.vertex_weights_when_visited().begin(), - test_vis.vertex_weights_when_visited().end(), - expected_weights_when_visited1.cbegin(), - expected_weights_when_visited1.cend() - ); + // convenience overload: start vertex and priority queue are defaulted + boost::graph::maximum_adjacency_search(g, weight_map, boost::graph::make_mas_visitor(boost::null_visitor())); + boost::graph::maximum_adjacency_search(g, weight_map, boost::graph::default_mas_visitor()); test_vis.clear(); - boost::maximum_adjacency_search(g, - boost::weight_map(weights).visitor( - boost::make_mas_visitor(boost::null_visitor()))); - - boost::maximum_adjacency_search(g, boost::weight_map(weights)); - - boost::maximum_adjacency_search(g, boost::root_vertex(*vertices(g).first)); - - test_vis.clear(); - boost::maximum_adjacency_search(g, - boost::weight_map( - boost::make_constant_property< edge_descriptor >(weight_type(1))) - .visitor(test_vis) - .max_priority_queue(pq)); + // fully positional with a constant weight map + auto one_weight_map = boost::make_constant_property< edge_descriptor >(static_cast< weight_type >(1)); + boost::graph::maximum_adjacency_search(g, one_weight_map, test_vis, *vertices(g).first, pq); const boost::array< vertex_descriptor, vertices_count > expected_vertex_order2 = { 0, 1, 4, 5, 2, 6, 3, 7 }; const boost::array< weight_type, vertices_count > expected_weights_when_visited2 = { 9, 1, 2, 2, 1, 2, 2, 2 }; - BOOST_TEST_ALL_EQ( - test_vis.vertex_visit_order().begin(), - test_vis.vertex_visit_order().end(), - expected_vertex_order2.cbegin(), - expected_vertex_order2.cend() - ); - - BOOST_TEST_ALL_EQ( - test_vis.vertex_weights_when_visited().begin(), - test_vis.vertex_weights_when_visited().end(), - expected_weights_when_visited2.cbegin(), - expected_weights_when_visited2.cend() - ); + BOOST_TEST_ALL_EQ(test_vis.vertex_visit_order().begin(), + test_vis.vertex_visit_order().end(), + expected_vertex_order2.cbegin(), + expected_vertex_order2.cend()); + + BOOST_TEST_ALL_EQ(test_vis.vertex_weights_when_visited().begin(), + test_vis.vertex_weights_when_visited().end(), + expected_weights_when_visited2.cbegin(), + expected_weights_when_visited2.cend()); } -// Check the unweighted case -// with and without providing a weight_map +// Check the unweighted case, using a constant weight map and an explicit one. void test1() { - typedef boost::graph_traits< - undirected_unweighted_graph >::vertex_descriptor vertex_descriptor; - typedef boost::graph_traits< undirected_unweighted_graph >::edge_descriptor - edge_descriptor; + using vertex_descriptor = boost::graph_traits< undirected_unweighted_graph >::vertex_descriptor; + using edge_descriptor = boost::graph_traits< undirected_unweighted_graph >::edge_descriptor; + using weight_type = unsigned; + using distances_type = boost::shared_array_property_map< weight_type, boost::property_map< undirected_graph, boost::vertex_index_t >::const_type >; + using index_in_heap_type = std::vector< vertex_descriptor >::size_type; + using indices_in_heap_type = boost::shared_array_property_map< index_in_heap_type, boost::property_map< undirected_graph, boost::vertex_index_t >::const_type >; + using maxheap_type = boost::d_ary_heap_indirect< vertex_descriptor, 22, indices_in_heap_type, distances_type, std::greater< weight_type > >; - boost::array< edge_t, 12 > edge_list = { { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 0, 4 }, { 1, 4 }, { 1, 5 }, - { 2, 6 }, { 3, 6 }, { 3, 7 }, { 4, 5 }, { 5, 6 }, { 6, 7 } } }; - const std::size_t vertices_count = 8; + constexpr std::size_t vertices_count = 8; + boost::array< edge_t, 12 > edge_list = { { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 0, 4 }, { 1, 4 }, { 1, 5 }, { 2, 6 }, { 3, 6 }, { 3, 7 }, { 4, 5 }, { 5, 6 }, { 6, 7 } } }; undirected_unweighted_graph g(edge_list.cbegin(), edge_list.cend(), vertices_count); - std::map< vertex_descriptor, vertex_descriptor > assignment; - boost::associative_property_map< - std::map< vertex_descriptor, vertex_descriptor > > - assignments(assignment); - - typedef unsigned weight_type; - typedef boost::shared_array_property_map< weight_type, - boost::property_map< undirected_graph, - boost::vertex_index_t >::const_type > - distances_type; - distances_type distances = boost::make_shared_array_property_map( - num_vertices(g), weight_type(0), get(boost::vertex_index, g)); - typedef std::vector< vertex_descriptor >::size_type index_in_heap_type; - typedef boost::shared_array_property_map< index_in_heap_type, - boost::property_map< undirected_graph, - boost::vertex_index_t >::const_type > - indicesInHeap_type; - indicesInHeap_type indicesInHeap = boost::make_shared_array_property_map( - num_vertices(g), index_in_heap_type(-1), get(boost::vertex_index, g)); - boost::d_ary_heap_indirect< vertex_descriptor, 22, indicesInHeap_type, - distances_type, std::greater< weight_type > > - pq(distances, indicesInHeap); - - mas_test_visitor< undirected_unweighted_graph, - boost::d_ary_heap_indirect< vertex_descriptor, 22, indicesInHeap_type, - distances_type, std::greater< weight_type > > > - test_vis(pq); - - boost::maximum_adjacency_search(g, - boost::weight_map( - boost::make_constant_property< edge_descriptor >(weight_type(1))) - .visitor(test_vis) - .max_priority_queue(pq)); + auto id_map = get(boost::vertex_index, g); + auto distances_map = boost::make_shared_array_property_map(num_vertices(g), static_cast< weight_type >(0), id_map); + auto indices_map = boost::make_shared_array_property_map(num_vertices(g), static_cast< index_in_heap_type >(-1), id_map); + maxheap_type pq(distances_map, indices_map); + + mas_test_visitor< undirected_unweighted_graph, maxheap_type > test_vis(pq); + + auto one_weight_map = boost::make_constant_property< edge_descriptor >(static_cast< weight_type >(1)); + boost::graph::maximum_adjacency_search(g, one_weight_map, test_vis, *vertices(g).first, pq); const boost::array< vertex_descriptor, vertices_count > expected_vertex_order1 = { 0, 1, 4, 5, 2, 6, 3, 7 }; const boost::array< weight_type, vertices_count > expected_weights_when_visited1 = { 9, 1, 2, 2, 1, 2, 2, 2 }; - BOOST_TEST_ALL_EQ( - test_vis.vertex_visit_order().begin(), - test_vis.vertex_visit_order().end(), - expected_vertex_order1.cbegin(), - expected_vertex_order1.cend() - ); + BOOST_TEST_ALL_EQ(test_vis.vertex_visit_order().begin(), + test_vis.vertex_visit_order().end(), + expected_vertex_order1.cbegin(), + expected_vertex_order1.cend()); - BOOST_TEST_ALL_EQ( - test_vis.vertex_weights_when_visited().begin(), - test_vis.vertex_weights_when_visited().end(), - expected_weights_when_visited1.cbegin(), - expected_weights_when_visited1.cend() - ); + BOOST_TEST_ALL_EQ(test_vis.vertex_weights_when_visited().begin(), + test_vis.vertex_weights_when_visited().end(), + expected_weights_when_visited1.cbegin(), + expected_weights_when_visited1.cend()); test_vis.clear(); - const boost::array ws = { 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 1, 3 }; + const boost::array< weight_type, 12 > ws = { 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 1, 3 }; std::map< edge_descriptor, weight_type > wm; - - weight_type i = 0; - BGL_FORALL_EDGES(e, g, undirected_unweighted_graph) + std::size_t i = 0; + for (const auto& e : boost::make_iterator_range(edges(g))) { wm[e] = ws[i]; ++i; } - boost::associative_property_map< std::map< edge_descriptor, weight_type > > - ws_map(wm); + boost::associative_property_map< std::map< edge_descriptor, weight_type > > ws_map(wm); + + boost::graph::maximum_adjacency_search(g, ws_map, test_vis, *vertices(g).first, pq); - boost::maximum_adjacency_search( - g, boost::weight_map(ws_map).visitor(test_vis).max_priority_queue(pq)); - const boost::array< vertex_descriptor, vertices_count > expected_vertex_order2 = { 0, 4, 1, 5, 2, 3, 6, 7 }; const boost::array< weight_type, vertices_count > expected_weights_when_visited2 = { 9, 3, 4, 5, 3, 4, 5, 5 }; - BOOST_TEST_ALL_EQ( - test_vis.vertex_visit_order().begin(), - test_vis.vertex_visit_order().end(), - expected_vertex_order2.cbegin(), - expected_vertex_order2.cend() - ); - - BOOST_TEST_ALL_EQ( - test_vis.vertex_weights_when_visited().begin(), - test_vis.vertex_weights_when_visited().end(), - expected_weights_when_visited2.cbegin(), - expected_weights_when_visited2.cend() - ); -} - -typedef boost::graph_traits< undirected_unweighted_graph >::vertex_descriptor mas_test_vertex_descriptor; -typedef boost::graph_traits< undirected_unweighted_graph >::edge_descriptor mas_test_edge_descriptor; + BOOST_TEST_ALL_EQ(test_vis.vertex_visit_order().begin(), + test_vis.vertex_visit_order().end(), + expected_vertex_order2.cbegin(), + expected_vertex_order2.cend()); -typedef std::size_t mas_test_weight_type; // weight corresponds to the priority value in the priority queue. -typedef boost::shared_array_property_map< mas_test_weight_type, boost::property_map< undirected_graph, boost::vertex_index_t >::const_type > mas_test_distances_type; -typedef std::vector< mas_test_vertex_descriptor >::size_type mas_test_index_in_heap_type; -typedef boost::shared_array_property_map< mas_test_index_in_heap_type, boost::property_map< undirected_graph, boost::vertex_index_t >::const_type > mas_test_indicesInHeap_type; -const std::size_t mas_test_arity = 4; -typedef boost::d_ary_heap_indirect< mas_test_vertex_descriptor, mas_test_arity, mas_test_indicesInHeap_type, mas_test_distances_type, std::greater< mas_test_weight_type > > mas_test_maxheap_type; -typedef mas_test_visitor< undirected_unweighted_graph, mas_test_maxheap_type> mas_text_visitor_type; + BOOST_TEST_ALL_EQ(test_vis.vertex_weights_when_visited().begin(), + test_vis.vertex_weights_when_visited().end(), + expected_weights_when_visited2.cbegin(), + expected_weights_when_visited2.cend()); +} -template -mas_test_maxheap_type create_mas_test_maxheap(const Graph& g) { - mas_test_distances_type distances = boost::make_shared_array_property_map( - num_vertices(g), mas_test_weight_type(0), get(boost::vertex_index, g)); +using mas_test_vertex_descriptor = boost::graph_traits< undirected_unweighted_graph >::vertex_descriptor; +using mas_test_edge_descriptor = boost::graph_traits< undirected_unweighted_graph >::edge_descriptor; - mas_test_indicesInHeap_type indicesInHeap = boost::make_shared_array_property_map( - num_vertices(g), mas_test_index_in_heap_type(-1), get(boost::vertex_index, g)); +// weight corresponds to the priority value in the priority queue +using mas_test_weight_type = std::size_t; +using mas_test_distances_type = boost::shared_array_property_map< mas_test_weight_type, boost::property_map< undirected_graph, boost::vertex_index_t >::const_type >; +using mas_test_index_in_heap_type = std::vector< mas_test_vertex_descriptor >::size_type; +using mas_test_indices_in_heap_type = boost::shared_array_property_map< mas_test_index_in_heap_type, boost::property_map< undirected_graph, boost::vertex_index_t >::const_type >; +constexpr std::size_t mas_test_arity = 4; +using mas_test_maxheap_type = boost::d_ary_heap_indirect< mas_test_vertex_descriptor, mas_test_arity, mas_test_indices_in_heap_type, mas_test_distances_type, std::greater< mas_test_weight_type > >; +using mas_test_visitor_type = mas_test_visitor< undirected_unweighted_graph, mas_test_maxheap_type >; - return mas_test_maxheap_type(distances, indicesInHeap); +template < typename Graph > +mas_test_maxheap_type create_mas_test_maxheap(const Graph& g) +{ + auto id_map = get(boost::vertex_index, g); + auto distances_map = boost::make_shared_array_property_map(num_vertices(g), static_cast< mas_test_weight_type >(0), id_map); + auto indices_map = boost::make_shared_array_property_map(num_vertices(g), static_cast< mas_test_index_in_heap_type >(-1), id_map); + return mas_test_maxheap_type(distances_map, indices_map); } -template +template < std::size_t edge_count, std::size_t vertices_count > void test_weighted( - const boost::array& edge_list, - const boost::array weights_list, - const boost::array& expected_vertex_order, - const boost::array& expected_weights_when_visited, - const mas_test_vertex_descriptor start_vertex = 0) + const boost::array< edge_t, edge_count >& edge_list, + const boost::array< mas_test_weight_type, edge_count > weights_list, + const boost::array< mas_test_vertex_descriptor, vertices_count >& expected_vertex_order, + const boost::array< mas_test_weight_type, vertices_count >& expected_weights_when_visited, + const mas_test_vertex_descriptor start_vertex = 0) { const undirected_unweighted_graph g(edge_list.cbegin(), edge_list.cend(), vertices_count); mas_test_maxheap_type pq = create_mas_test_maxheap(g); - mas_text_visitor_type test_vis = mas_text_visitor_type(pq); + mas_test_visitor_type test_vis(pq); std::map< mas_test_edge_descriptor, mas_test_weight_type > weights_map; - std::size_t i = 0; - BGL_FORALL_EDGES(e, g, undirected_unweighted_graph) + for (const auto& e : boost::make_iterator_range(edges(g))) { weights_map[e] = weights_list[i]; ++i; } - boost::associative_property_map< std::map< mas_test_edge_descriptor, mas_test_weight_type > > - weights_boost_map(weights_map); - - boost::maximum_adjacency_search( - g, - boost::weight_map( - weights_boost_map) - .visitor(test_vis) - .max_priority_queue(pq) - .root_vertex(start_vertex) - ); - - BOOST_TEST_ALL_EQ( - test_vis.vertex_visit_order().begin(), - test_vis.vertex_visit_order().end(), - expected_vertex_order.cbegin(), - expected_vertex_order.cend() - ); - - BOOST_TEST_ALL_EQ( - test_vis.vertex_weights_when_visited().begin(), - test_vis.vertex_weights_when_visited().end(), - expected_weights_when_visited.cbegin(), - expected_weights_when_visited.cend() - ); + boost::associative_property_map< std::map< mas_test_edge_descriptor, mas_test_weight_type > > weights_boost_map(weights_map); + + boost::graph::maximum_adjacency_search(g, weights_boost_map, test_vis, start_vertex, pq); + + BOOST_TEST_ALL_EQ(test_vis.vertex_visit_order().begin(), + test_vis.vertex_visit_order().end(), + expected_vertex_order.cbegin(), + expected_vertex_order.cend()); + + BOOST_TEST_ALL_EQ(test_vis.vertex_weights_when_visited().begin(), + test_vis.vertex_weights_when_visited().end(), + expected_weights_when_visited.cbegin(), + expected_weights_when_visited.cend()); } -template +template < std::size_t edge_count, std::size_t vertices_count > void test_unweighted( - const boost::array& edge_list, - const boost::array& expected_vertex_order, - const boost::array& expected_weights_when_visited, - const mas_test_vertex_descriptor start_vertex = 0) + const boost::array< edge_t, edge_count >& edge_list, + const boost::array< mas_test_vertex_descriptor, vertices_count >& expected_vertex_order, + const boost::array< mas_test_weight_type, vertices_count >& expected_weights_when_visited, + const mas_test_vertex_descriptor start_vertex = 0) { - boost::array weights_list; - for (std::size_t i = 0; i < edge_count; i++) { - weights_list[i] = 1; - } - - test_weighted( - edge_list, - weights_list, - expected_vertex_order, - expected_weights_when_visited, - start_vertex); -} + boost::array< mas_test_weight_type, edge_count > weights_list; + for (std::size_t i = 0; i < edge_count; ++i) weights_list[i] = 1; -void test2_noweights() { - const std::size_t edge_count = 1; - const std::size_t vertices_count = 2; + test_weighted(edge_list, weights_list, expected_vertex_order, expected_weights_when_visited, start_vertex); +} +void test2_noweights() +{ + constexpr std::size_t edge_count = 1; + constexpr std::size_t vertices_count = 2; const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 } } }; - const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 0, 1 }; - const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 1 }; - - test_unweighted( - edge_list, - expected_vertex_order, - expected_weights_when_visited - ); + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count + 1, 1 }; + test_unweighted(edge_list, expected_vertex_order, expected_weights_when_visited); } -void test3_noweights() { - const std::size_t edge_count = 2; - const std::size_t vertices_count = 3; - +void test3_noweights() +{ + constexpr std::size_t edge_count = 2; + constexpr std::size_t vertices_count = 3; const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 1, 2 } } }; - const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 0, 1, 2 }; - const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 1, 1 }; + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count + 1, 1, 1 }; - test_unweighted( - edge_list, - expected_vertex_order, - expected_weights_when_visited - ); + test_unweighted(edge_list, expected_vertex_order, expected_weights_when_visited); } -void test4_noweights() { - const std::size_t edge_count = 3; - const std::size_t vertices_count = 3; - +void test4_noweights() +{ + constexpr std::size_t edge_count = 3; + constexpr std::size_t vertices_count = 3; const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 0, 2 }, { 1, 2 } } }; - const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 0, 1, 2 }; - const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 1, 2 }; + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count + 1, 1, 2 }; - test_unweighted( - edge_list, - expected_vertex_order, - expected_weights_when_visited - ); + test_unweighted(edge_list, expected_vertex_order, expected_weights_when_visited); } // The example graph from Matula (1993) -void test5_Matula1993() { - const std::size_t edge_count = 24; - const std::size_t vertices_count = 12; - - const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 0, 2 }, - { 0, 3 }, { 0, 9 }, { 1, 2 }, { 1, 4 }, { 1, 10 }, { 2, 5 }, { 2, 11 }, - { 3, 4 }, { 3, 5 }, { 3, 6 }, { 4, 5 }, { 4, 7 }, { 5, 8 }, { 6, 7 }, - { 6, 8 }, { 6, 9 }, { 7, 8 }, { 7, 10 }, { 8, 11 }, { 9, 10 }, - { 9, 11 }, { 10, 11 } } }; - +void test5_Matula1993() +{ + constexpr std::size_t edge_count = 24; + constexpr std::size_t vertices_count = 12; + const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 0, 2 }, { 0, 3 }, { 0, 9 }, { 1, 2 }, { 1, 4 }, { 1, 10 }, { 2, 5 }, { 2, 11 }, { 3, 4 }, { 3, 5 }, { 3, 6 }, { 4, 5 }, { 4, 7 }, { 5, 8 }, { 6, 7 }, { 6, 8 }, { 6, 9 }, { 7, 8 }, { 7, 10 }, { 8, 11 }, { 9, 10 }, { 9, 11 }, { 10, 11 } } }; const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 0, 1, 2, 10, 9, 11, 6, 3, 7, 4, 8, 5 }; - const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 1, 2, 1, 2, 3, 1, 2, 2, 3, 3, 4 }; + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count + 1, 1, 2, 1, 2, 3, 1, 2, 2, 3, 3, 4 }; - test_unweighted( - edge_list, - expected_vertex_order, - expected_weights_when_visited - ); + test_unweighted(edge_list, expected_vertex_order, expected_weights_when_visited); } // Testing with a different start vertex -void test6_noweights_start_vertex() { - const std::size_t edge_count = 2; - const std::size_t vertices_count = 3; - +void test6_noweights_start_vertex() +{ + constexpr std::size_t edge_count = 2; + constexpr std::size_t vertices_count = 3; const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 1, 2 } } }; - const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 1, 0, 2 }; - const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 1, 1 }; - - test_unweighted( - edge_list, - expected_vertex_order, - expected_weights_when_visited, - 1 - ); -} + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count + 1, 1, 1 }; -void test7_weights() { - const std::size_t edge_count = 2; - const std::size_t vertices_count = 3; + test_unweighted(edge_list, expected_vertex_order, expected_weights_when_visited, 1); +} +void test7_weights() +{ + constexpr std::size_t edge_count = 2; + constexpr std::size_t vertices_count = 3; const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 1, 2 } } }; - const boost::array< mas_test_weight_type, edge_count > weights_list = { 2, 6 }; - const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 0, 1, 2 }; - const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 2, 6 }; - - test_weighted( - edge_list, - weights_list, - expected_vertex_order, - expected_weights_when_visited - ); -} + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count + 1, 2, 6 }; -void test8_weights() { - const std::size_t edge_count = 3; - const std::size_t vertices_count = 3; + test_weighted(edge_list, weights_list, expected_vertex_order, expected_weights_when_visited); +} +void test8_weights() +{ + constexpr std::size_t edge_count = 3; + constexpr std::size_t vertices_count = 3; const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 0, 2 }, { 1, 2 } } }; + const boost::array< mas_test_weight_type, edge_count > weights_list = { 2, 6, 7 }; + const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 0, 2, 1 }; + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count + 1, 6, 9 }; + + test_weighted(edge_list, weights_list, expected_vertex_order, expected_weights_when_visited); +} +void test9_weights_start_vertex() +{ + constexpr std::size_t edge_count = 3; + constexpr std::size_t vertices_count = 3; + const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 0, 2 }, { 1, 2 } } }; const boost::array< mas_test_weight_type, edge_count > weights_list = { 2, 6, 7 }; + const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 1, 2, 0 }; + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count + 1, 7, 8 }; - const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 0, 2, 1 }; - const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 6, 9 }; - - test_weighted( - edge_list, - weights_list, - expected_vertex_order, - expected_weights_when_visited - ); + test_weighted(edge_list, weights_list, expected_vertex_order, expected_weights_when_visited, 1); } -void test9_weights_start_vertex() { - const std::size_t edge_count = 3; - const std::size_t vertices_count = 3; +using cv_distances_map_type = boost::shared_array_property_map< weight_type, boost::property_map< undirected_graph, boost::vertex_index_t >::const_type >; +using cv_index_in_heap_type = std::vector< vertex_descriptor >::size_type; +using cv_indices_map_type = boost::shared_array_property_map< cv_index_in_heap_type, boost::property_map< undirected_graph, boost::vertex_index_t >::const_type >; +using cv_maxheap_type = boost::d_ary_heap_indirect< vertex_descriptor, 4, cv_indices_map_type, cv_distances_map_type, std::greater< weight_type > >; - const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 0, 2 }, { 1, 2 } } }; +// Build the keyed max priority queue MAS runs on: reach counts plus heap positions. +cv_maxheap_type make_weighted_maxheap(const undirected_graph& g) +{ + auto id_map = get(boost::vertex_index, g); + auto distances_map = boost::make_shared_array_property_map(num_vertices(g), static_cast< weight_type >(0), id_map); + auto indices_map = boost::make_shared_array_property_map(num_vertices(g), static_cast< cv_index_in_heap_type >(-1), id_map); + return cv_maxheap_type(distances_map, indices_map); +} - const boost::array< mas_test_weight_type, edge_count > weights_list = { 2, 6, 7 }; +// Check invariants on a MAS run +void check_visit_order_invariants(const undirected_graph& g, const std::vector< vertex_descriptor >& order, const std::vector< weight_type >& reach) +{ + const std::size_t n = num_vertices(g); - const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 1, 2, 0 }; - const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 7, 8 }; - - test_weighted( - edge_list, - weights_list, - expected_vertex_order, - expected_weights_when_visited, - 1 - ); + // 1) the order is a permutation of all vertices + std::vector< vertex_descriptor > sorted = order; + std::sort(sorted.begin(), sorted.end()); + for (std::size_t i = 0; i < sorted.size(); ++i) BOOST_TEST_EQ(sorted[i], static_cast< vertex_descriptor >(i)); + + // 2) MAS adds n+1 to the start vertex key to force it first, so its recorded reach is n+1 + BOOST_TEST_EQ(reach[0], static_cast< weight_type >(n + 1)); + + // only the start vertex is visited before the loop + std::vector< bool > visited(n, false); + visited[order[0]] = true; + auto weight_map = get(boost::edge_weight, g); + + // 3) recompute each later vertex reach independently and check MAS agrees + for (std::size_t i = 1; i < order.size(); ++i) + { + const vertex_descriptor u = order[i]; + // sum the weights of u's edges that lead back into the visited set + weight_type expected = 0; + for (const auto& e : boost::make_iterator_range(out_edges(u, g))) + if (visited[target(e, g)]) expected += get(weight_map, e); + + BOOST_TEST_EQ(reach[i], expected); + visited[u] = true; + } } -#include +// Records every visitor event. +class recording_visitor : public boost::graph::default_mas_visitor +{ +public: + recording_visitor(std::size_t& initialize_count, std::size_t& examine_count, std::vector< vertex_descriptor >& start_order, std::vector< vertex_descriptor >& finish_order) + : initialize_count_(initialize_count), + examine_count_(examine_count), + start_order_(start_order), + finish_order_(finish_order) + {} + + void initialize_vertex(vertex_descriptor, const undirected_graph&) { ++initialize_count_; } + void start_vertex(vertex_descriptor u, const undirected_graph&) { start_order_.push_back(u); } + void examine_edge(edge_descriptor, const undirected_graph&) { ++examine_count_; } + void finish_vertex(vertex_descriptor u, const undirected_graph&) { finish_order_.push_back(u); } + +private: + std::size_t& initialize_count_; + std::size_t& examine_count_; + std::vector< vertex_descriptor >& start_order_; + std::vector< vertex_descriptor >& finish_order_; +}; -int main(int argc, char* argv[]) +// Cross validation against the max flow oracle +// for the last two visited vertices s (second last) and t (last), +// the reach count of t equals its weighted degree and equals the min cut between s and t. +void test_maxflow_crossvalidation() { - if (BOOST_TEST(argc == 2)) { - test_dir = argv[1]; - test0(); - test1(); - test2_noweights(); - test3_noweights(); - test4_noweights(); - test5_Matula1993(); - test6_noweights_start_vertex(); - test7_weights(); - test8_weights(); - test9_weights_start_vertex(); + // check every curated graph + for (const mas_sw_oracle::curated_graph& cg : mas_sw_oracle::curated_graphs()) + { + const undirected_graph& g = cg.graph; + BOOST_TEST(mas_sw_oracle::is_connected(g)); + + // run MAS, recording visit order and reach counts + cv_maxheap_type pq = make_weighted_maxheap(g); + mas_test_visitor< undirected_graph, cv_maxheap_type > vis(pq); + boost::graph::maximum_adjacency_search(g, get(boost::edge_weight, g), vis, *vertices(g).first, pq); + + const std::vector< vertex_descriptor >& order = vis.vertex_visit_order(); + const std::vector< weight_type >& reach = vis.vertex_weights_when_visited(); + BOOST_TEST_EQ(order.size(), num_vertices(g)); + + // take the last two visited vertices s and t + const std::size_t last = order.size() - 1; + const vertex_descriptor s = order[last - 1]; + const vertex_descriptor t = order[last]; + const weight_type reach_of_t = reach[last]; + + // t's reach must equal its weighted degree and the min cut between s and t + BOOST_TEST_EQ(reach_of_t, mas_sw_oracle::weighted_degree(g, t)); + BOOST_TEST_EQ(reach_of_t, mas_sw_oracle::undirected_min_cut(g, s, t)); + + // and the whole order must be a valid maximum adjacency ordering + check_visit_order_invariants(g, order, reach); + } +} + +// Every visitor event fires the expected number of times +void test_visitor_events() +{ + const undirected_graph g = mas_sw_oracle::make_weighted_graph(6, { { 0, 1, 2 }, { 1, 2, 3 }, { 2, 0, 1 }, { 2, 3, 4 }, { 3, 4, 2 }, { 4, 5, 1 }, { 5, 3, 3 } }); + + cv_maxheap_type pq = make_weighted_maxheap(g); + std::size_t initialize_count = 0; + std::size_t examine_count = 0; + std::vector< vertex_descriptor > start_order; + std::vector< vertex_descriptor > finish_order; + recording_visitor vis(initialize_count, examine_count, start_order, finish_order); + + boost::graph::maximum_adjacency_search(g, get(boost::edge_weight, g), vis, *vertices(g).first, pq); + + BOOST_TEST_EQ(initialize_count, static_cast< std::size_t >(num_vertices(g))); + BOOST_TEST_EQ(examine_count, static_cast< std::size_t >(2 * num_edges(g))); + BOOST_TEST_EQ(start_order.size(), static_cast< std::size_t >(num_vertices(g))); + BOOST_TEST_EQ(finish_order.size(), static_cast< std::size_t >(num_vertices(g))); + BOOST_TEST_ALL_EQ(start_order.begin(), + start_order.end(), + finish_order.begin(), + finish_order.end()); +} + +// Precondition violations throw. +void test_exceptions() +{ + // a graph with fewer than two vertices is rejected + { + undirected_graph too_small; + add_vertex(too_small); + auto weight_map = get(boost::edge_weight, too_small); + boost::graph::default_mas_visitor visitor; + BOOST_TEST_THROWS(boost::graph::maximum_adjacency_search(too_small, weight_map, visitor), boost::bad_graph); + } + + // a priority queue that is not empty is rejected + { + const undirected_graph g = mas_sw_oracle::make_weighted_graph(4, { { 0, 1, 1 }, { 1, 2, 1 }, { 2, 3, 1 } }); + cv_maxheap_type pq = make_weighted_maxheap(g); + pq.push(0); + auto weight_map = get(boost::edge_weight, g); + boost::graph::default_mas_visitor visitor; + const vertex_descriptor start = *vertices(g).first; + BOOST_TEST_THROWS(boost::graph::maximum_adjacency_search(g, weight_map, visitor, start, pq), std::invalid_argument); + } +} + +// A stateful visitor that owns its state as a plain data member. +class counting_visitor : public boost::graph::default_mas_visitor +{ +public: + std::size_t finish_count = 0; + void finish_vertex(vertex_descriptor, const undirected_graph&) { ++finish_count; } +}; + +// A visitor passed with std::ref keeps its state across the algorithm +void test_stateful_visitor_with_ref() +{ + const undirected_graph g = mas_sw_oracle::make_weighted_graph(4, { { 0, 1, 1 }, { 1, 2, 1 }, { 2, 3, 1 } }); + auto weight_map = get(boost::edge_weight, g); + + // std::ref makes the algorithm operate on the caller's visitor + { + cv_maxheap_type pq = make_weighted_maxheap(g); + counting_visitor vis; + boost::graph::maximum_adjacency_search(g, weight_map, std::ref(vis), *vertices(g).first, pq); + BOOST_TEST_EQ(vis.finish_count, static_cast< std::size_t >(num_vertices(g))); + } + + // by value the caller's visitor is left unchanged + { + cv_maxheap_type pq = make_weighted_maxheap(g); + counting_visitor vis; + boost::graph::maximum_adjacency_search(g, weight_map, vis, *vertices(g).first, pq); + BOOST_TEST_EQ(vis.finish_count, static_cast< std::size_t >(0)); } +} + +int main() +{ + test0(); + test1(); + test2_noweights(); + test3_noweights(); + test4_noweights(); + test5_Matula1993(); + test6_noweights_start_vertex(); + test7_weights(); + test8_weights(); + test9_weights_start_vertex(); + test_maxflow_crossvalidation(); + test_visitor_events(); + test_stateful_visitor_with_ref(); + test_exceptions(); return boost::report_errors(); } diff --git a/test/mas_test_old.cpp b/test/mas_test_old.cpp new file mode 100644 index 000000000..d05e1ee3e --- /dev/null +++ b/test/mas_test_old.cpp @@ -0,0 +1,757 @@ +// Copyright Fernando Vilas 2012. +// Based on stoer_wagner_test.cpp by Daniel Trebbien. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or the copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// This test exercises the deprecated interfaces on purpose (the named +// parameter and assignment-map overloads, and the boost:: visitor aliases +// mas_visitor / make_mas_visitor / default_mas_visitor that now live in +// boost::graph), so silence the deprecation warnings. +#define BOOST_ALLOW_DEPRECATED_SYMBOLS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mas_sw_maxflow_oracle.hpp" + +using mas_sw_oracle::undirected_graph; +using mas_sw_oracle::weight_map_type; +using mas_sw_oracle::weight_type; +using mas_sw_oracle::vertex_descriptor; +using mas_sw_oracle::edge_descriptor; + +typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS > + undirected_unweighted_graph; + +std::string test_dir; + +struct edge_t +{ + unsigned long first; + unsigned long second; +}; + +template < typename Graph, typename KeyedUpdatablePriorityQueue > +class mas_test_visitor : public boost::default_mas_visitor +{ +public: + typedef typename boost::graph_traits< Graph >::vertex_descriptor + vertex_descriptor; + typedef typename KeyedUpdatablePriorityQueue::key_type weight_type; + + explicit mas_test_visitor(KeyedUpdatablePriorityQueue& pq) + : m_pq_(pq), + vertex_visit_order_(boost::make_shared< std::vector< vertex_descriptor > >()), + vertex_weights_when_visited_(boost::make_shared< std::vector< weight_type > >()) + {} + + void clear() + { + vertex_visit_order_->clear(); + vertex_weights_when_visited_->clear(); + } + + void start_vertex(vertex_descriptor u, const Graph&) + { + vertex_visit_order_->push_back(u); + + const weight_type u_weight = get(m_pq_.keys(), u); + vertex_weights_when_visited_->push_back(u_weight); + } + + const std::vector& vertex_visit_order() const { + return *vertex_visit_order_; + } + + const std::vector& vertex_weights_when_visited() const { + return *vertex_weights_when_visited_; + } + +private: + const KeyedUpdatablePriorityQueue& m_pq_; + boost::shared_ptr< std::vector< vertex_descriptor > > vertex_visit_order_; + boost::shared_ptr< std::vector< weight_type > > vertex_weights_when_visited_; +}; + +// the example from Stoer & Wagner (1997) +// Check various implementations of the ArgPack where +// the weights are provided in it, and one case where +// they are not. +void test0() +{ + typedef boost::graph_traits< undirected_graph >::vertex_descriptor + vertex_descriptor; + typedef boost::graph_traits< undirected_graph >::edge_descriptor + edge_descriptor; + + boost::array< edge_t, 12 > edge_list = { { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 0, 4 }, { 1, 4 }, { 1, 5 }, + { 2, 6 }, { 3, 6 }, { 3, 7 }, { 4, 5 }, { 5, 6 }, { 6, 7 } } }; + const boost::array ws = { 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 1, 3 }; + const std::size_t vertices_count = 8; + + undirected_graph g(edge_list.cbegin(), edge_list.cend(), ws.cbegin(), vertices_count, ws.size()); + + weight_map_type weights = get(boost::edge_weight, g); + + std::map< vertex_descriptor, vertex_descriptor > assignment; + boost::associative_property_map< + std::map< vertex_descriptor, vertex_descriptor > > + assignments(assignment); + + typedef boost::shared_array_property_map< weight_type, + boost::property_map< undirected_graph, + boost::vertex_index_t >::const_type > + distances_type; + distances_type distances = boost::make_shared_array_property_map( + num_vertices(g), weight_type(0), get(boost::vertex_index, g)); + typedef std::vector< vertex_descriptor >::size_type index_in_heap_type; + typedef boost::shared_array_property_map< index_in_heap_type, + boost::property_map< undirected_graph, + boost::vertex_index_t >::const_type > + indicesInHeap_type; + indicesInHeap_type indicesInHeap = boost::make_shared_array_property_map( + num_vertices(g), index_in_heap_type(-1), get(boost::vertex_index, g)); + boost::d_ary_heap_indirect< vertex_descriptor, 22, indicesInHeap_type, + distances_type, std::greater< weight_type > > + pq(distances, indicesInHeap); + + mas_test_visitor< undirected_graph, + boost::d_ary_heap_indirect< vertex_descriptor, 22, indicesInHeap_type, + distances_type, std::greater< weight_type > > > + test_vis(pq); + + boost::maximum_adjacency_search(g, + boost::weight_map(weights) + .visitor(test_vis) + .root_vertex(*vertices(g).first) + .vertex_assignment_map(assignments) + .max_priority_queue(pq)); + + const boost::array< vertex_descriptor, vertices_count > expected_vertex_order1 = { 0, 4, 1, 5, 2, 3, 6, 7 }; + const boost::array< weight_type, vertices_count > expected_weights_when_visited1 = { 9, 3, 4, 5, 3, 4, 5, 5 }; + + BOOST_TEST_ALL_EQ( + test_vis.vertex_visit_order().begin(), + test_vis.vertex_visit_order().end(), + expected_vertex_order1.cbegin(), + expected_vertex_order1.cend() + ); + + BOOST_TEST_ALL_EQ( + test_vis.vertex_weights_when_visited().begin(), + test_vis.vertex_weights_when_visited().end(), + expected_weights_when_visited1.cbegin(), + expected_weights_when_visited1.cend() + ); + + test_vis.clear(); + + boost::maximum_adjacency_search(g, + boost::weight_map(weights) + .visitor(test_vis) + .root_vertex(*vertices(g).first) + .max_priority_queue(pq)); + + BOOST_TEST_ALL_EQ( + test_vis.vertex_visit_order().begin(), + test_vis.vertex_visit_order().end(), + expected_vertex_order1.cbegin(), + expected_vertex_order1.cend() + ); + + BOOST_TEST_ALL_EQ( + test_vis.vertex_weights_when_visited().begin(), + test_vis.vertex_weights_when_visited().end(), + expected_weights_when_visited1.cbegin(), + expected_weights_when_visited1.cend() + ); + + test_vis.clear(); + + boost::maximum_adjacency_search( + g, boost::weight_map(weights).visitor(test_vis).max_priority_queue(pq)); + + BOOST_TEST_ALL_EQ( + test_vis.vertex_visit_order().begin(), + test_vis.vertex_visit_order().end(), + expected_vertex_order1.cbegin(), + expected_vertex_order1.cend() + ); + + BOOST_TEST_ALL_EQ( + test_vis.vertex_weights_when_visited().begin(), + test_vis.vertex_weights_when_visited().end(), + expected_weights_when_visited1.cbegin(), + expected_weights_when_visited1.cend() + ); + + test_vis.clear(); + + boost::maximum_adjacency_search(g, + boost::weight_map(weights).visitor( + boost::make_mas_visitor(boost::null_visitor()))); + + boost::maximum_adjacency_search(g, boost::weight_map(weights)); + + boost::maximum_adjacency_search(g, boost::root_vertex(*vertices(g).first)); + + test_vis.clear(); + boost::maximum_adjacency_search(g, + boost::weight_map( + boost::make_constant_property< edge_descriptor >(weight_type(1))) + .visitor(test_vis) + .max_priority_queue(pq)); + + const boost::array< vertex_descriptor, vertices_count > expected_vertex_order2 = { 0, 1, 4, 5, 2, 6, 3, 7 }; + const boost::array< weight_type, vertices_count > expected_weights_when_visited2 = { 9, 1, 2, 2, 1, 2, 2, 2 }; + + BOOST_TEST_ALL_EQ( + test_vis.vertex_visit_order().begin(), + test_vis.vertex_visit_order().end(), + expected_vertex_order2.cbegin(), + expected_vertex_order2.cend() + ); + + BOOST_TEST_ALL_EQ( + test_vis.vertex_weights_when_visited().begin(), + test_vis.vertex_weights_when_visited().end(), + expected_weights_when_visited2.cbegin(), + expected_weights_when_visited2.cend() + ); +} + +// Check the unweighted case +// with and without providing a weight_map +void test1() +{ + typedef boost::graph_traits< + undirected_unweighted_graph >::vertex_descriptor vertex_descriptor; + typedef boost::graph_traits< undirected_unweighted_graph >::edge_descriptor + edge_descriptor; + + boost::array< edge_t, 12 > edge_list = { { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 0, 4 }, { 1, 4 }, { 1, 5 }, + { 2, 6 }, { 3, 6 }, { 3, 7 }, { 4, 5 }, { 5, 6 }, { 6, 7 } } }; + const std::size_t vertices_count = 8; + + undirected_unweighted_graph g(edge_list.cbegin(), edge_list.cend(), vertices_count); + + std::map< vertex_descriptor, vertex_descriptor > assignment; + boost::associative_property_map< + std::map< vertex_descriptor, vertex_descriptor > > + assignments(assignment); + + typedef unsigned weight_type; + typedef boost::shared_array_property_map< weight_type, + boost::property_map< undirected_graph, + boost::vertex_index_t >::const_type > + distances_type; + distances_type distances = boost::make_shared_array_property_map( + num_vertices(g), weight_type(0), get(boost::vertex_index, g)); + typedef std::vector< vertex_descriptor >::size_type index_in_heap_type; + typedef boost::shared_array_property_map< index_in_heap_type, + boost::property_map< undirected_graph, + boost::vertex_index_t >::const_type > + indicesInHeap_type; + indicesInHeap_type indicesInHeap = boost::make_shared_array_property_map( + num_vertices(g), index_in_heap_type(-1), get(boost::vertex_index, g)); + boost::d_ary_heap_indirect< vertex_descriptor, 22, indicesInHeap_type, + distances_type, std::greater< weight_type > > + pq(distances, indicesInHeap); + + mas_test_visitor< undirected_unweighted_graph, + boost::d_ary_heap_indirect< vertex_descriptor, 22, indicesInHeap_type, + distances_type, std::greater< weight_type > > > + test_vis(pq); + + boost::maximum_adjacency_search(g, + boost::weight_map( + boost::make_constant_property< edge_descriptor >(weight_type(1))) + .visitor(test_vis) + .max_priority_queue(pq)); + + const boost::array< vertex_descriptor, vertices_count > expected_vertex_order1 = { 0, 1, 4, 5, 2, 6, 3, 7 }; + const boost::array< weight_type, vertices_count > expected_weights_when_visited1 = { 9, 1, 2, 2, 1, 2, 2, 2 }; + + BOOST_TEST_ALL_EQ( + test_vis.vertex_visit_order().begin(), + test_vis.vertex_visit_order().end(), + expected_vertex_order1.cbegin(), + expected_vertex_order1.cend() + ); + + BOOST_TEST_ALL_EQ( + test_vis.vertex_weights_when_visited().begin(), + test_vis.vertex_weights_when_visited().end(), + expected_weights_when_visited1.cbegin(), + expected_weights_when_visited1.cend() + ); + + test_vis.clear(); + + const boost::array ws = { 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 1, 3 }; + std::map< edge_descriptor, weight_type > wm; + + weight_type i = 0; + BGL_FORALL_EDGES(e, g, undirected_unweighted_graph) + { + wm[e] = ws[i]; + ++i; + } + boost::associative_property_map< std::map< edge_descriptor, weight_type > > + ws_map(wm); + + boost::maximum_adjacency_search( + g, boost::weight_map(ws_map).visitor(test_vis).max_priority_queue(pq)); + + const boost::array< vertex_descriptor, vertices_count > expected_vertex_order2 = { 0, 4, 1, 5, 2, 3, 6, 7 }; + const boost::array< weight_type, vertices_count > expected_weights_when_visited2 = { 9, 3, 4, 5, 3, 4, 5, 5 }; + + BOOST_TEST_ALL_EQ( + test_vis.vertex_visit_order().begin(), + test_vis.vertex_visit_order().end(), + expected_vertex_order2.cbegin(), + expected_vertex_order2.cend() + ); + + BOOST_TEST_ALL_EQ( + test_vis.vertex_weights_when_visited().begin(), + test_vis.vertex_weights_when_visited().end(), + expected_weights_when_visited2.cbegin(), + expected_weights_when_visited2.cend() + ); +} + +typedef boost::graph_traits< undirected_unweighted_graph >::vertex_descriptor mas_test_vertex_descriptor; +typedef boost::graph_traits< undirected_unweighted_graph >::edge_descriptor mas_test_edge_descriptor; + +typedef std::size_t mas_test_weight_type; // weight corresponds to the priority value in the priority queue. +typedef boost::shared_array_property_map< mas_test_weight_type, boost::property_map< undirected_graph, boost::vertex_index_t >::const_type > mas_test_distances_type; +typedef std::vector< mas_test_vertex_descriptor >::size_type mas_test_index_in_heap_type; +typedef boost::shared_array_property_map< mas_test_index_in_heap_type, boost::property_map< undirected_graph, boost::vertex_index_t >::const_type > mas_test_indicesInHeap_type; +const std::size_t mas_test_arity = 4; +typedef boost::d_ary_heap_indirect< mas_test_vertex_descriptor, mas_test_arity, mas_test_indicesInHeap_type, mas_test_distances_type, std::greater< mas_test_weight_type > > mas_test_maxheap_type; +typedef mas_test_visitor< undirected_unweighted_graph, mas_test_maxheap_type> mas_text_visitor_type; + +template +mas_test_maxheap_type create_mas_test_maxheap(const Graph& g) { + mas_test_distances_type distances = boost::make_shared_array_property_map( + num_vertices(g), mas_test_weight_type(0), get(boost::vertex_index, g)); + + mas_test_indicesInHeap_type indicesInHeap = boost::make_shared_array_property_map( + num_vertices(g), mas_test_index_in_heap_type(-1), get(boost::vertex_index, g)); + + return mas_test_maxheap_type(distances, indicesInHeap); +} + +template +void test_weighted( + const boost::array& edge_list, + const boost::array weights_list, + const boost::array& expected_vertex_order, + const boost::array& expected_weights_when_visited, + const mas_test_vertex_descriptor start_vertex = 0) +{ + const undirected_unweighted_graph g(edge_list.cbegin(), edge_list.cend(), vertices_count); + + mas_test_maxheap_type pq = create_mas_test_maxheap(g); + mas_text_visitor_type test_vis = mas_text_visitor_type(pq); + + std::map< mas_test_edge_descriptor, mas_test_weight_type > weights_map; + + std::size_t i = 0; + BGL_FORALL_EDGES(e, g, undirected_unweighted_graph) + { + weights_map[e] = weights_list[i]; + ++i; + } + boost::associative_property_map< std::map< mas_test_edge_descriptor, mas_test_weight_type > > + weights_boost_map(weights_map); + + boost::maximum_adjacency_search( + g, + boost::weight_map( + weights_boost_map) + .visitor(test_vis) + .max_priority_queue(pq) + .root_vertex(start_vertex) + ); + + BOOST_TEST_ALL_EQ( + test_vis.vertex_visit_order().begin(), + test_vis.vertex_visit_order().end(), + expected_vertex_order.cbegin(), + expected_vertex_order.cend() + ); + + BOOST_TEST_ALL_EQ( + test_vis.vertex_weights_when_visited().begin(), + test_vis.vertex_weights_when_visited().end(), + expected_weights_when_visited.cbegin(), + expected_weights_when_visited.cend() + ); +} + +template +void test_unweighted( + const boost::array& edge_list, + const boost::array& expected_vertex_order, + const boost::array& expected_weights_when_visited, + const mas_test_vertex_descriptor start_vertex = 0) +{ + boost::array weights_list; + for (std::size_t i = 0; i < edge_count; i++) { + weights_list[i] = 1; + } + + test_weighted( + edge_list, + weights_list, + expected_vertex_order, + expected_weights_when_visited, + start_vertex); +} + +void test2_noweights() { + const std::size_t edge_count = 1; + const std::size_t vertices_count = 2; + + const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 } } }; + + const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 0, 1 }; + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 1 }; + + test_unweighted( + edge_list, + expected_vertex_order, + expected_weights_when_visited + ); +} + +void test3_noweights() { + const std::size_t edge_count = 2; + const std::size_t vertices_count = 3; + + const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 1, 2 } } }; + + const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 0, 1, 2 }; + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 1, 1 }; + + test_unweighted( + edge_list, + expected_vertex_order, + expected_weights_when_visited + ); +} + +void test4_noweights() { + const std::size_t edge_count = 3; + const std::size_t vertices_count = 3; + + const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 0, 2 }, { 1, 2 } } }; + + const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 0, 1, 2 }; + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 1, 2 }; + + test_unweighted( + edge_list, + expected_vertex_order, + expected_weights_when_visited + ); +} + +// The example graph from Matula (1993) +void test5_Matula1993() { + const std::size_t edge_count = 24; + const std::size_t vertices_count = 12; + + const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 0, 2 }, + { 0, 3 }, { 0, 9 }, { 1, 2 }, { 1, 4 }, { 1, 10 }, { 2, 5 }, { 2, 11 }, + { 3, 4 }, { 3, 5 }, { 3, 6 }, { 4, 5 }, { 4, 7 }, { 5, 8 }, { 6, 7 }, + { 6, 8 }, { 6, 9 }, { 7, 8 }, { 7, 10 }, { 8, 11 }, { 9, 10 }, + { 9, 11 }, { 10, 11 } } }; + + const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 0, 1, 2, 10, 9, 11, 6, 3, 7, 4, 8, 5 }; + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 1, 2, 1, 2, 3, 1, 2, 2, 3, 3, 4 }; + + test_unweighted( + edge_list, + expected_vertex_order, + expected_weights_when_visited + ); +} + +// Testing with a different start vertex +void test6_noweights_start_vertex() { + const std::size_t edge_count = 2; + const std::size_t vertices_count = 3; + + const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 1, 2 } } }; + + const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 1, 0, 2 }; + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 1, 1 }; + + test_unweighted( + edge_list, + expected_vertex_order, + expected_weights_when_visited, + 1 + ); +} + +void test7_weights() { + const std::size_t edge_count = 2; + const std::size_t vertices_count = 3; + + const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 1, 2 } } }; + + const boost::array< mas_test_weight_type, edge_count > weights_list = { 2, 6 }; + + const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 0, 1, 2 }; + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 2, 6 }; + + test_weighted( + edge_list, + weights_list, + expected_vertex_order, + expected_weights_when_visited + ); +} + +void test8_weights() { + const std::size_t edge_count = 3; + const std::size_t vertices_count = 3; + + const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 0, 2 }, { 1, 2 } } }; + + const boost::array< mas_test_weight_type, edge_count > weights_list = { 2, 6, 7 }; + + const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 0, 2, 1 }; + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 6, 9 }; + + test_weighted( + edge_list, + weights_list, + expected_vertex_order, + expected_weights_when_visited + ); +} + +void test9_weights_start_vertex() { + const std::size_t edge_count = 3; + const std::size_t vertices_count = 3; + + const boost::array< edge_t, edge_count > edge_list = { { { 0, 1 }, { 0, 2 }, { 1, 2 } } }; + + const boost::array< mas_test_weight_type, edge_count > weights_list = { 2, 6, 7 }; + + const boost::array< mas_test_vertex_descriptor, vertices_count > expected_vertex_order = { 1, 2, 0 }; + const boost::array< mas_test_weight_type, vertices_count > expected_weights_when_visited = { vertices_count+1, 7, 8 }; + + test_weighted( + edge_list, + weights_list, + expected_vertex_order, + expected_weights_when_visited, + 1 + ); +} + +using cv_distances_map_type = boost::shared_array_property_map< weight_type, + boost::property_map< undirected_graph, boost::vertex_index_t >::const_type >; +using cv_index_in_heap_type = std::vector< vertex_descriptor >::size_type; +using cv_indices_map_type = boost::shared_array_property_map< cv_index_in_heap_type, + boost::property_map< undirected_graph, boost::vertex_index_t >::const_type >; +using cv_maxheap_type = boost::d_ary_heap_indirect< vertex_descriptor, 4, cv_indices_map_type, + cv_distances_map_type, std::greater< weight_type > >; + +// Build the keyed max priority queue MAS runs on: reach counts plus heap positions. +cv_maxheap_type make_weighted_maxheap(const undirected_graph& g) +{ + auto distances_map = boost::make_shared_array_property_map(num_vertices(g), weight_type(0), get(boost::vertex_index, g)); + auto indices_map = boost::make_shared_array_property_map(num_vertices(g), cv_index_in_heap_type(-1), get(boost::vertex_index, g)); + return cv_maxheap_type(distances_map, indices_map); +} + +// Check invariants on a MAS run +void check_visit_order_invariants( + const undirected_graph& g, + const std::vector< vertex_descriptor >& order, + const std::vector< weight_type >& reach) +{ + const std::size_t n = num_vertices(g); + + // 1) the order is a permutation of all vertices + std::vector< vertex_descriptor > sorted = order; + std::sort(sorted.begin(), sorted.end()); + for (std::size_t i = 0; i < sorted.size(); ++i) + BOOST_TEST_EQ(sorted[i], static_cast< vertex_descriptor >(i)); + + // 2) MAS adds n+1 to the start vertex key to force it first, so its recorded reach is n+1 + BOOST_TEST_EQ(reach[0], static_cast< weight_type >(n + 1)); + + // only the start vertex is visited before the loop + std::vector< bool > visited(n, false); + visited[order[0]] = true; + auto weight_map = get(boost::edge_weight, g); + + // 3) recompute each later vertex reach independently and check MAS agrees + for (std::size_t i = 1; i < order.size(); ++i) + { + const vertex_descriptor u = order[i]; + // sum the weights of u's edges that lead back into the visited set + weight_type expected = 0; + boost::graph_traits< undirected_graph >::out_edge_iterator oi, oi_end; + for (boost::tie(oi, oi_end) = out_edges(u, g); oi != oi_end; ++oi) + if (visited[target(*oi, g)]) + expected += get(weight_map, *oi); + + BOOST_TEST_EQ(reach[i], expected); + visited[u] = true; + } +} + +// Records every visitor event. +class recording_visitor : public boost::default_mas_visitor +{ +public: + recording_visitor( + std::size_t& initialize_count, + std::size_t& examine_count, + std::vector< vertex_descriptor >& start_order, + std::vector< vertex_descriptor >& finish_order + ) + : + initialize_count_(initialize_count), + examine_count_(examine_count), + start_order_(start_order), + finish_order_(finish_order) + {} + + void initialize_vertex(vertex_descriptor, const undirected_graph&) { ++initialize_count_; } + void start_vertex(vertex_descriptor u, const undirected_graph&) { start_order_.push_back(u); } + void examine_edge(edge_descriptor, const undirected_graph&) { ++examine_count_; } + void finish_vertex(vertex_descriptor u, const undirected_graph&) { finish_order_.push_back(u); } + +private: + std::size_t& initialize_count_; + std::size_t& examine_count_; + std::vector< vertex_descriptor >& start_order_; + std::vector< vertex_descriptor >& finish_order_; +}; + +// Cross-validation against the max-flow oracle +// for the last two visited vertices s (second-last) and t (last), +// the reach count of t equals its weighted degree and equals the min s-t cut. +void test_maxflow_crossvalidation() +{ + // check every curated graph + for (const mas_sw_oracle::curated_graph& cg : mas_sw_oracle::curated_graphs()) + { + const undirected_graph& g = cg.graph; + BOOST_TEST(mas_sw_oracle::is_connected(g)); + + // run MAS, recording visit order and reach counts + cv_maxheap_type pq = make_weighted_maxheap(g); + mas_test_visitor< undirected_graph, cv_maxheap_type > vis(pq); + boost::maximum_adjacency_search(g, boost::weight_map(get(boost::edge_weight, g)).visitor(vis).max_priority_queue(pq)); + + const std::vector< vertex_descriptor >& order = vis.vertex_visit_order(); + const std::vector< weight_type >& reach = vis.vertex_weights_when_visited(); + BOOST_TEST_EQ(order.size(), num_vertices(g)); + + // take the last two visited vertices s and t + const std::size_t last = order.size() - 1; + const vertex_descriptor s = order[last - 1]; + const vertex_descriptor t = order[last]; + const weight_type reach_of_t = reach[last]; + + // t's reach must equal its weighted degree and the min s-t cut + BOOST_TEST_EQ(reach_of_t, mas_sw_oracle::weighted_degree(g, t)); + BOOST_TEST_EQ(reach_of_t, mas_sw_oracle::undirected_min_cut(g, s, t)); + + // and the whole order must be a valid maximum adjacency ordering + check_visit_order_invariants(g, order, reach); + } +} + +// Every visitor event fires the expected number of times +void test_visitor_events() +{ + const undirected_graph g = mas_sw_oracle::make_weighted_graph(6, { { 0, 1, 2 }, { 1, 2, 3 }, { 2, 0, 1 }, { 2, 3, 4 }, { 3, 4, 2 }, { 4, 5, 1 }, { 5, 3, 3 } }); + + cv_maxheap_type pq = make_weighted_maxheap(g); + std::size_t initialize_count = 0; + std::size_t examine_count = 0; + std::vector< vertex_descriptor > start_order; + std::vector< vertex_descriptor > finish_order; + recording_visitor vis(initialize_count, examine_count, start_order, finish_order); + + boost::maximum_adjacency_search(g, boost::weight_map(get(boost::edge_weight, g)).visitor(vis).max_priority_queue(pq)); + + BOOST_TEST_EQ(initialize_count, static_cast< std::size_t >(num_vertices(g))); + BOOST_TEST_EQ(examine_count, static_cast< std::size_t >(2 * num_edges(g))); + BOOST_TEST_EQ(start_order.size(), static_cast< std::size_t >(num_vertices(g))); + BOOST_TEST_EQ(finish_order.size(), static_cast< std::size_t >(num_vertices(g))); + BOOST_TEST_ALL_EQ(start_order.begin(), start_order.end(), finish_order.begin(), finish_order.end()); +} + +// Precondition violations throw. +void test_exceptions() +{ + // a graph with fewer than two vertices is rejected + undirected_graph too_small; + add_vertex(too_small); + BOOST_TEST_THROWS(boost::maximum_adjacency_search(too_small, boost::weight_map(get(boost::edge_weight, too_small))), boost::bad_graph); + + // a non-empty priority queue is rejected + const undirected_graph g = mas_sw_oracle::make_weighted_graph(4, { { 0, 1, 1 }, { 1, 2, 1 }, { 2, 3, 1 } }); + cv_maxheap_type pq = make_weighted_maxheap(g); + pq.push(0); + BOOST_TEST_THROWS(boost::maximum_adjacency_search(g, boost::weight_map(get(boost::edge_weight, g)).max_priority_queue(pq)), std::invalid_argument); +} + +#include + +int main(int argc, char* argv[]) +{ + if (BOOST_TEST(argc == 2)) { + test_dir = argv[1]; + test0(); + test1(); + test2_noweights(); + test3_noweights(); + test4_noweights(); + test5_Matula1993(); + test6_noweights_start_vertex(); + test7_weights(); + test8_weights(); + test9_weights_start_vertex(); + test_maxflow_crossvalidation(); + test_visitor_events(); + test_exceptions(); + } + return boost::report_errors(); +} diff --git a/test/matching_test.cpp b/test/matching_test.cpp index 275ad3460..c4b566203 100644 --- a/test/matching_test.cpp +++ b/test/matching_test.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -309,7 +308,7 @@ void matching_test(std::size_t num_v, const std::string& graph_name) vertex_index_installer< Graph >::install(j); typedef boost::mt19937 base_generator_type; - base_generator_type generator(static_cast< unsigned int >(std::time(0))); + base_generator_type generator(42); boost::uniform_int<> distribution(0, double_num_v - 1); boost::variate_generator< base_generator_type&, boost::uniform_int<> > rand_num(generator, distribution); diff --git a/test/max_flow_test.cpp b/test/max_flow_test.cpp index 14e5d77d0..014067ab2 100644 --- a/test/max_flow_test.cpp +++ b/test/max_flow_test.cpp @@ -77,14 +77,12 @@ int main(int argc, char* argv[]) graph_traits< Graph >::vertices_size_type n_verts = 100; graph_traits< Graph >::edges_size_type n_edges = 1000; - std::size_t seed = 1; + std::size_t seed = 42; if (argc > 1) n_verts = lexical_cast< std::size_t >(argv[1]); if (argc > 2) n_edges = lexical_cast< std::size_t >(argv[2]); - if (argc > 3) - seed = lexical_cast< std::size_t >(argv[3]); Graph g; const int cap_low = 1; diff --git a/test/mcgregor_subgraphs_test.cpp b/test/mcgregor_subgraphs_test.cpp index 5409dbf15..089b6b902 100644 --- a/test/mcgregor_subgraphs_test.cpp +++ b/test/mcgregor_subgraphs_test.cpp @@ -12,15 +12,14 @@ #include #include #include -#include #include #include +#include #include #include #include #include -#include #include #include #include @@ -103,8 +102,7 @@ template < typename Graph > struct test_callback EdgeNameMap ename_map2 = get(boost::edge_name, subgraph2); // Verify that subgraph1 matches the supplied common subgraph - BGL_FORALL_VERTICES_T(vertex1, subgraph1, MembershipFilteredGraph) - { + for (auto vertex1 : boost::make_iterator_range(vertices(subgraph1))) { Vertex vertex_common = vertex(get(vindex_map1, vertex1), m_common_subgraph); @@ -117,16 +115,13 @@ template < typename Graph > struct test_callback // Keep looking return (true); } - - BGL_FORALL_VERTICES_T(vertex1_2, subgraph1, MembershipFilteredGraph) - { - + + for (auto vertex1_2 : boost::make_iterator_range(vertices(subgraph1))) { Vertex vertex_common2 = vertex(get(vindex_map1, vertex1_2), m_common_subgraph); EdgeInfo edge_common = edge(vertex_common, vertex_common2, m_common_subgraph); EdgeInfo edge1 = edge(vertex1, vertex1_2, subgraph1); - if ((edge_common.second != edge1.second) || ((edge_common.second && edge1.second) && (get(ename_map_common, edge_common.first) @@ -137,13 +132,10 @@ template < typename Graph > struct test_callback return (true); } } - - } // BGL_FORALL_VERTICES_T (subgraph1) + } // Verify that subgraph2 matches the supplied common subgraph - BGL_FORALL_VERTICES_T(vertex2, subgraph2, MembershipFilteredGraph) - { - + for (auto vertex2 : boost::make_iterator_range(vertices(subgraph2))) { Vertex vertex_common = vertex(get(vindex_map2, vertex2), m_common_subgraph); @@ -155,11 +147,9 @@ template < typename Graph > struct test_callback // Keep looking return (true); } - - BGL_FORALL_VERTICES_T(vertex2_2, subgraph2, MembershipFilteredGraph) - { - - Vertex vertex_common2 + + for (auto vertex2_2 : boost::make_iterator_range(vertices(subgraph2))) { + Vertex vertex_common2 = vertex(get(vindex_map2, vertex2_2), m_common_subgraph); EdgeInfo edge_common = edge(vertex_common, vertex_common2, m_common_subgraph); @@ -170,13 +160,11 @@ template < typename Graph > struct test_callback && (get(ename_map_common, edge_common.first) != get(ename_map2, edge2.first)))) { - // Keep looking return (true); } } - - } // BGL_FORALL_VERTICES_T (subgraph2) + } // Check isomorphism just to be thorough if (verify_isomorphism(subgraph1, subgraph2, correspondence_map_1_to_2)) @@ -224,9 +212,7 @@ template < typename Graph > struct simple_callback std::stringstream subgraph_string; - BGL_FORALL_VERTICES_T(vertex1, m_graph1, Graph) - { - + for (auto vertex1 : boost::make_iterator_range(vertices(m_graph1))) { Vertex vertex2 = get(correspondence_map_1_to_2, vertex1); if (vertex2 != boost::graph_traits< Graph >::null_vertex()) @@ -284,15 +270,14 @@ void add_random_vertices(Graph& graph, RandomNumberGenerator& generator, { continue; } - - BGL_FORALL_OUTEDGES_T(source_vertex, edge, graph, Graph) - { + + for (auto edge : boost::make_iterator_range(out_edges(source_vertex, graph))) { if (target(edge, graph) == target_vertex) { continue; } } - + put(ename_map, add_edge(source_vertex, target_vertex, graph).first, generator()); @@ -312,7 +297,7 @@ int main(int argc, char* argv[]) { int vertices_to_create = 10; int max_edges_per_vertex = 2; - std::size_t random_seed = std::time(0); + std::size_t random_seed = 42; if (argc > 1) { @@ -329,11 +314,6 @@ int main(int argc, char* argv[]) output_graphs = boost::lexical_cast< bool >(argv[3]); } - if (argc > 4) - { - random_seed = boost::lexical_cast< std::size_t >(argv[4]); - } - boost::minstd_rand generator(random_seed); // Using a vecS graph here so that we don't have to mess around with @@ -365,12 +345,8 @@ int main(int argc, char* argv[]) put(vname_map_common, add_vertex(common_subgraph), generator()); } - BGL_FORALL_VERTICES(source_vertex, common_subgraph, Graph) - { - - BGL_FORALL_VERTICES(target_vertex, common_subgraph, Graph) - { - + for (auto source_vertex : boost::make_iterator_range(vertices(common_subgraph))) { + for (auto target_vertex : boost::make_iterator_range(vertices(common_subgraph))) { if (source_vertex != target_vertex) { put(ename_map_common, @@ -380,7 +356,7 @@ int main(int argc, char* argv[]) } } } - + boost::randomize_property< boost::vertex_name_t >( common_subgraph, generator); boost::randomize_property< boost::edge_name_t >(common_subgraph, generator); diff --git a/test/metric_tsp_approx.cpp b/test/metric_tsp_approx.cpp index fda070729..9d7b03d52 100644 --- a/test/metric_tsp_approx.cpp +++ b/test/metric_tsp_approx.cpp @@ -7,14 +7,12 @@ // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= +#include #include #include -#include #include -#include -#include -#include +#include #include #include #include @@ -24,9 +22,6 @@ #include #include -// TODO: Integrate this into the test system a little better. We need to run -// the test with some kind of input file. - template < typename PointType > struct cmpPnt { bool operator()(const boost::simple_point< PointType >& l, @@ -90,7 +85,7 @@ void testScalability(unsigned numpts) typedef set< simple_point< double >, cmpPnt< double > > PointSet; typedef vector< Vertex > Container; - boost::mt19937 rng(std::time(0)); + boost::mt19937 rng(42); uniform_real<> range(0.01, (numpts * 2)); variate_generator< boost::mt19937&, uniform_real<> > pnt_gen(rng, range); @@ -174,23 +169,7 @@ template < typename PositionVec > void checkAdjList(PositionVec v) c.clear(); } -static void usage() -{ - using namespace std; - cerr << "To run this program properly please place a " - << "file called graph.txt" << endl - << "into the current working directory." << endl - << "Each line of this file should be a coordinate specifying the" - << endl - << "location of a vertex" << endl - << "For example: " << endl - << "1,2" << endl - << "20,4" << endl - << "15,7" << endl - << endl; -} - -int main(int argc, char* argv[]) +int main() { using namespace boost; using namespace std; @@ -204,43 +183,18 @@ int main(int argc, char* argv[]) typedef property_map< Graph, edge_weight_t >::type WeightMap; typedef property_map< Graph, vertex_index_t >::type VertexMap; - // Make sure that the the we can parse the given file. - if (argc < 2) - { - usage(); - // return -1; - return 0; - } - - // Open the graph file, failing if one isn't given on the command line. - ifstream fin(argv[1]); - if (!fin) - { - usage(); - // return -1; - return 0; - } + static const double coords[][2] = { { 2, 5 }, { 2, 3 }, { 1, 2 }, + { 4, 5 }, { 5, 4 }, { 4, 3 }, { 6, 3 }, { 3, 1 } }; - string line; PositionVec position_vec; - - int n(0); - while (getline(fin, line)) + for (size_t i = 0; i < sizeof(coords) / sizeof(coords[0]); ++i) { simple_point< double > vertex; - - size_t idx(line.find(",")); - string xStr(line.substr(0, idx)); - string yStr(line.substr(idx + 1, line.size() - idx)); - - vertex.x = lexical_cast< double >(xStr); - vertex.y = lexical_cast< double >(yStr); - + vertex.x = coords[i][0]; + vertex.y = coords[i][1]; position_vec.push_back(vertex); - n++; } - - fin.close(); + int n(static_cast< int >(position_vec.size())); Container c; Graph g(position_vec.size()); @@ -286,10 +240,12 @@ int main(int argc, char* argv[]) return -1; } - cout << "Number of points: " << num_vertices(g) << endl; - cout << "Number of edges: " << num_edges(g) << endl; cout << "Length of Tour: " << len << endl; + BOOST_TEST_EQ(num_vertices(g), size_t(8)); + BOOST_TEST_EQ(c.size(), num_vertices(g) + 1); + BOOST_TEST(std::abs(len - 19.073950245236318) < 1e-9); + int cnt(0); pair< Vertex, Vertex > triangleEdge; for (vector< Vertex >::iterator itr = c.begin(); itr != c.end(); @@ -327,7 +283,7 @@ int main(int argc, char* argv[]) { caught = true; } - BOOST_ASSERT(caught); + BOOST_TEST(caught); - return 0; + return boost::report_errors(); } diff --git a/test/metric_tsp_approx.graph b/test/metric_tsp_approx.graph deleted file mode 100644 index 1af437ac6..000000000 --- a/test/metric_tsp_approx.graph +++ /dev/null @@ -1,8 +0,0 @@ -2,5 -2,3 -1,2 -4,5 -5,4 -4,3 -6,3 -3,1 \ No newline at end of file diff --git a/test/min_degree_empty.cpp b/test/min_degree_empty.cpp index 1585742fd..1267bbf2f 100644 --- a/test/min_degree_empty.cpp +++ b/test/min_degree_empty.cpp @@ -16,7 +16,7 @@ typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS > G; -int main(int argc, char** argv) +int main() { size_t n = 10; G g(n); diff --git a/test/parallel_edges_loops_test.cpp b/test/parallel_edges_loops_test.cpp index 3087fb530..229c694c5 100644 --- a/test/parallel_edges_loops_test.cpp +++ b/test/parallel_edges_loops_test.cpp @@ -28,7 +28,6 @@ This test needs to be linked against Boost.Filesystem. #include #include #include -#include #include #include @@ -90,7 +89,14 @@ void read_dimacs(Graph& g, const std::string& filename) continue; std::vector< std::string > v; - split(v, buffer, is_any_of(" \t\n")); + for (std::string::size_type start = 0;;) + { + std::string::size_type pos = s.find_first_of(" \t\n", start); + v.push_back(s.substr(start, pos - start)); + if (pos == std::string::npos) + break; + start = pos + 1; + } if (v[0] == "p") { diff --git a/test/property_iter.cpp b/test/property_iter.cpp index 09a116db0..8a2912277 100644 --- a/test/property_iter.cpp +++ b/test/property_iter.cpp @@ -80,7 +80,7 @@ int main(int, char*[]) for (std::size_t k = 0; k < N; ++k) add_vertex(current_vertex_id++, g); - mt19937 gen; + mt19937 gen(42); for (j = 0; j < 10; ++j) { diff --git a/test/r_c_shortest_paths_test.cpp b/test/r_c_shortest_paths_test.cpp index 7a80d7c1c..e1b805cb6 100644 --- a/test/r_c_shortest_paths_test.cpp +++ b/test/r_c_shortest_paths_test.cpp @@ -157,7 +157,7 @@ class ref_spptw spp_spptw_res_cont& new_cont, const spp_spptw_res_cont& old_cont, graph_traits< SPPRC_Example_Graph >::edge_descriptor ed) const { - const SPPRC_Example_Graph_Arc_Prop& arc_prop = get(edge_bundle, g)[ed]; + const SPPRC_Example_Graph_Arc_Prop arc_prop = get(edge_bundle, g)[ed]; const SPPRC_Example_Graph_Vert_Prop& vert_prop = get(vertex_bundle, g)[target(ed, g)]; new_cont.cost = old_cont.cost + arc_prop.cost; @@ -261,7 +261,7 @@ class ref_spptw_marked return false; } - const SPPRC_Example_Graph_Arc_Prop& arc_prop = get(edge_bundle, g)[ed]; + const SPPRC_Example_Graph_Arc_Prop arc_prop = get(edge_bundle, g)[ed]; const SPPRC_Example_Graph_Vert_Prop& vert_prop = get(vertex_bundle, g)[dest]; new_cont.cost = old_cont.cost + arc_prop.cost; @@ -363,8 +363,7 @@ int main(int, char*[]) { for (int t = 0; t < 10; ++t) { - r_c_shortest_paths(g, get(&SPPRC_Example_Graph_Vert_Prop::num, g), - get(&SPPRC_Example_Graph_Arc_Prop::num, g), s, t, opt_solutions, + r_c_shortest_paths(g, get(&SPPRC_Example_Graph_Vert_Prop::num, g), s, t, opt_solutions, pareto_opt_rcs_no_rc, spp_no_rc_res_cont(0), ref_no_res_cont(), dominance_no_res_cont(), std::allocator< r_c_shortest_paths_label< SPPRC_Example_Graph, @@ -523,7 +522,7 @@ int main(int, char*[]) for (int t = 0; t < 10; ++t) { r_c_shortest_paths(g, get(&SPPRC_Example_Graph_Vert_Prop::num, g), - get(&SPPRC_Example_Graph_Arc_Prop::num, g), s, t, + s, t, opt_solutions_spptw, pareto_opt_rcs_spptw, // be careful, do not simply take 0 as initial value for time spp_spptw_res_cont(0, g[s].eat), ref_spptw(), dominance_spptw(), @@ -685,7 +684,7 @@ int main(int, char*[]) opt_solution; spp_spptw_res_cont pareto_opt_rc; r_c_shortest_paths(g2, get(&SPPRC_Example_Graph_Vert_Prop::num, g2), - get(&SPPRC_Example_Graph_Arc_Prop::num, g2), 0, 3, opt_solution, + 0, 3, opt_solution, pareto_opt_rc, spp_spptw_res_cont(0, 0), ref_spptw(), dominance_spptw(), std::allocator< r_c_shortest_paths_label< SPPRC_Example_Graph, spp_spptw_res_cont > >(), @@ -730,7 +729,7 @@ int main(int, char*[]) graph_traits< SPPRC_Example_Graph >::vertex_descriptor g3_source = 0, g3_target = 1; r_c_shortest_paths(g3, get(&SPPRC_Example_Graph_Vert_Prop::num, g3), - get(&SPPRC_Example_Graph_Arc_Prop::num, g3), g3_source, g3_target, + g3_source, g3_target, pareto_opt_marked_solutions, pareto_opt_marked_resource_containers, spp_spptw_marked_res_cont(0, 0, 0), ref_spptw_marked(), dominance_spptw_marked(), diff --git a/test/r_c_shortest_paths_test_old.cpp b/test/r_c_shortest_paths_test_old.cpp new file mode 100644 index 000000000..3f686b7f3 --- /dev/null +++ b/test/r_c_shortest_paths_test_old.cpp @@ -0,0 +1,785 @@ +// Copyright Michael Drexl 2005, 2006. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://boost.org/LICENSE_1_0.txt) +#define BOOST_ALLOW_DEPRECATED_SYMBOLS +#include + +#ifdef BOOST_MSVC +#pragma warning(disable : 4267) +#endif + +#include +//#include + +#include +#include +#include + +using namespace boost; + +struct SPPRC_Example_Graph_Vert_Prop +{ + SPPRC_Example_Graph_Vert_Prop(int n = 0, int e = 0, int l = 0) + : num(n), eat(e), lat(l) + { + } + int num; + // earliest arrival time + int eat; + // latest arrival time + int lat; +}; + +struct SPPRC_Example_Graph_Arc_Prop +{ + SPPRC_Example_Graph_Arc_Prop(int n = 0, int c = 0, int t = 0) + : num(n), cost(c), time(t) + { + } + int num; + // traversal cost + int cost; + // traversal time + int time; +}; + +typedef adjacency_list< vecS, vecS, directedS, SPPRC_Example_Graph_Vert_Prop, + SPPRC_Example_Graph_Arc_Prop > + SPPRC_Example_Graph; + +// data structures for spp without resource constraints: +// ResourceContainer model +struct spp_no_rc_res_cont +{ + spp_no_rc_res_cont(int c = 0) : cost(c) {}; + spp_no_rc_res_cont& operator=(const spp_no_rc_res_cont& other) + { + if (this == &other) + return *this; + this->~spp_no_rc_res_cont(); + new (this) spp_no_rc_res_cont(other); + return *this; + } + int cost; +}; + +bool operator==( + const spp_no_rc_res_cont& res_cont_1, const spp_no_rc_res_cont& res_cont_2) +{ + return (res_cont_1.cost == res_cont_2.cost); +} + +bool operator<( + const spp_no_rc_res_cont& res_cont_1, const spp_no_rc_res_cont& res_cont_2) +{ + return (res_cont_1.cost < res_cont_2.cost); +} + +// ResourceExtensionFunction model +class ref_no_res_cont +{ +public: + inline bool operator()(const SPPRC_Example_Graph& g, + spp_no_rc_res_cont& new_cont, const spp_no_rc_res_cont& old_cont, + graph_traits< SPPRC_Example_Graph >::edge_descriptor ed) const + { + new_cont.cost = old_cont.cost + g[ed].cost; + return true; + } +}; + +// DominanceFunction model +class dominance_no_res_cont +{ +public: + inline bool operator()(const spp_no_rc_res_cont& res_cont_1, + const spp_no_rc_res_cont& res_cont_2) const + { + // must be "<=" here!!! + // must NOT be "<"!!! + return res_cont_1.cost <= res_cont_2.cost; + // this is not a contradiction to the documentation + // the documentation says: + // "A label $l_1$ dominates a label $l_2$ if and only if both are + // resident at the same vertex, and if, for each resource, the resource + // consumption of $l_1$ is less than or equal to the resource + // consumption of $l_2$, and if there is at least one resource where + // $l_1$ has a lower resource consumption than $l_2$." one can think of + // a new label with a resource consumption equal to that of an old label + // as being dominated by that old label, because the new one will have a + // higher number and is created at a later point in time, so one can + // implicitly use the number or the creation time as a resource for + // tie-breaking + } +}; +// end data structures for spp without resource constraints: + +// data structures for shortest path problem with time windows (spptw) +// ResourceContainer model +struct spp_spptw_res_cont +{ + spp_spptw_res_cont(int c = 0, int t = 0) : cost(c), time(t) {} + spp_spptw_res_cont& operator=(const spp_spptw_res_cont& other) + { + if (this == &other) + return *this; + this->~spp_spptw_res_cont(); + new (this) spp_spptw_res_cont(other); + return *this; + } + int cost; + int time; +}; + +bool operator==( + const spp_spptw_res_cont& res_cont_1, const spp_spptw_res_cont& res_cont_2) +{ + return (res_cont_1.cost == res_cont_2.cost + && res_cont_1.time == res_cont_2.time); +} + +bool operator<( + const spp_spptw_res_cont& res_cont_1, const spp_spptw_res_cont& res_cont_2) +{ + if (res_cont_1.cost > res_cont_2.cost) + return false; + if (res_cont_1.cost == res_cont_2.cost) + return res_cont_1.time < res_cont_2.time; + return true; +} + +// ResourceExtensionFunction model +class ref_spptw +{ +public: + inline bool operator()(const SPPRC_Example_Graph& g, + spp_spptw_res_cont& new_cont, const spp_spptw_res_cont& old_cont, + graph_traits< SPPRC_Example_Graph >::edge_descriptor ed) const + { + const SPPRC_Example_Graph_Arc_Prop& arc_prop = get(edge_bundle, g)[ed]; + const SPPRC_Example_Graph_Vert_Prop& vert_prop + = get(vertex_bundle, g)[target(ed, g)]; + new_cont.cost = old_cont.cost + arc_prop.cost; + int& i_time = new_cont.time; + i_time = old_cont.time + arc_prop.time; + i_time < vert_prop.eat ? i_time = vert_prop.eat : 0; + return i_time <= vert_prop.lat ? true : false; + } +}; + +// DominanceFunction model +class dominance_spptw +{ +public: + inline bool operator()(const spp_spptw_res_cont& res_cont_1, + const spp_spptw_res_cont& res_cont_2) const + { + // must be "<=" here!!! + // must NOT be "<"!!! + return res_cont_1.cost <= res_cont_2.cost + && res_cont_1.time <= res_cont_2.time; + // this is not a contradiction to the documentation + // the documentation says: + // "A label $l_1$ dominates a label $l_2$ if and only if both are + // resident at the same vertex, and if, for each resource, the resource + // consumption of $l_1$ is less than or equal to the resource + // consumption of $l_2$, and if there is at least one resource where + // $l_1$ has a lower resource consumption than $l_2$." one can think of + // a new label with a resource consumption equal to that of an old label + // as being dominated by that old label, because the new one will have a + // higher number and is created at a later point in time, so one can + // implicitly use the number or the creation time as a resource for + // tie-breaking + } +}; +// end data structures for shortest path problem with time windows (spptw) + +struct spp_spptw_marked_res_cont +{ + spp_spptw_marked_res_cont( + SPPRC_Example_Graph::vertex_descriptor v, int c = 0, int t = 0) + : cost(c), time(t), marked() + { + marked.insert(v); + } + spp_spptw_marked_res_cont& operator=(const spp_spptw_marked_res_cont& other) + { + if (this == &other) + return *this; + this->~spp_spptw_marked_res_cont(); + new (this) spp_spptw_marked_res_cont(other); + return *this; + } + int cost; + int time; + std::set< SPPRC_Example_Graph::vertex_descriptor > marked; +}; + +bool operator==(const spp_spptw_marked_res_cont& res_cont_1, + const spp_spptw_marked_res_cont& res_cont_2) +{ + return res_cont_1.cost == res_cont_2.cost + && res_cont_1.time == res_cont_2.time + && res_cont_1.marked == res_cont_2.marked; +} + +bool operator<(const spp_spptw_marked_res_cont& res_cont_1, + const spp_spptw_marked_res_cont& res_cont_2) +{ + if (res_cont_1.cost > res_cont_2.cost || res_cont_1.time > res_cont_2.time) + { + return false; + } + + if (!std::includes(res_cont_2.marked.begin(), res_cont_2.marked.end(), + res_cont_1.marked.begin(), res_cont_1.marked.end())) + { + return false; + } + + if (res_cont_1.cost == res_cont_2.cost) + { + return res_cont_1.time < res_cont_2.time; + } + return true; +} + +class ref_spptw_marked +{ +public: + inline bool operator()(const SPPRC_Example_Graph& g, + spp_spptw_marked_res_cont& new_cont, + const spp_spptw_marked_res_cont& old_cont, + graph_traits< SPPRC_Example_Graph >::edge_descriptor ed) const + { + const graph_traits< SPPRC_Example_Graph >::vertex_descriptor dest + = target(ed, g); + + if (old_cont.marked.find(dest) != old_cont.marked.end()) + { + return false; + } + + const SPPRC_Example_Graph_Arc_Prop& arc_prop = get(edge_bundle, g)[ed]; + const SPPRC_Example_Graph_Vert_Prop& vert_prop + = get(vertex_bundle, g)[dest]; + new_cont.cost = old_cont.cost + arc_prop.cost; + new_cont.marked = old_cont.marked; + new_cont.marked.insert(dest); + int& i_time = new_cont.time; + i_time = old_cont.time + arc_prop.time; + i_time < vert_prop.eat ? i_time = vert_prop.eat : 0; + return i_time <= vert_prop.lat; + } +}; + +class dominance_spptw_marked +{ +public: + inline bool operator()(const spp_spptw_marked_res_cont& res_cont_1, + const spp_spptw_marked_res_cont& res_cont_2) const + { + return res_cont_1.time <= res_cont_2.time + && res_cont_1.cost <= res_cont_2.cost + && std::includes(res_cont_1.marked.begin(), res_cont_1.marked.end(), + res_cont_2.marked.begin(), res_cont_2.marked.end()); + } +}; + +int main(int, char*[]) +{ + SPPRC_Example_Graph g; + add_vertex(SPPRC_Example_Graph_Vert_Prop(0, 0, 1000000000), g); + add_vertex(SPPRC_Example_Graph_Vert_Prop(1, 56, 142), g); + add_vertex(SPPRC_Example_Graph_Vert_Prop(2, 0, 1000000000), g); + add_vertex(SPPRC_Example_Graph_Vert_Prop(3, 89, 178), g); + add_vertex(SPPRC_Example_Graph_Vert_Prop(4, 0, 1000000000), g); + add_vertex(SPPRC_Example_Graph_Vert_Prop(5, 49, 76), g); + add_vertex(SPPRC_Example_Graph_Vert_Prop(6, 0, 1000000000), g); + add_vertex(SPPRC_Example_Graph_Vert_Prop(7, 98, 160), g); + add_vertex(SPPRC_Example_Graph_Vert_Prop(8, 0, 1000000000), g); + add_vertex(SPPRC_Example_Graph_Vert_Prop(9, 90, 158), g); + add_edge(0, 7, SPPRC_Example_Graph_Arc_Prop(6, 33, 2), g); + add_edge(0, 6, SPPRC_Example_Graph_Arc_Prop(5, 31, 6), g); + add_edge(0, 4, SPPRC_Example_Graph_Arc_Prop(3, 14, 4), g); + add_edge(0, 1, SPPRC_Example_Graph_Arc_Prop(0, 43, 8), g); + add_edge(0, 4, SPPRC_Example_Graph_Arc_Prop(4, 28, 10), g); + add_edge(0, 3, SPPRC_Example_Graph_Arc_Prop(1, 31, 10), g); + add_edge(0, 3, SPPRC_Example_Graph_Arc_Prop(2, 1, 7), g); + add_edge(0, 9, SPPRC_Example_Graph_Arc_Prop(7, 25, 9), g); + add_edge(1, 0, SPPRC_Example_Graph_Arc_Prop(8, 37, 4), g); + add_edge(1, 6, SPPRC_Example_Graph_Arc_Prop(9, 7, 3), g); + add_edge(2, 6, SPPRC_Example_Graph_Arc_Prop(12, 6, 7), g); + add_edge(2, 3, SPPRC_Example_Graph_Arc_Prop(10, 13, 7), g); + add_edge(2, 3, SPPRC_Example_Graph_Arc_Prop(11, 49, 9), g); + add_edge(2, 8, SPPRC_Example_Graph_Arc_Prop(13, 47, 5), g); + add_edge(3, 4, SPPRC_Example_Graph_Arc_Prop(17, 5, 10), g); + add_edge(3, 1, SPPRC_Example_Graph_Arc_Prop(15, 47, 1), g); + add_edge(3, 2, SPPRC_Example_Graph_Arc_Prop(16, 26, 9), g); + add_edge(3, 9, SPPRC_Example_Graph_Arc_Prop(21, 24, 10), g); + add_edge(3, 7, SPPRC_Example_Graph_Arc_Prop(20, 50, 10), g); + add_edge(3, 0, SPPRC_Example_Graph_Arc_Prop(14, 41, 4), g); + add_edge(3, 6, SPPRC_Example_Graph_Arc_Prop(19, 6, 1), g); + add_edge(3, 4, SPPRC_Example_Graph_Arc_Prop(18, 8, 1), g); + add_edge(4, 5, SPPRC_Example_Graph_Arc_Prop(26, 38, 4), g); + add_edge(4, 9, SPPRC_Example_Graph_Arc_Prop(27, 32, 10), g); + add_edge(4, 3, SPPRC_Example_Graph_Arc_Prop(24, 40, 3), g); + add_edge(4, 0, SPPRC_Example_Graph_Arc_Prop(22, 7, 3), g); + add_edge(4, 3, SPPRC_Example_Graph_Arc_Prop(25, 28, 9), g); + add_edge(4, 2, SPPRC_Example_Graph_Arc_Prop(23, 39, 6), g); + add_edge(5, 8, SPPRC_Example_Graph_Arc_Prop(32, 6, 2), g); + add_edge(5, 2, SPPRC_Example_Graph_Arc_Prop(30, 26, 10), g); + add_edge(5, 0, SPPRC_Example_Graph_Arc_Prop(28, 38, 9), g); + add_edge(5, 2, SPPRC_Example_Graph_Arc_Prop(31, 48, 10), g); + add_edge(5, 9, SPPRC_Example_Graph_Arc_Prop(33, 49, 2), g); + add_edge(5, 1, SPPRC_Example_Graph_Arc_Prop(29, 22, 7), g); + add_edge(6, 1, SPPRC_Example_Graph_Arc_Prop(34, 15, 7), g); + add_edge(6, 7, SPPRC_Example_Graph_Arc_Prop(35, 20, 3), g); + add_edge(7, 9, SPPRC_Example_Graph_Arc_Prop(40, 1, 3), g); + add_edge(7, 0, SPPRC_Example_Graph_Arc_Prop(36, 23, 5), g); + add_edge(7, 6, SPPRC_Example_Graph_Arc_Prop(38, 36, 2), g); + add_edge(7, 6, SPPRC_Example_Graph_Arc_Prop(39, 18, 10), g); + add_edge(7, 2, SPPRC_Example_Graph_Arc_Prop(37, 2, 1), g); + add_edge(8, 5, SPPRC_Example_Graph_Arc_Prop(46, 36, 5), g); + add_edge(8, 1, SPPRC_Example_Graph_Arc_Prop(42, 13, 10), g); + add_edge(8, 0, SPPRC_Example_Graph_Arc_Prop(41, 40, 5), g); + add_edge(8, 1, SPPRC_Example_Graph_Arc_Prop(43, 32, 8), g); + add_edge(8, 6, SPPRC_Example_Graph_Arc_Prop(47, 25, 1), g); + add_edge(8, 2, SPPRC_Example_Graph_Arc_Prop(44, 44, 3), g); + add_edge(8, 3, SPPRC_Example_Graph_Arc_Prop(45, 11, 9), g); + add_edge(9, 0, SPPRC_Example_Graph_Arc_Prop(48, 41, 5), g); + add_edge(9, 1, SPPRC_Example_Graph_Arc_Prop(49, 44, 7), g); + + // spp without resource constraints + + std::vector< + std::vector< graph_traits< SPPRC_Example_Graph >::edge_descriptor > > + opt_solutions; + std::vector< spp_no_rc_res_cont > pareto_opt_rcs_no_rc; + std::vector< int > i_vec_opt_solutions_spp_no_rc; + // std::cout << "r_c_shortest_paths:" << std::endl; + for (int s = 0; s < 10; ++s) + { + for (int t = 0; t < 10; ++t) + { + r_c_shortest_paths(g, get(&SPPRC_Example_Graph_Vert_Prop::num, g), + get(&SPPRC_Example_Graph_Arc_Prop::num, g), s, t, opt_solutions, + pareto_opt_rcs_no_rc, spp_no_rc_res_cont(0), ref_no_res_cont(), + dominance_no_res_cont(), + std::allocator< r_c_shortest_paths_label< SPPRC_Example_Graph, + spp_no_rc_res_cont > >(), + default_r_c_shortest_paths_visitor()); + i_vec_opt_solutions_spp_no_rc.push_back( + pareto_opt_rcs_no_rc[0].cost); + // std::cout << "From " << s << " to " << t << ": "; + // std::cout << pareto_opt_rcs_no_rc[0].cost << std::endl; + } + } + + // std::vector::vertex_descriptor> + // p( num_vertices( g ) ); + // std::vector d( num_vertices( g ) ); + // std::vector i_vec_dijkstra_distances; + // std::cout << "Dijkstra:" << std::endl; + // for( int s = 0; s < 10; ++s ) + //{ + // dijkstra_shortest_paths( g, + // s, + // &p[0], + // &d[0], + // get( &SPPRC_Example_Graph_Arc_Prop::cost, g ), + // get( &SPPRC_Example_Graph_Vert_Prop::num, g ), + // std::less(), + // closed_plus(), + // (std::numeric_limits::max)(), + // 0, + // default_dijkstra_visitor() ); + // for( int t = 0; t < 10; ++t ) + // { + // i_vec_dijkstra_distances.push_back( d[t] ); + // std::cout << "From " << s << " to " << t << ": " << d[t] << std::endl; + // } + //} + + std::vector< int > i_vec_correct_solutions; + i_vec_correct_solutions.push_back(0); + i_vec_correct_solutions.push_back(22); + i_vec_correct_solutions.push_back(27); + i_vec_correct_solutions.push_back(1); + i_vec_correct_solutions.push_back(6); + i_vec_correct_solutions.push_back(44); + i_vec_correct_solutions.push_back(7); + i_vec_correct_solutions.push_back(27); + i_vec_correct_solutions.push_back(50); + i_vec_correct_solutions.push_back(25); + i_vec_correct_solutions.push_back(37); + i_vec_correct_solutions.push_back(0); + i_vec_correct_solutions.push_back(29); + i_vec_correct_solutions.push_back(38); + i_vec_correct_solutions.push_back(43); + i_vec_correct_solutions.push_back(81); + i_vec_correct_solutions.push_back(7); + i_vec_correct_solutions.push_back(27); + i_vec_correct_solutions.push_back(76); + i_vec_correct_solutions.push_back(28); + i_vec_correct_solutions.push_back(25); + i_vec_correct_solutions.push_back(21); + i_vec_correct_solutions.push_back(0); + i_vec_correct_solutions.push_back(13); + i_vec_correct_solutions.push_back(18); + i_vec_correct_solutions.push_back(56); + i_vec_correct_solutions.push_back(6); + i_vec_correct_solutions.push_back(26); + i_vec_correct_solutions.push_back(47); + i_vec_correct_solutions.push_back(27); + i_vec_correct_solutions.push_back(12); + i_vec_correct_solutions.push_back(21); + i_vec_correct_solutions.push_back(26); + i_vec_correct_solutions.push_back(0); + i_vec_correct_solutions.push_back(5); + i_vec_correct_solutions.push_back(43); + i_vec_correct_solutions.push_back(6); + i_vec_correct_solutions.push_back(26); + i_vec_correct_solutions.push_back(49); + i_vec_correct_solutions.push_back(24); + i_vec_correct_solutions.push_back(7); + i_vec_correct_solutions.push_back(29); + i_vec_correct_solutions.push_back(34); + i_vec_correct_solutions.push_back(8); + i_vec_correct_solutions.push_back(0); + i_vec_correct_solutions.push_back(38); + i_vec_correct_solutions.push_back(14); + i_vec_correct_solutions.push_back(34); + i_vec_correct_solutions.push_back(44); + i_vec_correct_solutions.push_back(32); + i_vec_correct_solutions.push_back(29); + i_vec_correct_solutions.push_back(19); + i_vec_correct_solutions.push_back(26); + i_vec_correct_solutions.push_back(17); + i_vec_correct_solutions.push_back(22); + i_vec_correct_solutions.push_back(0); + i_vec_correct_solutions.push_back(23); + i_vec_correct_solutions.push_back(43); + i_vec_correct_solutions.push_back(6); + i_vec_correct_solutions.push_back(41); + i_vec_correct_solutions.push_back(43); + i_vec_correct_solutions.push_back(15); + i_vec_correct_solutions.push_back(22); + i_vec_correct_solutions.push_back(35); + i_vec_correct_solutions.push_back(40); + i_vec_correct_solutions.push_back(78); + i_vec_correct_solutions.push_back(0); + i_vec_correct_solutions.push_back(20); + i_vec_correct_solutions.push_back(69); + i_vec_correct_solutions.push_back(21); + i_vec_correct_solutions.push_back(23); + i_vec_correct_solutions.push_back(23); + i_vec_correct_solutions.push_back(2); + i_vec_correct_solutions.push_back(15); + i_vec_correct_solutions.push_back(20); + i_vec_correct_solutions.push_back(58); + i_vec_correct_solutions.push_back(8); + i_vec_correct_solutions.push_back(0); + i_vec_correct_solutions.push_back(49); + i_vec_correct_solutions.push_back(1); + i_vec_correct_solutions.push_back(23); + i_vec_correct_solutions.push_back(13); + i_vec_correct_solutions.push_back(37); + i_vec_correct_solutions.push_back(11); + i_vec_correct_solutions.push_back(16); + i_vec_correct_solutions.push_back(36); + i_vec_correct_solutions.push_back(17); + i_vec_correct_solutions.push_back(37); + i_vec_correct_solutions.push_back(0); + i_vec_correct_solutions.push_back(35); + i_vec_correct_solutions.push_back(41); + i_vec_correct_solutions.push_back(44); + i_vec_correct_solutions.push_back(68); + i_vec_correct_solutions.push_back(42); + i_vec_correct_solutions.push_back(47); + i_vec_correct_solutions.push_back(85); + i_vec_correct_solutions.push_back(48); + i_vec_correct_solutions.push_back(68); + i_vec_correct_solutions.push_back(91); + i_vec_correct_solutions.push_back(0); + BOOST_TEST( + i_vec_opt_solutions_spp_no_rc.size() == i_vec_correct_solutions.size()); + for (int i = 0; i < static_cast< int >(i_vec_correct_solutions.size()); ++i) + BOOST_TEST( + i_vec_opt_solutions_spp_no_rc[i] == i_vec_correct_solutions[i]); + + // spptw + std::vector< + std::vector< graph_traits< SPPRC_Example_Graph >::edge_descriptor > > + opt_solutions_spptw; + std::vector< spp_spptw_res_cont > pareto_opt_rcs_spptw; + std::vector< std::vector< std::vector< std::vector< + graph_traits< SPPRC_Example_Graph >::edge_descriptor > > > > + vec_vec_vec_vec_opt_solutions_spptw(10); + + for (int s = 0; s < 10; ++s) + { + for (int t = 0; t < 10; ++t) + { + r_c_shortest_paths(g, get(&SPPRC_Example_Graph_Vert_Prop::num, g), + get(&SPPRC_Example_Graph_Arc_Prop::num, g), s, t, + opt_solutions_spptw, pareto_opt_rcs_spptw, + // be careful, do not simply take 0 as initial value for time + spp_spptw_res_cont(0, g[s].eat), ref_spptw(), dominance_spptw(), + std::allocator< r_c_shortest_paths_label< SPPRC_Example_Graph, + spp_spptw_res_cont > >(), + default_r_c_shortest_paths_visitor()); + vec_vec_vec_vec_opt_solutions_spptw[s].push_back( + opt_solutions_spptw); + if (opt_solutions_spptw.size()) + { + bool b_is_a_path_at_all = false; + bool b_feasible = false; + bool b_correctly_extended = false; + spp_spptw_res_cont actual_final_resource_levels(0, 0); + graph_traits< SPPRC_Example_Graph >::edge_descriptor + ed_last_extended_arc; + check_r_c_path(g, opt_solutions_spptw[0], + spp_spptw_res_cont(0, g[s].eat), true, + pareto_opt_rcs_spptw[0], actual_final_resource_levels, + ref_spptw(), b_is_a_path_at_all, b_feasible, + b_correctly_extended, ed_last_extended_arc); + BOOST_TEST( + b_is_a_path_at_all && b_feasible && b_correctly_extended); + b_is_a_path_at_all = false; + b_feasible = false; + b_correctly_extended = false; + spp_spptw_res_cont actual_final_resource_levels2(0, 0); + graph_traits< SPPRC_Example_Graph >::edge_descriptor + ed_last_extended_arc2; + check_r_c_path(g, opt_solutions_spptw[0], + spp_spptw_res_cont(0, g[s].eat), false, + pareto_opt_rcs_spptw[0], actual_final_resource_levels2, + ref_spptw(), b_is_a_path_at_all, b_feasible, + b_correctly_extended, ed_last_extended_arc2); + BOOST_TEST( + b_is_a_path_at_all && b_feasible && b_correctly_extended); + } + } + } + + std::vector< int > i_vec_correct_num_solutions_spptw; + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(3); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(3); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(4); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(3); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(4); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(4); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(3); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(0); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(4); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(4); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(4); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(4); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(5); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(3); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(0); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(3); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(3); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(3); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(4); + i_vec_correct_num_solutions_spptw.push_back(1); + i_vec_correct_num_solutions_spptw.push_back(3); + i_vec_correct_num_solutions_spptw.push_back(0); + i_vec_correct_num_solutions_spptw.push_back(2); + i_vec_correct_num_solutions_spptw.push_back(3); + i_vec_correct_num_solutions_spptw.push_back(4); + i_vec_correct_num_solutions_spptw.push_back(1); + for (int s = 0; s < 10; ++s) + for (int t = 0; t < 10; ++t) + BOOST_TEST(static_cast< int >( + vec_vec_vec_vec_opt_solutions_spptw[s][t].size()) + == i_vec_correct_num_solutions_spptw[10 * s + t]); + + // one pareto-optimal solution + SPPRC_Example_Graph g2; + add_vertex(SPPRC_Example_Graph_Vert_Prop(0, 0, 1000000000), g2); + add_vertex(SPPRC_Example_Graph_Vert_Prop(1, 0, 1000000000), g2); + add_vertex(SPPRC_Example_Graph_Vert_Prop(2, 0, 1000000000), g2); + add_vertex(SPPRC_Example_Graph_Vert_Prop(3, 0, 1000000000), g2); + add_edge(0, 1, SPPRC_Example_Graph_Arc_Prop(0, 1, 1), g2); + add_edge(0, 2, SPPRC_Example_Graph_Arc_Prop(1, 2, 1), g2); + add_edge(1, 3, SPPRC_Example_Graph_Arc_Prop(2, 3, 1), g2); + add_edge(2, 3, SPPRC_Example_Graph_Arc_Prop(3, 1, 1), g2); + std::vector< graph_traits< SPPRC_Example_Graph >::edge_descriptor > + opt_solution; + spp_spptw_res_cont pareto_opt_rc; + r_c_shortest_paths(g2, get(&SPPRC_Example_Graph_Vert_Prop::num, g2), + get(&SPPRC_Example_Graph_Arc_Prop::num, g2), 0, 3, opt_solution, + pareto_opt_rc, spp_spptw_res_cont(0, 0), ref_spptw(), dominance_spptw(), + std::allocator< r_c_shortest_paths_label< SPPRC_Example_Graph, + spp_spptw_res_cont > >(), + default_r_c_shortest_paths_visitor()); + + BOOST_TEST(pareto_opt_rc.cost == 3); + + SPPRC_Example_Graph g3; + add_vertex(SPPRC_Example_Graph_Vert_Prop(0, 0, 1000), g3); + add_vertex(SPPRC_Example_Graph_Vert_Prop(1, 0, 1000), g3); + add_vertex(SPPRC_Example_Graph_Vert_Prop(2, 0, 974), g3); + add_vertex(SPPRC_Example_Graph_Vert_Prop(3, 0, 972), g3); + add_vertex(SPPRC_Example_Graph_Vert_Prop(4, 0, 967), g3); + add_vertex(SPPRC_Example_Graph_Vert_Prop(5, 678, 801), g3); + add_edge(0, 2, SPPRC_Example_Graph_Arc_Prop(0, 0, 16), g3); + add_edge(0, 3, SPPRC_Example_Graph_Arc_Prop(1, 0, 18), g3); + add_edge(0, 4, SPPRC_Example_Graph_Arc_Prop(2, 0, 23), g3); + add_edge(0, 5, SPPRC_Example_Graph_Arc_Prop(3, 0, 25), g3); + add_edge(2, 3, SPPRC_Example_Graph_Arc_Prop(4, 0, 33), g3); + add_edge(2, 4, SPPRC_Example_Graph_Arc_Prop(5, 0, 15), g3); + add_edge(2, 5, SPPRC_Example_Graph_Arc_Prop(6, 0, 33), g3); + add_edge(2, 1, SPPRC_Example_Graph_Arc_Prop(7, 0, 16), g3); + add_edge(3, 2, SPPRC_Example_Graph_Arc_Prop(8, 0, 33), g3); + add_edge(3, 4, SPPRC_Example_Graph_Arc_Prop(9, 0, 35), g3); + add_edge(3, 5, SPPRC_Example_Graph_Arc_Prop(10, 0, 21), g3); + add_edge(3, 1, SPPRC_Example_Graph_Arc_Prop(11, 0, 18), g3); + add_edge(4, 2, SPPRC_Example_Graph_Arc_Prop(12, 0, 15), g3); + add_edge(4, 3, SPPRC_Example_Graph_Arc_Prop(13, 0, 35), g3); + add_edge(4, 5, SPPRC_Example_Graph_Arc_Prop(14, 0, 25), g3); + add_edge(4, 1, SPPRC_Example_Graph_Arc_Prop(15, 0, 23), g3); + add_edge(5, 2, SPPRC_Example_Graph_Arc_Prop(16, 0, 33), g3); + add_edge(5, 3, SPPRC_Example_Graph_Arc_Prop(17, 0, 21), g3); + add_edge(5, 4, SPPRC_Example_Graph_Arc_Prop(18, 0, 25), g3); + add_edge(5, 1, SPPRC_Example_Graph_Arc_Prop(19, 0, 25), g3); + + std::vector< + std::vector< graph_traits< SPPRC_Example_Graph >::edge_descriptor > > + pareto_opt_marked_solutions; + std::vector< spp_spptw_marked_res_cont > + pareto_opt_marked_resource_containers; + + graph_traits< SPPRC_Example_Graph >::vertex_descriptor g3_source = 0, + g3_target = 1; + r_c_shortest_paths(g3, get(&SPPRC_Example_Graph_Vert_Prop::num, g3), + get(&SPPRC_Example_Graph_Arc_Prop::num, g3), g3_source, g3_target, + pareto_opt_marked_solutions, pareto_opt_marked_resource_containers, + spp_spptw_marked_res_cont(0, 0, 0), ref_spptw_marked(), + dominance_spptw_marked(), + std::allocator< r_c_shortest_paths_label< SPPRC_Example_Graph, + spp_spptw_marked_res_cont > >(), + default_r_c_shortest_paths_visitor()); + + BOOST_TEST(!pareto_opt_marked_solutions.empty()); + std::vector< std::vector< + graph_traits< SPPRC_Example_Graph >::edge_descriptor > >::const_iterator + path_it, + path_end_it; + for (path_it = pareto_opt_marked_solutions.begin(), + path_end_it = pareto_opt_marked_solutions.end(); + path_it != path_end_it; ++path_it) + { + const std::vector< + graph_traits< SPPRC_Example_Graph >::edge_descriptor >& path + = *path_it; + BOOST_TEST(!path.empty()); + + const graph_traits< SPPRC_Example_Graph >::edge_descriptor front + = path.front(); + BOOST_TEST(boost::target(front, g3) == g3_target); + + std::vector< graph_traits< SPPRC_Example_Graph >::edge_descriptor >:: + const_iterator edge_it, + edge_it_end; + graph_traits< SPPRC_Example_Graph >::edge_descriptor prev_edge = front; + + for (edge_it = path.begin() + 1, edge_it_end = path.end(); + edge_it != edge_it_end; ++edge_it) + { + graph_traits< SPPRC_Example_Graph >::edge_descriptor edge + = *edge_it; + + graph_traits< SPPRC_Example_Graph >::vertex_descriptor prev_end, + current_end; + prev_end = boost::source(prev_edge, g3); + current_end = boost::target(edge, g3); + BOOST_TEST(prev_end == current_end); + + prev_edge = edge; + } + + const graph_traits< SPPRC_Example_Graph >::edge_descriptor back + = path.back(); + BOOST_TEST(boost::source(back, g3) == g3_source); + } + + return boost::report_errors(); +} diff --git a/test/random_matching_test.cpp b/test/random_matching_test.cpp index 34de16108..f39cdd77b 100644 --- a/test/random_matching_test.cpp +++ b/test/random_matching_test.cpp @@ -1,65 +1,46 @@ //======================================================================= // Copyright (c) 2005 Aaron Windsor +// Copyright (c) 2026 Arnaud Becheler // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // //======================================================================= -#include #include +#include #include #include #include -#include -#include #include +#include using namespace boost; -typedef adjacency_list< vecS, vecS, undirectedS, - property< vertex_index_t, int > > - undirected_graph; +using undirected_graph = adjacency_list< vecS, vecS, undirectedS, property< vertex_index_t, int > >; +using vertex_index_map_t = property_map< undirected_graph, vertex_index_t >::type; +using mate_t = vector_property_map< graph_traits< undirected_graph >::vertex_descriptor, vertex_index_map_t >; +using vertex_iterator_t = graph_traits< undirected_graph >::vertex_iterator; +using vertex_descriptor_t = graph_traits< undirected_graph >::vertex_descriptor; +using v_size_t = graph_traits< undirected_graph >::vertices_size_type; -typedef property_map< undirected_graph, vertex_index_t >::type - vertex_index_map_t; -typedef vector_property_map< - graph_traits< undirected_graph >::vertex_descriptor, vertex_index_map_t > - mate_t; -typedef graph_traits< undirected_graph >::vertex_iterator vertex_iterator_t; -typedef graph_traits< undirected_graph >::vertex_descriptor vertex_descriptor_t; -typedef graph_traits< undirected_graph >::vertices_size_type v_size_t; - -int main(int argc, char** argv) +int main() { - if (argc < 3) - { - std::cout << "Usage: " << argv[0] << " n m" << std::endl - << "Tests the checked matching on a random graph w/ n " - "vertices and m edges" - << std::endl; - exit(-1); - } - - int n = atoi(argv[1]); - int m = atoi(argv[2]); - + // Test the checked matching on a random graph with n vertices and m edges. + constexpr int n = 1000; + constexpr int m = 1020; + undirected_graph g(n); - - typedef boost::mt19937 base_generator_type; - base_generator_type generator(static_cast< unsigned int >(std::time(0))); - boost::uniform_int<> distribution(0, n - 1); - boost::variate_generator< base_generator_type&, boost::uniform_int<> > - rand_num(generator, distribution); + std::mt19937 generator(42); int num_edges = 0; bool success; while (num_edges < m) { - vertex_descriptor_t u = random_vertex(g, rand_num); - vertex_descriptor_t v = random_vertex(g, rand_num); + vertex_descriptor_t u = random_vertex(g, generator); + vertex_descriptor_t v = random_vertex(g, generator); if (u != v) { if (!edge(u, v, g).second) @@ -73,15 +54,12 @@ int main(int argc, char** argv) } mate_t mate(n); - bool random_graph_result - = checked_edmonds_maximum_cardinality_matching(g, mate); + bool random_graph_result = checked_edmonds_maximum_cardinality_matching(g, mate); if (!random_graph_result) { - std::cout << "TEST 1 FAILED!!!" << std::endl << std::endl; - std::cout << "Graph has edges: "; - typedef graph_traits< undirected_graph >::edge_iterator edge_iterator_t; + using edge_iterator_t = graph_traits< undirected_graph >::edge_iterator; edge_iterator_t ei, ei_end; for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) std::cout << *ei << ", "; @@ -95,6 +73,7 @@ int main(int argc, char** argv) std::cout << "{" << *vi << "," << mate[*vi] << "}, "; std::cout << std::endl; } + BOOST_TEST(random_graph_result); // Now remove an edge from the random_mate matching. vertex_iterator_t vi, vi_end; @@ -105,27 +84,25 @@ int main(int argc, char** argv) mate[mate[*vi]] = graph_traits< undirected_graph >::null_vertex(); mate[*vi] = graph_traits< undirected_graph >::null_vertex(); - //...and run the matching verifier - it should tell us that the matching - // isn't a maximum matching. + // the verifier should report this modified matching isn't maximum bool modified_random_verification_result = maximum_cardinality_matching_verifier< undirected_graph, mate_t, vertex_index_map_t >::verify_matching(g, mate, get(vertex_index, g)); - if (modified_random_verification_result) - { - std::cout << "TEST 2 FAILED!!!" << std::endl; - } + BOOST_TEST(!modified_random_verification_result); // find a greedy matching on the graph mate_t greedy_mate(n); greedy_matching< undirected_graph, mate_t >::find_matching(g, greedy_mate); - if (matching_size(g, mate) > matching_size(g, greedy_mate) + // a verified maximum greedy matching can't be smaller than mate + bool greedy_contradicts_verifier + = matching_size(g, mate) > matching_size(g, greedy_mate) && maximum_cardinality_matching_verifier< undirected_graph, mate_t, vertex_index_map_t >::verify_matching(g, greedy_mate, - get(vertex_index, g))) - std::cout << "TEST 3 FAILED!!!" << std::endl; + get(vertex_index, g)); + BOOST_TEST(!greedy_contradicts_verifier); - return 0; + return boost::report_errors(); } diff --git a/test/random_spanning_tree_test.cpp b/test/random_spanning_tree_test.cpp index bcd40d183..c0974d253 100644 --- a/test/random_spanning_tree_test.cpp +++ b/test/random_spanning_tree_test.cpp @@ -77,7 +77,7 @@ int main(int, char**) put(weight, e, (1. + get(edge_index, g, e)) / num_edges(g)); } - boost::mt19937 gen; + boost::mt19937 gen(42); random_spanning_tree(g, gen, predecessor_map(pred)); // write_spanning_tree(g, pred, constant_property_map(1.), "unweight_random_st.dot"); diff --git a/test/rcsp_custom_vertex_id.cpp b/test/rcsp_custom_vertex_id.cpp index c5e5ebf24..da61f71f2 100644 --- a/test/rcsp_custom_vertex_id.cpp +++ b/test/rcsp_custom_vertex_id.cpp @@ -113,8 +113,7 @@ int main() OptPath op; ParetoOpt ol; - r_c_shortest_paths(g, get(&VertexProperty::id, g), - get(&EdgeProperty::id, g), v1, v2, op, ol, ResourceCont(5), LabelExt(), + r_c_shortest_paths(g, get(&VertexProperty::id, g), v1, v2, op, ol, ResourceCont(5), LabelExt(), LabelDom(), allocator< r_c_shortest_paths_label< Graph, ResourceCont > >(), default_r_c_shortest_paths_visitor()); diff --git a/test/rcsp_custom_vertex_id_old.cpp b/test/rcsp_custom_vertex_id_old.cpp new file mode 100644 index 000000000..1e0e94cd2 --- /dev/null +++ b/test/rcsp_custom_vertex_id_old.cpp @@ -0,0 +1,124 @@ +//======================================================================= +// Copyright (c) 2013 Alberto Santini +// Author: Alberto Santini +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= +#define BOOST_ALLOW_DEPRECATED_SYMBOLS + +#include + +#ifdef BOOST_MSVC +// Without disabling this we get hard errors about initialialized pointers: +#pragma warning(disable : 4703) +#endif + +#include +#include +#include +#include +#include +#include + +using std::allocator; +using std::vector; +using namespace boost; + +class VertexProperty +{ +public: + int property1; + int property2; + int id; + VertexProperty() {} + VertexProperty(const int property1, const int property2) + : property1(property1), property2(property2) + { + } +}; + +class EdgeProperty +{ +public: + int cost; + int id; + EdgeProperty() {} + EdgeProperty(const int cost) : cost(cost) {} +}; + +typedef adjacency_list< listS, listS, bidirectionalS, VertexProperty, + EdgeProperty > + Graph; +typedef graph_traits< Graph >::vertex_descriptor Vertex; +typedef graph_traits< Graph >::edge_descriptor Edge; + +class ResourceCont +{ +public: + int res; + ResourceCont(const int res = 5) : res(res) {} + bool operator==(const ResourceCont& rc) const { return (res == rc.res); } + bool operator<(const ResourceCont& rc) const { return (res > rc.res); } +}; + +class LabelExt +{ +public: + bool operator()(const Graph& g, ResourceCont& rc, + const ResourceCont& old_rc, Edge e) const + { + rc.res = old_rc.res - g[e].cost; + return (rc.res > 0); + } +}; + +class LabelDom +{ +public: + bool operator()(const ResourceCont& rc1, const ResourceCont& rc2) const + { + return (rc1 == rc2 || rc1 < rc2); + } +}; + +int main() +{ + VertexProperty vp1(1, 1); + VertexProperty vp2(5, 9); + VertexProperty vp3(4, 3); + EdgeProperty e12(1); + EdgeProperty e23(2); + + Graph g; + + Vertex v1 = add_vertex(g); + g[v1] = vp1; + Vertex v2 = add_vertex(g); + g[v2] = vp2; + Vertex v3 = add_vertex(g); + g[v3] = vp3; + + add_edge(v1, v2, e12, g); + add_edge(v2, v3, e23, g); + + int index = 0; + BGL_FORALL_VERTICES(v, g, Graph) { g[v].id = index++; } + index = 0; + BGL_FORALL_EDGES(e, g, Graph) { g[e].id = index++; } + + typedef vector< vector< Edge > > OptPath; + typedef vector< ResourceCont > ParetoOpt; + + OptPath op; + ParetoOpt ol; + + r_c_shortest_paths(g, get(&VertexProperty::id, g), + v1, v2, op, ol, ResourceCont(5), LabelExt(), + LabelDom(), + allocator< r_c_shortest_paths_label< Graph, ResourceCont > >(), + default_r_c_shortest_paths_visitor()); + + return 0; +} diff --git a/test/rcsp_single_solution.cpp b/test/rcsp_single_solution.cpp index 765a7f373..f7b948019 100644 --- a/test/rcsp_single_solution.cpp +++ b/test/rcsp_single_solution.cpp @@ -75,13 +75,12 @@ struct extension_function { resource_container run_rcsp(const graph_type& graph, vertex_type source, vertex_type target) { const auto vertex_index_map = boost::get(boost::vertex_index, graph); - const auto edge_index_map = boost::get(boost::edge_all, graph); boost::default_r_c_shortest_paths_allocator label_allocator{}; path_type single_solution; resource_container single_resource(0, 0); const resource_container start_resource(0, 0); - boost::r_c_shortest_paths(graph, vertex_index_map, edge_index_map, source, target, single_solution, single_resource, + boost::r_c_shortest_paths(graph, vertex_index_map, source, target, single_solution, single_resource, start_resource, extension_function{}, dominance{}, label_allocator, boost::default_r_c_shortest_paths_visitor()); diff --git a/test/rcsp_single_solution_old.cpp b/test/rcsp_single_solution_old.cpp new file mode 100644 index 000000000..8ef922dd3 --- /dev/null +++ b/test/rcsp_single_solution_old.cpp @@ -0,0 +1,119 @@ +//======================================================================= +// Copyright (c) 2024 Andrea Cassioli +// Author: Andrea Cassioli +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= +#define BOOST_ALLOW_DEPRECATED_SYMBOLS + +#include +#include + +#include + +struct edge_prop { + edge_prop(int c, int t) : cost(c), time(t) {} + + int cost; + int time; +}; + +using graph_type = boost::adjacency_list; +using vertex_type = graph_type::vertex_descriptor; +using edge_type = graph_type::edge_descriptor; +using path_type = std::vector; + +class dominance +{ + public: + template + inline bool operator()(const C& res_cont_1, const C& res_cont_2) const { + return res_cont_1.cost <= res_cont_2.cost && res_cont_1.time <= res_cont_2.time; + } +}; + +struct resource_container +{ + resource_container(int c, int t) : cost(c), time(t) {} + + int cost; // minimise cost + int time; // a fake time constraints +}; + + +bool operator==( + const resource_container& res_cont_1, const resource_container& res_cont_2) +{ + return (res_cont_1.cost == res_cont_2.cost + && res_cont_1.time == res_cont_2.time); +} + +bool operator<( + const resource_container& res_cont_1, const resource_container& res_cont_2) +{ + if (res_cont_1.cost > res_cont_2.cost) + return false; + if (res_cont_1.cost == res_cont_2.cost) + return res_cont_1.time < res_cont_2.time; + return true; +} + +struct extension_function { + template + bool operator()(const GraphType& graph, + resource_container& new_cont, + const resource_container& old_cont, + const typename GraphType::edge_descriptor& edge) const { + new_cont = old_cont; + new_cont.cost = old_cont.cost + graph[edge].cost; + // here I could check tme constraint, but for this example does not matter + new_cont.time = old_cont.time + graph[edge].time; + return true; + } +}; + +resource_container run_rcsp(const graph_type& graph, vertex_type source, vertex_type target) { + const auto vertex_index_map = boost::get(boost::vertex_index, graph); + const auto edge_index_map = boost::get(boost::edge_all, graph); + boost::default_r_c_shortest_paths_allocator label_allocator{}; + + path_type single_solution; + resource_container single_resource(0, 0); + const resource_container start_resource(0, 0); + boost::r_c_shortest_paths(graph, vertex_index_map, edge_index_map, source, target, single_solution, single_resource, + start_resource, extension_function{}, dominance{}, label_allocator, + boost::default_r_c_shortest_paths_visitor()); + + return single_resource; +} + +int main() { + graph_type graph; + + /* + (1,0) (10, 1) + /-----> [A] ------\ + [s] [t] + \-----> [B] ------/ + (2, 1) (3,1) + + The shortest path is s->B->t with cost 5. + */ + + const auto s = boost::add_vertex("s", graph); + const auto A = boost::add_vertex("A", graph); + const auto B = boost::add_vertex("B", graph); + const auto t = boost::add_vertex("t", graph); + + boost::add_edge(s, A, edge_prop(1, 0), graph); + boost::add_edge(s, B, edge_prop(2, 1), graph); + boost::add_edge(A, t, edge_prop(10, 0), graph); + boost::add_edge(B, t, edge_prop(3, 1), graph); + + const auto solution_resource_container = run_rcsp(graph, s, t); + + BOOST_TEST(solution_resource_container.cost == 5); + return boost::report_errors(); +} diff --git a/test/serialize.cpp b/test/serialize.cpp index a6044c414..b609238d6 100644 --- a/test/serialize.cpp +++ b/test/serialize.cpp @@ -16,6 +16,7 @@ #include #include #include +#include struct vertex_properties { @@ -47,6 +48,10 @@ typedef adjacency_list< vecS, vecS, undirectedS, vertex_properties, typedef graph_traits< Graph >::vertex_descriptor vd_type; +static_assert(boost::serialization::tracking_level< Graph >::value + == boost::serialization::track_never, + "adjacency_list tracking_level must be track_never"); + typedef adjacency_list< vecS, vecS, undirectedS, vertex_properties > Graph_no_edge_property; diff --git a/test/stoer_wagner_test.cpp b/test/stoer_wagner_test.cpp index 198121474..e3143d5ae 100644 --- a/test/stoer_wagner_test.cpp +++ b/test/stoer_wagner_test.cpp @@ -1,17 +1,18 @@ // Copyright Daniel Trebbien 2010. +// Copyright Arnaud Becheler 2026. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or the copy at // http://www.boost.org/LICENSE_1_0.txt) -#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS -#endif +// Exercises the positional boost::graph::stoer_wagner_min_cut interface. +// The deprecated named parameter forms are covered in stoer_wagner_test_old.cpp. #include -#include +#include #include -#include +#include #include +#include #include #include #include @@ -20,18 +21,18 @@ #include #include #include +#include #include -#include -typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS, - boost::no_property, boost::property< boost::edge_weight_t, int > > - undirected_graph; -typedef boost::property_map< undirected_graph, boost::edge_weight_t >::type - weight_map_type; -typedef boost::property_traits< weight_map_type >::value_type weight_type; +#include "mas_sw_maxflow_oracle.hpp" -typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS > - undirected_unweighted_graph; +using mas_sw_oracle::undirected_graph; +using mas_sw_oracle::weight_map_type; +using mas_sw_oracle::weight_type; +using mas_sw_oracle::vertex_descriptor; +using mas_sw_oracle::edge_descriptor; + +using undirected_unweighted_graph = boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS >; std::string test_dir; @@ -41,7 +42,44 @@ struct edge_t unsigned long second; }; -// the example from Stoer & Wagner (1997) +// Build the keyed max priority queue the Stoer-Wagner phases run on. +template < class Graph > +auto make_maxheap(const Graph& g) +{ + using vd = typename boost::graph_traits< Graph >::vertex_descriptor; + using index_map_type = typename boost::property_map< Graph, boost::vertex_index_t >::const_type; + using distances_type = boost::shared_array_property_map< weight_type, index_map_type >; + using index_in_heap_type = typename std::vector< vd >::size_type; + using indices_type = boost::shared_array_property_map< index_in_heap_type, index_map_type >; + using maxheap_type = boost::d_ary_heap_indirect< vd, 22, indices_type, distances_type, std::greater< weight_type > >; + + const index_map_type index_map = get(boost::vertex_index, g); + distances_type distances_map = boost::make_shared_array_property_map(num_vertices(g), static_cast< weight_type >(0), index_map); + indices_type indices_map = boost::make_shared_array_property_map(num_vertices(g), static_cast< index_in_heap_type >(-1), index_map); + return maxheap_type(distances_map, indices_map); +} + +// Assignment work map: each vertex maps to its supernode representative. +template < class Graph > +auto make_assignment_map(const Graph& g) +{ + using vd = typename boost::graph_traits< Graph >::vertex_descriptor; + return boost::make_shared_array_property_map(num_vertices(g), vd(), get(boost::vertex_index, g)); +} + +// Stoer Wagner global min cut on a curated set, checked against the known value. +void test_curated_min_cuts() +{ + for (const mas_sw_oracle::curated_graph& cg : mas_sw_oracle::curated_graphs()) + { + const undirected_graph& g = cg.graph; + BOOST_TEST(mas_sw_oracle::is_connected(g)); + const weight_type w = boost::graph::stoer_wagner_min_cut(g, get(boost::edge_weight, g), boost::dummy_property_map()); + BOOST_TEST_EQ(w, cg.min_cut); + } +} + +// the example from Stoer & Wagner (1997), via the convenience overload void test0() { edge_t edges[] = { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 0, 4 }, { 1, 4 }, @@ -50,10 +88,9 @@ void test0() undirected_graph g(edges, edges + 12, ws, 8, 12); weight_map_type weights = get(boost::edge_weight, g); - std::map< int, bool > parity; - boost::associative_property_map< std::map< int, bool > > parities(parity); - int w - = boost::stoer_wagner_min_cut(g, weights, boost::parity_map(parities)); + std::map< vertex_descriptor, bool > parity; + boost::associative_property_map< std::map< vertex_descriptor, bool > > parities(parity); + const int w = boost::graph::stoer_wagner_min_cut(g, weights, parities); BOOST_TEST_EQ(w, 4); const bool parity0 = get(parities, 0); BOOST_TEST_EQ(parity0, get(parities, 1)); @@ -68,32 +105,22 @@ void test0() void test1() { - { // if only one vertex, can't run `boost::stoer_wagner_min_cut` + { // if only one vertex, can't run stoer_wagner_min_cut undirected_graph g; add_vertex(g); - BOOST_TEST_THROWS( - boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g)), + boost::graph::stoer_wagner_min_cut(g, get(boost::edge_weight, g), boost::dummy_property_map()), boost::bad_graph); } { // three vertices with one multi-edge - typedef boost::graph_traits< undirected_graph >::vertex_descriptor - vertex_descriptor; - edge_t edges[] = { { 0, 1 }, { 1, 2 }, { 1, 2 }, { 2, 0 } }; weight_type ws[] = { 3, 1, 1, 1 }; undirected_graph g(edges, edges + 4, ws, 3, 4); weight_map_type weights = get(boost::edge_weight, g); - std::map< int, bool > parity; - boost::associative_property_map< std::map< int, bool > > parities( - parity); - std::map< vertex_descriptor, vertex_descriptor > assignment; - boost::associative_property_map< - std::map< vertex_descriptor, vertex_descriptor > > - assignments(assignment); - int w = boost::stoer_wagner_min_cut(g, weights, - boost::parity_map(parities).vertex_assignment_map(assignments)); + std::map< vertex_descriptor, bool > parity; + boost::associative_property_map< std::map< vertex_descriptor, bool > > parities(parity); + const int w = boost::graph::stoer_wagner_min_cut(g, weights, parities); BOOST_TEST_EQ(w, 3); const bool parity2 = get(parities, 2), parity0 = get(parities, 0); BOOST_TEST_NE(parity2, parity0); @@ -101,6 +128,21 @@ void test1() } } +// a priority queue that is not empty on entry is rejected +void test_nonempty_queue_throws() +{ + undirected_graph g = mas_sw_oracle::make_weighted_graph(4, { { 0, 1, 1 }, { 1, 2, 1 }, { 2, 3, 1 } }); + weight_map_type weights = get(boost::edge_weight, g); + std::map< vertex_descriptor, bool > parity; + boost::associative_property_map< std::map< vertex_descriptor, bool > > parities(parity); + auto assignment_map = make_assignment_map(g); + auto pq = make_maxheap(g); + pq.push(0); + BOOST_TEST_THROWS( + boost::graph::stoer_wagner_min_cut(g, weights, parities, assignment_map, pq), + std::invalid_argument); +} + // example by Daniel Trebbien void test2() { @@ -109,10 +151,9 @@ void test2() weight_type ws[] = { 1, 3, 4, 6, 4, 1, 2, 5, 2 }; undirected_graph g(edges, edges + 9, ws, 7, 9); - std::map< int, bool > parity; - boost::associative_property_map< std::map< int, bool > > parities(parity); - int w = boost::stoer_wagner_min_cut( - g, get(boost::edge_weight, g), boost::parity_map(parities)); + std::map< vertex_descriptor, bool > parity; + boost::associative_property_map< std::map< vertex_descriptor, bool > > parities(parity); + const int w = boost::graph::stoer_wagner_min_cut(g, get(boost::edge_weight, g), parities); BOOST_TEST_EQ(w, 3); const bool parity2 = get(parities, 2); BOOST_TEST_EQ(parity2, get(parities, 4)); @@ -127,17 +168,18 @@ void test2() // example by Daniel Trebbien void test3() { - edge_t edges[] = { { 3, 4 }, { 3, 6 }, { 3, 5 }, { 0, 4 }, { 0, 1 }, + edge_t edges[] = { + { 3, 4 }, { 3, 6 }, { 3, 5 }, { 0, 4 }, { 0, 1 }, { 0, 6 }, { 0, 7 }, { 0, 5 }, { 0, 2 }, { 4, 1 }, { 1, 6 }, { 1, 5 }, - { 6, 7 }, { 7, 5 }, { 5, 2 }, { 3, 4 } }; + { 6, 7 }, { 7, 5 }, { 5, 2 }, { 3, 4 } + }; weight_type ws[] = { 0, 3, 1, 3, 1, 2, 6, 1, 8, 1, 1, 80, 2, 1, 1, 4 }; undirected_graph g(edges, edges + 16, ws, 8, 16); weight_map_type weights = get(boost::edge_weight, g); - std::map< int, bool > parity; - boost::associative_property_map< std::map< int, bool > > parities(parity); - int w - = boost::stoer_wagner_min_cut(g, weights, boost::parity_map(parities)); + std::map< vertex_descriptor, bool > parity; + boost::associative_property_map< std::map< vertex_descriptor, bool > > parities(parity); + const int w = boost::graph::stoer_wagner_min_cut(g, weights, parities); BOOST_TEST_EQ(w, 7); const bool parity1 = get(parities, 1); BOOST_TEST_EQ(parity1, get(parities, 5)); @@ -150,28 +192,21 @@ void test3() BOOST_TEST_EQ(parity0, get(parities, 7)); } +// unweighted graph with a constant weight map void test4() { - typedef boost::graph_traits< - undirected_unweighted_graph >::vertex_descriptor vertex_descriptor; - typedef boost::graph_traits< undirected_unweighted_graph >::edge_descriptor - edge_descriptor; + using vd = boost::graph_traits< undirected_unweighted_graph >::vertex_descriptor; + using ed = boost::graph_traits< undirected_unweighted_graph >::edge_descriptor; edge_t edges[] = { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 0, 4 }, { 1, 4 }, { 1, 5 }, { 2, 6 }, { 3, 6 }, { 3, 7 }, { 4, 5 }, { 5, 6 }, { 6, 7 }, { 0, 4 }, { 6, 7 } }; undirected_unweighted_graph g(edges, edges + 14, 8); - std::map< vertex_descriptor, bool > parity; - boost::associative_property_map< std::map< vertex_descriptor, bool > > - parities(parity); - std::map< vertex_descriptor, vertex_descriptor > assignment; - boost::associative_property_map< - std::map< vertex_descriptor, vertex_descriptor > > - assignments(assignment); - int w = boost::stoer_wagner_min_cut(g, - boost::make_constant_property< edge_descriptor >(weight_type(1)), - boost::vertex_assignment_map(assignments).parity_map(parities)); + std::map< vd, bool > parity; + boost::associative_property_map< std::map< vd, bool > > parities(parity); + const int w = boost::graph::stoer_wagner_min_cut(g, + boost::make_constant_property< ed >(weight_type(1)), parities); BOOST_TEST_EQ(w, 2); const bool parity0 = get(parities, 0); BOOST_TEST_EQ(parity0, get(parities, 1)); @@ -194,10 +229,9 @@ void test5() undirected_graph g(edges, edges + 13, ws, 8, 13); weight_map_type weights = get(boost::edge_weight, g); - std::map< int, bool > parity; - boost::associative_property_map< std::map< int, bool > > parities(parity); - int w - = boost::stoer_wagner_min_cut(g, weights, boost::parity_map(parities)); + std::map< vertex_descriptor, bool > parity; + boost::associative_property_map< std::map< vertex_descriptor, bool > > parities(parity); + const int w = boost::graph::stoer_wagner_min_cut(g, weights, parities); BOOST_TEST_EQ(w, 6); const bool parity0 = get(parities, 0); BOOST_TEST_EQ(parity0, get(parities, 1)); @@ -210,102 +244,62 @@ void test5() BOOST_TEST_EQ(parity4, get(parities, 7)); } -// The input for the `test_prgen` family of tests comes from a program, named -// `prgen`, that comes with a package of min-cut solvers by Chandra Chekuri, -// Andrew Goldberg, David Karger, Matthew Levine, and Cliff Stein. `prgen` was +// The input for the test_prgen family of tests comes from a program named +// prgen that comes with a package of min-cut solvers by Chandra Chekuri, +// Andrew Goldberg, David Karger, Matthew Levine, and Cliff Stein. prgen was // used to generate input graphs and the solvers were used to verify the return -// value of `boost::stoer_wagner_min_cut` on the input graphs. +// value of stoer_wagner_min_cut on the input graphs. // // http://www.columbia.edu/~cs2035/code.html // -// Note that it is somewhat more difficult to verify the parities because -// "`prgen` graphs" often have several min-cuts. This is why only the cut -// weight of the min-cut is verified. +// Only the cut weight is verified because prgen graphs often have several +// min-cuts. -// 3 min-cuts +// 3 min-cuts, via the fully positional overload with an explicit index map void test_prgen_20_70_2() { - typedef boost::graph_traits< undirected_graph >::vertex_descriptor - vertex_descriptor; - - std::ifstream ifs( - (test_dir + "/prgen_input_graphs/prgen_20_70_2.net").c_str()); + std::ifstream ifs((test_dir + "/prgen_input_graphs/prgen_20_70_2.net").c_str()); undirected_graph g; - boost::read_dimacs_min_cut( - g, get(boost::edge_weight, g), boost::dummy_property_map(), ifs); + boost::read_dimacs_min_cut(g, get(boost::edge_weight, g), boost::dummy_property_map(), ifs); std::map< vertex_descriptor, std::size_t > component; - boost::associative_property_map< - std::map< vertex_descriptor, std::size_t > > - components(component); - BOOST_TEST_EQ(boost::connected_components(g, components), - 1U); // verify the connectedness assumption - - typedef boost::shared_array_property_map< weight_type, - boost::property_map< undirected_graph, - boost::vertex_index_t >::const_type > - distances_type; - distances_type distances = boost::make_shared_array_property_map( - num_vertices(g), weight_type(0), get(boost::vertex_index, g)); - typedef std::vector< vertex_descriptor >::size_type index_in_heap_type; - typedef boost::shared_array_property_map< index_in_heap_type, - boost::property_map< undirected_graph, - boost::vertex_index_t >::const_type > - indicesInHeap_type; - indicesInHeap_type indicesInHeap = boost::make_shared_array_property_map( - num_vertices(g), index_in_heap_type(-1), get(boost::vertex_index, g)); - boost::d_ary_heap_indirect< vertex_descriptor, 22, indicesInHeap_type, - distances_type, std::greater< weight_type > > - pq(distances, indicesInHeap); - - int w = boost::stoer_wagner_min_cut( - g, get(boost::edge_weight, g), boost::max_priority_queue(pq)); + boost::associative_property_map< std::map< vertex_descriptor, std::size_t > > components(component); + BOOST_TEST_EQ(boost::connected_components(g, components), 1U); + + auto assignment_map = make_assignment_map(g); + auto pq = make_maxheap(g); + const int w = boost::graph::stoer_wagner_min_cut(g, get(boost::edge_weight, g), + boost::dummy_property_map(), assignment_map, pq, get(boost::vertex_index, g)); BOOST_TEST_EQ(w, 3407); } // 7 min-cuts void test_prgen_50_40_2() { - typedef boost::graph_traits< undirected_graph >::vertex_descriptor - vertex_descriptor; - - std::ifstream ifs( - (test_dir + "/prgen_input_graphs/prgen_50_40_2.net").c_str()); + std::ifstream ifs((test_dir + "/prgen_input_graphs/prgen_50_40_2.net").c_str()); undirected_graph g; - boost::read_dimacs_min_cut( - g, get(boost::edge_weight, g), boost::dummy_property_map(), ifs); + boost::read_dimacs_min_cut(g, get(boost::edge_weight, g), boost::dummy_property_map(), ifs); std::map< vertex_descriptor, std::size_t > component; - boost::associative_property_map< - std::map< vertex_descriptor, std::size_t > > - components(component); - BOOST_TEST_EQ(boost::connected_components(g, components), - 1U); // verify the connectedness assumption + boost::associative_property_map< std::map< vertex_descriptor, std::size_t > > components(component); + BOOST_TEST_EQ(boost::connected_components(g, components), 1U); - int w = boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g)); + const int w = boost::graph::stoer_wagner_min_cut(g, get(boost::edge_weight, g), boost::dummy_property_map()); BOOST_TEST_EQ(w, 10056); } // 6 min-cuts void test_prgen_50_70_2() { - typedef boost::graph_traits< undirected_graph >::vertex_descriptor - vertex_descriptor; - - std::ifstream ifs( - (test_dir + "/prgen_input_graphs/prgen_50_70_2.net").c_str()); + std::ifstream ifs((test_dir + "/prgen_input_graphs/prgen_50_70_2.net").c_str()); undirected_graph g; - boost::read_dimacs_min_cut( - g, get(boost::edge_weight, g), boost::dummy_property_map(), ifs); + boost::read_dimacs_min_cut(g, get(boost::edge_weight, g), boost::dummy_property_map(), ifs); std::map< vertex_descriptor, std::size_t > component; - boost::associative_property_map< - std::map< vertex_descriptor, std::size_t > > - components(component); - BOOST_TEST_EQ(boost::connected_components(g, components), - 1U); // verify the connectedness assumption + boost::associative_property_map< std::map< vertex_descriptor, std::size_t > > components(component); + BOOST_TEST_EQ(boost::connected_components(g, components), 1U); - int w = boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g)); + const int w = boost::graph::stoer_wagner_min_cut(g, get(boost::edge_weight, g), boost::dummy_property_map()); BOOST_TEST_EQ(w, 21755); } @@ -316,12 +310,15 @@ int main(int argc, char* argv[]) test_dir = argv[1]; test0(); test1(); + test_nonempty_queue_throws(); test2(); test3(); test4(); test5(); test_prgen_20_70_2(); + test_prgen_50_40_2(); test_prgen_50_70_2(); + test_curated_min_cuts(); } return boost::report_errors(); } diff --git a/test/stoer_wagner_test_old.cpp b/test/stoer_wagner_test_old.cpp new file mode 100644 index 000000000..d229d1c31 --- /dev/null +++ b/test/stoer_wagner_test_old.cpp @@ -0,0 +1,344 @@ +// Copyright Daniel Trebbien 2010. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or the copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// This test exercises the deprecated stoer_wagner_min_cut interfaces on purpose +// (the named parameter and boost:: positional overloads that now live in +// boost::graph), so silence the deprecation warnings. +#define BOOST_ALLOW_DEPRECATED_SYMBOLS + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mas_sw_maxflow_oracle.hpp" + +using mas_sw_oracle::undirected_graph; +using mas_sw_oracle::weight_map_type; +using mas_sw_oracle::weight_type; + +typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS > + undirected_unweighted_graph; + +std::string test_dir; + +struct edge_t +{ + unsigned long first; + unsigned long second; +}; + +// Stoer Wagner global min cut on a curated set, checked against the known value. +void test_curated_min_cuts() +{ + for (const mas_sw_oracle::curated_graph& cg : mas_sw_oracle::curated_graphs()) + { + const undirected_graph& g = cg.graph; + BOOST_TEST(mas_sw_oracle::is_connected(g)); + BOOST_TEST_EQ(boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g)), cg.min_cut); + } +} + +// the example from Stoer & Wagner (1997) +void test0() +{ + edge_t edges[] = { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 0, 4 }, { 1, 4 }, + { 1, 5 }, { 2, 6 }, { 3, 6 }, { 3, 7 }, { 4, 5 }, { 5, 6 }, { 6, 7 } }; + weight_type ws[] = { 2, 3, 4, 3, 2, 2, 2, 2, 2, 3, 1, 3 }; + undirected_graph g(edges, edges + 12, ws, 8, 12); + + weight_map_type weights = get(boost::edge_weight, g); + std::map< int, bool > parity; + boost::associative_property_map< std::map< int, bool > > parities(parity); + int w + = boost::stoer_wagner_min_cut(g, weights, boost::parity_map(parities)); + BOOST_TEST_EQ(w, 4); + const bool parity0 = get(parities, 0); + BOOST_TEST_EQ(parity0, get(parities, 1)); + BOOST_TEST_EQ(parity0, get(parities, 4)); + BOOST_TEST_EQ(parity0, get(parities, 5)); + const bool parity2 = get(parities, 2); + BOOST_TEST_NE(parity0, parity2); + BOOST_TEST_EQ(parity2, get(parities, 3)); + BOOST_TEST_EQ(parity2, get(parities, 6)); + BOOST_TEST_EQ(parity2, get(parities, 7)); +} + +void test1() +{ + { // if only one vertex, can't run `boost::stoer_wagner_min_cut` + undirected_graph g; + add_vertex(g); + + BOOST_TEST_THROWS( + boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g)), + boost::bad_graph); + } + { // three vertices with one multi-edge + typedef boost::graph_traits< undirected_graph >::vertex_descriptor + vertex_descriptor; + + edge_t edges[] = { { 0, 1 }, { 1, 2 }, { 1, 2 }, { 2, 0 } }; + weight_type ws[] = { 3, 1, 1, 1 }; + undirected_graph g(edges, edges + 4, ws, 3, 4); + + weight_map_type weights = get(boost::edge_weight, g); + std::map< int, bool > parity; + boost::associative_property_map< std::map< int, bool > > parities( + parity); + std::map< vertex_descriptor, vertex_descriptor > assignment; + boost::associative_property_map< + std::map< vertex_descriptor, vertex_descriptor > > + assignments(assignment); + int w = boost::stoer_wagner_min_cut(g, weights, + boost::parity_map(parities).vertex_assignment_map(assignments)); + BOOST_TEST_EQ(w, 3); + const bool parity2 = get(parities, 2), parity0 = get(parities, 0); + BOOST_TEST_NE(parity2, parity0); + BOOST_TEST_EQ(parity0, get(parities, 1)); + } +} + +// example by Daniel Trebbien +void test2() +{ + edge_t edges[] = { { 5, 2 }, { 0, 6 }, { 5, 6 }, { 3, 1 }, { 0, 1 }, + { 6, 3 }, { 4, 6 }, { 2, 4 }, { 5, 3 } }; + weight_type ws[] = { 1, 3, 4, 6, 4, 1, 2, 5, 2 }; + undirected_graph g(edges, edges + 9, ws, 7, 9); + + std::map< int, bool > parity; + boost::associative_property_map< std::map< int, bool > > parities(parity); + int w = boost::stoer_wagner_min_cut( + g, get(boost::edge_weight, g), boost::parity_map(parities)); + BOOST_TEST_EQ(w, 3); + const bool parity2 = get(parities, 2); + BOOST_TEST_EQ(parity2, get(parities, 4)); + const bool parity5 = get(parities, 5); + BOOST_TEST_NE(parity2, parity5); + BOOST_TEST_EQ(parity5, get(parities, 3)); + BOOST_TEST_EQ(parity5, get(parities, 6)); + BOOST_TEST_EQ(parity5, get(parities, 1)); + BOOST_TEST_EQ(parity5, get(parities, 0)); +} + +// example by Daniel Trebbien +void test3() +{ + edge_t edges[] = { { 3, 4 }, { 3, 6 }, { 3, 5 }, { 0, 4 }, { 0, 1 }, + { 0, 6 }, { 0, 7 }, { 0, 5 }, { 0, 2 }, { 4, 1 }, { 1, 6 }, { 1, 5 }, + { 6, 7 }, { 7, 5 }, { 5, 2 }, { 3, 4 } }; + weight_type ws[] = { 0, 3, 1, 3, 1, 2, 6, 1, 8, 1, 1, 80, 2, 1, 1, 4 }; + undirected_graph g(edges, edges + 16, ws, 8, 16); + + weight_map_type weights = get(boost::edge_weight, g); + std::map< int, bool > parity; + boost::associative_property_map< std::map< int, bool > > parities(parity); + int w + = boost::stoer_wagner_min_cut(g, weights, boost::parity_map(parities)); + BOOST_TEST_EQ(w, 7); + const bool parity1 = get(parities, 1); + BOOST_TEST_EQ(parity1, get(parities, 5)); + const bool parity0 = get(parities, 0); + BOOST_TEST_NE(parity1, parity0); + BOOST_TEST_EQ(parity0, get(parities, 2)); + BOOST_TEST_EQ(parity0, get(parities, 3)); + BOOST_TEST_EQ(parity0, get(parities, 4)); + BOOST_TEST_EQ(parity0, get(parities, 6)); + BOOST_TEST_EQ(parity0, get(parities, 7)); +} + +void test4() +{ + typedef boost::graph_traits< + undirected_unweighted_graph >::vertex_descriptor vertex_descriptor; + typedef boost::graph_traits< undirected_unweighted_graph >::edge_descriptor + edge_descriptor; + + edge_t edges[] = { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 0, 4 }, { 1, 4 }, + { 1, 5 }, { 2, 6 }, { 3, 6 }, { 3, 7 }, { 4, 5 }, { 5, 6 }, { 6, 7 }, + { 0, 4 }, { 6, 7 } }; + undirected_unweighted_graph g(edges, edges + 14, 8); + + std::map< vertex_descriptor, bool > parity; + boost::associative_property_map< std::map< vertex_descriptor, bool > > + parities(parity); + std::map< vertex_descriptor, vertex_descriptor > assignment; + boost::associative_property_map< + std::map< vertex_descriptor, vertex_descriptor > > + assignments(assignment); + int w = boost::stoer_wagner_min_cut(g, + boost::make_constant_property< edge_descriptor >(weight_type(1)), + boost::vertex_assignment_map(assignments).parity_map(parities)); + BOOST_TEST_EQ(w, 2); + const bool parity0 = get(parities, 0); + BOOST_TEST_EQ(parity0, get(parities, 1)); + BOOST_TEST_EQ(parity0, get(parities, 4)); + BOOST_TEST_EQ(parity0, get(parities, 5)); + const bool parity2 = get(parities, 2); + BOOST_TEST_NE(parity0, parity2); + BOOST_TEST_EQ(parity2, get(parities, 3)); + BOOST_TEST_EQ(parity2, get(parities, 6)); + BOOST_TEST_EQ(parity2, get(parities, 7)); +} + +// Non regression test for github.com/boostorg/graph/issues/286 +void test5() +{ + edge_t edges[] = { { 0, 1 }, { 0, 2 }, { 0, 3 }, { 1, 2 }, { 1, 3 }, + { 2, 3 }, { 4, 5 }, { 4, 6 }, { 4, 7 }, { 5, 6 }, { 5, 7 }, { 6, 7 }, + { 0, 4 } }; + weight_type ws[] = { 3, 3, 3, 2, 2, 2, 3, 3, 3, 2, 2, 2, 6 }; + undirected_graph g(edges, edges + 13, ws, 8, 13); + + weight_map_type weights = get(boost::edge_weight, g); + std::map< int, bool > parity; + boost::associative_property_map< std::map< int, bool > > parities(parity); + int w + = boost::stoer_wagner_min_cut(g, weights, boost::parity_map(parities)); + BOOST_TEST_EQ(w, 6); + const bool parity0 = get(parities, 0); + BOOST_TEST_EQ(parity0, get(parities, 1)); + BOOST_TEST_EQ(parity0, get(parities, 2)); + BOOST_TEST_EQ(parity0, get(parities, 3)); + const bool parity4 = get(parities, 4); + BOOST_TEST_NE(parity0, parity4); + BOOST_TEST_EQ(parity4, get(parities, 5)); + BOOST_TEST_EQ(parity4, get(parities, 6)); + BOOST_TEST_EQ(parity4, get(parities, 7)); +} + +// The input for the `test_prgen` family of tests comes from a program, named +// `prgen`, that comes with a package of min-cut solvers by Chandra Chekuri, +// Andrew Goldberg, David Karger, Matthew Levine, and Cliff Stein. `prgen` was +// used to generate input graphs and the solvers were used to verify the return +// value of `boost::stoer_wagner_min_cut` on the input graphs. +// +// http://www.columbia.edu/~cs2035/code.html +// +// Note that it is somewhat more difficult to verify the parities because +// "`prgen` graphs" often have several min-cuts. This is why only the cut +// weight of the min-cut is verified. + +// 3 min-cuts +void test_prgen_20_70_2() +{ + typedef boost::graph_traits< undirected_graph >::vertex_descriptor + vertex_descriptor; + + std::ifstream ifs( + (test_dir + "/prgen_input_graphs/prgen_20_70_2.net").c_str()); + undirected_graph g; + boost::read_dimacs_min_cut( + g, get(boost::edge_weight, g), boost::dummy_property_map(), ifs); + + std::map< vertex_descriptor, std::size_t > component; + boost::associative_property_map< + std::map< vertex_descriptor, std::size_t > > + components(component); + BOOST_TEST_EQ(boost::connected_components(g, components), + 1U); // verify the connectedness assumption + + typedef boost::shared_array_property_map< weight_type, + boost::property_map< undirected_graph, + boost::vertex_index_t >::const_type > + distances_type; + distances_type distances = boost::make_shared_array_property_map( + num_vertices(g), weight_type(0), get(boost::vertex_index, g)); + typedef std::vector< vertex_descriptor >::size_type index_in_heap_type; + typedef boost::shared_array_property_map< index_in_heap_type, + boost::property_map< undirected_graph, + boost::vertex_index_t >::const_type > + indicesInHeap_type; + indicesInHeap_type indicesInHeap = boost::make_shared_array_property_map( + num_vertices(g), index_in_heap_type(-1), get(boost::vertex_index, g)); + boost::d_ary_heap_indirect< vertex_descriptor, 22, indicesInHeap_type, + distances_type, std::greater< weight_type > > + pq(distances, indicesInHeap); + + int w = boost::stoer_wagner_min_cut( + g, get(boost::edge_weight, g), boost::max_priority_queue(pq)); + BOOST_TEST_EQ(w, 3407); +} + +// 7 min-cuts +void test_prgen_50_40_2() +{ + typedef boost::graph_traits< undirected_graph >::vertex_descriptor + vertex_descriptor; + + std::ifstream ifs( + (test_dir + "/prgen_input_graphs/prgen_50_40_2.net").c_str()); + undirected_graph g; + boost::read_dimacs_min_cut( + g, get(boost::edge_weight, g), boost::dummy_property_map(), ifs); + + std::map< vertex_descriptor, std::size_t > component; + boost::associative_property_map< + std::map< vertex_descriptor, std::size_t > > + components(component); + BOOST_TEST_EQ(boost::connected_components(g, components), + 1U); // verify the connectedness assumption + + int w = boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g)); + BOOST_TEST_EQ(w, 10056); +} + +// 6 min-cuts +void test_prgen_50_70_2() +{ + typedef boost::graph_traits< undirected_graph >::vertex_descriptor + vertex_descriptor; + + std::ifstream ifs( + (test_dir + "/prgen_input_graphs/prgen_50_70_2.net").c_str()); + undirected_graph g; + boost::read_dimacs_min_cut( + g, get(boost::edge_weight, g), boost::dummy_property_map(), ifs); + + std::map< vertex_descriptor, std::size_t > component; + boost::associative_property_map< + std::map< vertex_descriptor, std::size_t > > + components(component); + BOOST_TEST_EQ(boost::connected_components(g, components), + 1U); // verify the connectedness assumption + + int w = boost::stoer_wagner_min_cut(g, get(boost::edge_weight, g)); + BOOST_TEST_EQ(w, 21755); +} + +int main(int argc, char* argv[]) +{ + if (BOOST_TEST(argc == 2)) + { + test_dir = argv[1]; + test0(); + test1(); + test2(); + test3(); + test4(); + test5(); + test_prgen_20_70_2(); + test_prgen_50_40_2(); + test_prgen_50_70_2(); + test_curated_min_cuts(); + } + return boost::report_errors(); +} diff --git a/test/subgraph.cpp b/test/subgraph.cpp index 50168a7a0..655baa3a7 100644 --- a/test/subgraph.cpp +++ b/test/subgraph.cpp @@ -54,7 +54,7 @@ int main(int, char*[]) typedef subgraph< graph_t > subgraph_t; typedef graph_traits< subgraph_t >::vertex_descriptor vertex_t; - mt19937 gen; + mt19937 gen(42); for (int t = 0; t < 100; t += 5) { subgraph_t g; diff --git a/test/subgraph_bundled.cpp b/test/subgraph_bundled.cpp index 14bf527e4..8cbf7c1d6 100644 --- a/test/subgraph_bundled.cpp +++ b/test/subgraph_bundled.cpp @@ -37,7 +37,7 @@ typedef graph_traits< Subgraph >::edge_iterator EdgeIter; int main(int, char*[]) { - mt19937 gen; + mt19937 gen(42); for (int t = 0; t < 100; t += 5) { Subgraph g; diff --git a/test/subgraph_global_local.cpp b/test/subgraph_global_local.cpp new file mode 100644 index 000000000..a37f11a04 --- /dev/null +++ b/test/subgraph_global_local.cpp @@ -0,0 +1,141 @@ +// Copyright (c) 2026 Arnaud Becheler +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +#include + +using namespace boost; + +template < typename Directedness > +using subgraph_of = subgraph< adjacency_list< vecS, vecS, Directedness, + property< vertex_color_t, int >, + property< edge_index_t, std::size_t, property< edge_weight_t, int > > > >; + +template < typename Directedness > +void test_descriptor_conversion() +{ + using graph_t = subgraph_of< Directedness >; + using vertex_t = typename graph_traits< graph_t >::vertex_descriptor; + using edge_t = typename graph_traits< graph_t >::edge_descriptor; + using vertex_iterator = typename graph_traits< graph_t >::vertex_iterator; + using edge_iterator = typename graph_traits< graph_t >::edge_iterator; + + // root: path 0-1-2-3, with edge indices assigned in insertion order. + graph_t root(4); + add_edge(0, 1, root); // edge index 0 + add_edge(1, 2, root); // edge index 1 + add_edge(2, 3, root); // edge index 2 + + // child g1 = {1, 2, 3}: induces edges (1,2) and (2,3), but not (0,1). + graph_t& g1 = root.create_subgraph(); + add_vertex(1, g1); + add_vertex(2, g1); + add_vertex(3, g1); + + // grandchild g1a = {2, 3}: induces only edge (2,3). + graph_t& g1a = g1.create_subgraph(); + add_vertex(2, g1a); + add_vertex(3, g1a); + + // invariant: for an edge in the subgraph, global_to_local(local_to_global(e)) + // must equal e, and its edge_index must be preserved. + edge_iterator ei, ei_end; + for (boost::tie(ei, ei_end) = edges(g1); ei != ei_end; ++ei) + { + edge_t e_local = *ei; + edge_t e_round = g1.global_to_local(g1.local_to_global(e_local)); + BOOST_TEST(e_round == e_local); + BOOST_TEST(get(edge_index, g1, e_local) == get(edge_index, g1, e_round)); + } + + // invariant: for a vertex in the subgraph, global_to_local(local_to_global(v)) + // must equal v, and its vertex_index must be preserved. + vertex_iterator vi, vi_end; + for (boost::tie(vi, vi_end) = vertices(g1); vi != vi_end; ++vi) + { + vertex_t v_local = *vi; + vertex_t v_round = g1.global_to_local(g1.local_to_global(v_local)); + BOOST_TEST(v_round == v_local); + BOOST_TEST(get(vertex_index, g1, v_local) == get(vertex_index, g1, v_round)); + } + + // invariant: a property written through a child must be readable from the + // root, because the whole tree shares one property store. + edge_t some_local = *edges(g1).first; + put(edge_weight, g1, some_local, 42); + BOOST_TEST(get(edge_weight, root, g1.local_to_global(some_local)) == 42); + + // invariant: find_vertex must report a present vertex as true, and an absent + // one as false with a null_vertex() descriptor. + BOOST_TEST(g1.find_vertex(1).second); // vertex 1 is in g1 + BOOST_TEST(!g1.find_vertex(0).second); // vertex 0 is not in g1 + BOOST_TEST(g1.find_vertex(0).first == graph_traits< graph_t >::null_vertex()); + + // invariant: find_edge must report false with a default descriptor for a + // root edge that is absent from the subgraph. + edge_t e01 = edge(0, 1, root).first; + BOOST_TEST(get(edge_index, root, e01) == 0u); + BOOST_TEST(g1.find_edge(e01).first == edge_t()); // absent -> default + BOOST_TEST(!g1.find_edge(e01).second); // absent -> false + + // invariant: edge round-trip identity must hold at any nesting depth, + // not just for direct children. + for (boost::tie(ei, ei_end) = edges(g1a); ei != ei_end; ++ei) + { + edge_t e_local = *ei; + BOOST_TEST(g1a.global_to_local(g1a.local_to_global(e_local)) == e_local); + } + + // invariant: a property written through a grandchild must reach the root. + edge_t g1a_local = *edges(g1a).first; + put(edge_weight, g1a, g1a_local, 7); + BOOST_TEST(get(edge_weight, root, g1a.local_to_global(g1a_local)) == 7); + + // invariant: an edge present in the parent but not the grandchild must + // report absent from the grandchild. + edge_t e12 = edge(1, 2, root).first; + BOOST_TEST(!g1a.find_edge(e12).second); +} + +// idiom: find_edge is the membership query; global_to_local is the transform to +// run once membership is confirmed. +template < typename Directedness > +void test_membership_query_then_convert() +{ + using graph_t = subgraph_of< Directedness >; + using edge_t = typename graph_traits< graph_t >::edge_descriptor; + + graph_t root(3); + add_edge(0, 1, root); // edge index 0 + add_edge(1, 2, root); // edge index 1 + + // sg = {1, 2}: induces edge (1,2), but not edge (0,1). + graph_t& sg = root.create_subgraph(); + add_vertex(1, sg); + add_vertex(2, sg); + + // Present edge: the query confirms membership, then the transform agrees + // with the local descriptor the query returned. + edge_t e12 = edge(1, 2, root).first; + std::pair< edge_t, bool > found = sg.find_edge(e12); + BOOST_TEST(found.second); + BOOST_TEST(sg.global_to_local(e12) == found.first); + + // Absent edge: the query reports it, so the transform is not run. + edge_t e01 = edge(0, 1, root).first; + BOOST_TEST(!sg.find_edge(e01).second); +} + +int main() +{ + test_descriptor_conversion< directedS >(); + test_descriptor_conversion< bidirectionalS >(); + test_membership_query_then_convert< directedS >(); + test_membership_query_then_convert< bidirectionalS >(); + return boost::report_errors(); +} diff --git a/test/subgraph_props.cpp b/test/subgraph_props.cpp index acf4a880b..5bbc859a8 100644 --- a/test/subgraph_props.cpp +++ b/test/subgraph_props.cpp @@ -124,7 +124,7 @@ struct TestBundles } }; -int main(int argc, char* argv[]) +int main() { TestProps::run(); TestBundles::run(); diff --git a/test/test_construction.hpp b/test/test_construction.hpp index 787fcf37c..b2fb590b8 100644 --- a/test/test_construction.hpp +++ b/test/test_construction.hpp @@ -7,6 +7,7 @@ #ifndef TEST_CONSTRUCTION_HPP #define TEST_CONSTRUCTION_HPP +#include #include #include @@ -25,7 +26,7 @@ void build_graph(Graph& g, Add, Label) // This matches MutableGraph, so just add some vertices. template < typename Graph > -void build_graph(Graph& g, boost::mpl::true_, boost::mpl::false_) +void build_graph(Graph& g, std::true_type, std::false_type) { using namespace boost; BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); @@ -41,7 +42,7 @@ void build_graph(Graph& g, boost::mpl::true_, boost::mpl::false_) // This will match labeled graphs. template < typename Graph > -void build_graph(Graph& g, boost::mpl::false_, boost::mpl::true_) +void build_graph(Graph& g, std::false_type, std::true_type) { using namespace boost; BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); @@ -69,7 +70,7 @@ void build_property_graph(Graph const& g, Add, Label) } template < typename Graph > -void build_property_graph(Graph const&, boost::mpl::true_, boost::mpl::false_) +void build_property_graph(Graph const&, std::true_type, std::false_type) { using namespace boost; BOOST_CONCEPT_ASSERT((VertexMutablePropertyGraphConcept< Graph >)); @@ -93,7 +94,7 @@ void build_property_graph(Graph const&, boost::mpl::true_, boost::mpl::false_) */ //@{ template < typename Graph, typename VertexSet > -void connect_graph(Graph& g, VertexSet const& verts, boost::mpl::false_) +void connect_graph(Graph& g, VertexSet const& verts, std::false_type) { using namespace boost; BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< Graph >)); @@ -113,7 +114,7 @@ void connect_graph(Graph& g, VertexSet const& verts, boost::mpl::false_) } template < typename Graph, typename VertexSet > -void connect_graph(Graph& g, VertexSet const& verts, boost::mpl::true_) +void connect_graph(Graph& g, VertexSet const& verts, std::true_type) { using namespace boost; BOOST_CONCEPT_ASSERT((AdjacencyMatrixConcept< Graph >)); diff --git a/test/test_destruction.hpp b/test/test_destruction.hpp index f70828a52..62490958b 100644 --- a/test/test_destruction.hpp +++ b/test/test_destruction.hpp @@ -7,6 +7,7 @@ #ifndef TEST_DESTRUCTION_HPP #define TEST_DESTRUCTION_HPP +#include #include #include @@ -23,7 +24,7 @@ void destroy_graph(Graph&, VertexSet const&, Remove, Label) // This matches MutableGraph, so just remove a vertex and then clear. template < typename Graph, typename VertexSet > void destroy_graph( - Graph& g, VertexSet const& verts, boost::mpl::true_, boost::mpl::false_) + Graph& g, VertexSet const& verts, std::true_type, std::false_type) { using namespace boost; BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); @@ -38,7 +39,7 @@ void destroy_graph( // This will match labeled graphs. template < typename Graph, typename VertexSet > void destroy_graph( - Graph& g, VertexSet const&, boost::mpl::false_, boost::mpl::true_) + Graph& g, VertexSet const&, std::false_type, std::true_type) { using namespace boost; BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >)); @@ -62,7 +63,7 @@ void destroy_graph( //@{ template < typename Graph, typename VertexSet > -void disconnect_graph(Graph& g, VertexSet const& verts, boost::mpl::false_) +void disconnect_graph(Graph& g, VertexSet const& verts, std::false_type) { using namespace boost; BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph >)); @@ -90,7 +91,7 @@ void disconnect_graph(Graph& g, VertexSet const& verts, boost::mpl::false_) } template < typename Graph, typename VertexSet > -void disconnect_graph(Graph& g, VertexSet const&, boost::mpl::true_) +void disconnect_graph(Graph& g, VertexSet const&, std::true_type) { using namespace boost; BOOST_CONCEPT_ASSERT((EdgeListGraphConcept< Graph >)); diff --git a/test/test_direction.hpp b/test/test_direction.hpp index 7cc0bad6d..17e27d13d 100644 --- a/test/test_direction.hpp +++ b/test/test_direction.hpp @@ -7,6 +7,7 @@ #ifndef TEST_DIRECTION_HPP #define TEST_DIRECTION_HPP +#include #include #include #include @@ -17,7 +18,7 @@ //@{ template < typename Graph, typename VertexSet > void test_outdirected_graph( - Graph const& g, VertexSet const& verts, boost::mpl::true_) + Graph const& g, VertexSet const& verts, std::true_type) { using namespace boost; BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >)); @@ -53,7 +54,7 @@ void test_outdirected_graph( } template < typename Graph, typename VertexSet > -void test_outdirected_graph(Graph const&, VertexSet const&, boost::mpl::false_) +void test_outdirected_graph(Graph const&, VertexSet const&, std::false_type) { } //@} @@ -64,7 +65,7 @@ void test_outdirected_graph(Graph const&, VertexSet const&, boost::mpl::false_) //@{ template < typename Graph, typename VertexSet > void test_indirected_graph( - Graph const& g, VertexSet const& verts, boost::mpl::true_) + Graph const& g, VertexSet const& verts, std::true_type) { using namespace boost; BOOST_CONCEPT_ASSERT((BidirectionalGraphConcept< Graph >)); @@ -96,7 +97,7 @@ void test_indirected_graph( } template < typename Graph, typename VertexSet > -void test_indirected_graph(Graph const&, VertexSet const&, boost::mpl::false_) +void test_indirected_graph(Graph const&, VertexSet const&, std::false_type) { } //@} @@ -106,7 +107,7 @@ void test_indirected_graph(Graph const&, VertexSet const&, boost::mpl::false_) */ template < typename Graph, typename VertexSet > void test_undirected_graph( - Graph const& g, VertexSet const& verts, boost::mpl::true_) + Graph const& g, VertexSet const& verts, std::true_type) { using namespace boost; BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >)); @@ -134,7 +135,7 @@ void test_undirected_graph( } template < typename Graph, typename VertexSet > -void test_undirected_graph(Graph const&, VertexSet const&, boost::mpl::false_) +void test_undirected_graph(Graph const&, VertexSet const&, std::false_type) { } //@} diff --git a/test/test_properties.hpp b/test/test_properties.hpp index 677fa4850..03186174b 100644 --- a/test/test_properties.hpp +++ b/test/test_properties.hpp @@ -7,12 +7,13 @@ #ifndef TEST_PROPERTIES_HPP #define TEST_PROPERTIES_HPP +#include #include template < typename T > T const& as_const(T& x) { return x; } template < typename T > void ignore(T const&) {} -template < typename Graph > void test_graph_bundle(Graph& g, boost::mpl::true_) +template < typename Graph > void test_graph_bundle(Graph& g, std::true_type) { using namespace boost; std::cout << "...test_graph_bundle\n"; @@ -28,7 +29,7 @@ template < typename Graph > void test_graph_bundle(Graph& g, boost::mpl::true_) ignore(cb2); } -template < typename Graph > void test_graph_bundle(Graph& g, boost::mpl::false_) +template < typename Graph > void test_graph_bundle(Graph& g, std::false_type) { } @@ -38,7 +39,7 @@ template < typename Graph > void test_graph_bundle(Graph& g, boost::mpl::false_) */ //@{ template < typename Graph, typename VertexSet > -void test_vertex_bundle(Graph& g, VertexSet const& verts, boost::mpl::true_) +void test_vertex_bundle(Graph& g, VertexSet const& verts, std::true_type) { using namespace boost; BOOST_CONCEPT_ASSERT((GraphConcept< Graph >)); @@ -68,7 +69,7 @@ void test_vertex_bundle(Graph& g, VertexSet const& verts, boost::mpl::true_) } template < typename Graph, typename VertexSet > -void test_vertex_bundle(Graph&, VertexSet const&, boost::mpl::false_) +void test_vertex_bundle(Graph&, VertexSet const&, std::false_type) { } //@} @@ -79,7 +80,7 @@ void test_vertex_bundle(Graph&, VertexSet const&, boost::mpl::false_) */ //@{ template < typename Graph, typename VertexSet > -void test_edge_bundle(Graph& g, VertexSet const& verts, boost::mpl::true_) +void test_edge_bundle(Graph& g, VertexSet const& verts, std::true_type) { using namespace boost; BOOST_CONCEPT_ASSERT((GraphConcept< Graph >)); @@ -110,7 +111,7 @@ void test_edge_bundle(Graph& g, VertexSet const& verts, boost::mpl::true_) } template < typename Graph, typename VertexSet > -void test_edge_bundle(Graph&, VertexSet const&, boost::mpl::false_) +void test_edge_bundle(Graph&, VertexSet const&, std::false_type) { } //@} diff --git a/test/tiernan_all_cycles.cpp b/test/tiernan_all_cycles.cpp index 6705bb7e9..41431cd8b 100644 --- a/test/tiernan_all_cycles.cpp +++ b/test/tiernan_all_cycles.cpp @@ -49,7 +49,7 @@ template < typename Graph > void test() // of edge connection. static const size_t N = 20; static const double P = 0.1; - boost::minstd_rand rng; + boost::minstd_rand rng(42); Graph g(er(rng, N, P), er(), N); renumber_indices(g); diff --git a/test/transitive_closure_test.cpp b/test/transitive_closure_test.cpp index 8698a928e..ecf6977c4 100644 --- a/test/transitive_closure_test.cpp +++ b/test/transitive_closure_test.cpp @@ -1,179 +1,167 @@ // Copyright (C) 2001 Vladimir Prus // Copyright (C) 2001 Jeremy Siek +// Copyright (c) 2026 Arnaud Becheler // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include -#include -#include +#include +#include +#include +#include #include #include -#include #include #include -#include -using namespace std; -using namespace boost; +template < class Graph > +using vertex_iter_t = typename boost::graph_traits< Graph >::vertex_iterator; + +template < class Graph > +using out_edge_iter_t = typename boost::graph_traits< Graph >::out_edge_iterator; + +template < class Graph > +using adjacency_iter_t = typename boost::graph_traits< Graph >::adjacency_iterator; + +template < class Graph > +using vertex_desc_t = typename boost::graph_traits< Graph >::vertex_descriptor; + +template < class Graph > +using edge_desc_t = typename boost::graph_traits< Graph >::edge_descriptor; -void generate_graph(int n, double p, vector< vector< int > >& r1) +template < class Graph > +using degree_size_t = typename boost::graph_traits< Graph >::degree_size_type; + +template < class Generator > +void generate_graph(int n, double p, std::vector< std::vector< int > >& r1, Generator& uniform01) { - static class - { - public: - double operator()() { return double(rand()) / RAND_MAX; } - } gen; r1.clear(); r1.resize(n); for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) - if (gen() < p) + if (uniform01() < p) r1[i].push_back(j); } template < class Graph > -typename graph_traits< Graph >::degree_size_type num_incident( - typename graph_traits< Graph >::vertex_descriptor u, - typename graph_traits< Graph >::vertex_descriptor v, const Graph& g) +degree_size_t< Graph > num_incident(vertex_desc_t< Graph > u, vertex_desc_t< Graph > v, const Graph& g) { - typename graph_traits< Graph >::degree_size_type d = 0; - typename graph_traits< Graph >::out_edge_iterator i, i_end; - for (boost::tie(i, i_end) = out_edges(u, g); i != i_end; ++i) + using boost::target; // ADL also finds std::target for pair edges + degree_size_t< Graph > d = 0; + out_edge_iter_t< Graph > i, i_end; + for (boost::tie(i, i_end) = boost::out_edges(u, g); i != i_end; ++i) if (target(*i, g) == v) ++d; return d; } -// (i,j) is in E' iff j is reachable from i -// Hmm, is_reachable does not detect when there is a non-trivial path -// from i to i. It always returns true for is_reachable(i,i). -// This needs to be fixed/worked around. +// true iff g has a path of at least one edge from u to v. is_reachable treats u +// as reachable from itself, so a cycle through u is detected via its neighbors. +template < typename Graph > +bool has_nontrivial_path(Graph& g, vertex_desc_t< Graph > u, vertex_desc_t< Graph > v) +{ + auto reaches = [&](vertex_desc_t< Graph > from, vertex_desc_t< Graph > to) { + std::vector< boost::default_color_type > color(boost::num_vertices(g)); + auto index_map = boost::get(boost::vertex_index, g); + auto color_map = boost::make_iterator_property_map(color.begin(), index_map); + return boost::is_reachable(from, to, g, color_map); + }; + + if (u != v) + return reaches(u, v); + + adjacency_iter_t< Graph > k, k_end; + for (boost::tie(k, k_end) = boost::adjacent_vertices(u, g); k != k_end; ++k) + if (reaches(*k, u)) + return true; + return false; +} + +// tc must contain edge (i, j) exactly when g has a nontrivial path from i to j, +// and never as a duplicate (num_incident, not mere presence) template < typename Graph, typename GraphTC > bool check_transitive_closure(Graph& g, GraphTC& tc) { - typename graph_traits< Graph >::vertex_iterator i, i_end; - for (boost::tie(i, i_end) = vertices(g); i != i_end; ++i) + vertex_iter_t< Graph > i, i_end; + for (boost::tie(i, i_end) = boost::vertices(g); i != i_end; ++i) { - typename graph_traits< Graph >::vertex_iterator j, j_end; - for (boost::tie(j, j_end) = vertices(g); j != j_end; ++j) + vertex_iter_t< Graph > j, j_end; + for (boost::tie(j, j_end) = boost::vertices(g); j != j_end; ++j) { - bool g_has_edge; - typename graph_traits< Graph >::edge_descriptor e_g; - typename graph_traits< Graph >::degree_size_type num_tc; - boost::tie(e_g, g_has_edge) = edge(*i, *j, g); - num_tc = num_incident(*i, *j, tc); - if (*i == *j) - { - if (g_has_edge) - { - if (num_tc != 1) - return false; - } - else - { - bool can_reach = false; - typename graph_traits< Graph >::adjacency_iterator k, k_end; - for (boost::tie(k, k_end) = adjacent_vertices(*i, g); - k != k_end; ++k) - { - std::vector< default_color_type > color_map_vec( - num_vertices(g)); - if (is_reachable(*k, *i, g, - boost::make_iterator_property_map( - color_map_vec.begin(), - get(boost::vertex_index, g)))) - { - can_reach = true; - break; - } - } - if (can_reach) - { - if (num_tc != 1) - { - std::cout << "1. " << *i << std::endl; - return false; - } - } - else - { - if (num_tc != 0) - { - std::cout << "2. " << *i << std::endl; - return false; - } - } - } - } - else - { - std::vector< default_color_type > color_map_vec( - num_vertices(g)); - if (is_reachable(*i, *j, g, - boost::make_iterator_property_map(color_map_vec.begin(), - get(boost::vertex_index, g)))) - { - if (num_tc != 1) - return false; - } - else - { - if (num_tc != 0) - return false; - } - } + degree_size_t< Graph > expected = has_nontrivial_path(g, *i, *j) ? 1 : 0; + if (num_incident(*i, *j, tc) != expected) + return false; } } return true; } -bool test(int n, double p) +// verifies transitive_closure agrees with is_reachable +// if both are bugged, it would pass +template < class Generator > +bool is_random_graph_closure_correct(int n, double p, Generator& uniform01) { - vector< vector< int > > g1, g1_tc; - generate_graph(n, p, g1); - cout << "Created graph with " << n << " vertices.\n"; + std::vector< std::vector< int > > g1, g1_tc; + generate_graph(n, p, g1, uniform01); - vector< vector< int > > g1_c(g1); + boost::transitive_closure(g1, g1_tc); - { - boost::timer::auto_cpu_timer t; - cout << "transitive_closure" << endl; - transitive_closure( - g1, g1_tc, vertex_index_map(get(boost::vertex_index, g1))); - } - - if (check_transitive_closure(g1, g1_tc)) + if (check_transitive_closure(g1, g1_tc)){ return true; - else - { - cout << "Original graph was "; - print_graph(g1, get(boost::vertex_index, g1)); - cout << "Result is "; - print_graph(g1_tc, get(boost::vertex_index, g1_tc)); + } else { + std::cout << "failing graph: "; + boost::print_graph(g1, boost::get(boost::vertex_index, g1)); + std::cout << "computed closure: "; + boost::print_graph(g1_tc, boost::get(boost::vertex_index, g1_tc)); return false; } } +// closure of a fixed graph checked against a hand-computed edge set +// oracle independent of is_reachable +bool is_fixed_graph_closure_correct() +{ + using graph_t = boost::adjacency_list<>; + graph_t g(5), g_tc; + boost::add_edge(0, 2, g); + boost::add_edge(1, 0, g); + boost::add_edge(1, 2, g); + boost::add_edge(1, 4, g); + boost::add_edge(3, 0, g); + boost::add_edge(3, 2, g); + boost::add_edge(4, 2, g); + boost::add_edge(4, 3, g); + + boost::transitive_closure(g, g_tc); + + constexpr std::pair< int, int > expected[] + = { { 0, 2 }, { 1, 0 }, { 1, 2 }, { 1, 3 }, { 1, 4 }, { 3, 0 }, + { 3, 2 }, { 4, 0 }, { 4, 2 }, { 4, 3 } }; + + if (boost::num_edges(g_tc) != sizeof(expected) / sizeof(expected[0])) + return false; + for (const std::pair< int, int >& e : expected) + if (!boost::edge(e.first, e.second, g_tc).second) + return false; + return true; +} + int main() { - srand(time(0)); - static class - { - public: - double operator()() { return double(rand()) / RAND_MAX; } - } gen; + std::mt19937 engine(42); + std::uniform_real_distribution< double > dist(0.0, 1.0); + auto uniform01 = [&] { return dist(engine); }; - for (size_t i = 0; i < 100; ++i) + for (std::size_t i = 0; i < 100; ++i) { - int n = 0 + int(20 * gen()); - double p = gen(); - if (!test(n, p)) - { - cout << "Failed." << endl; - return 1; - } + int n = 0 + int(20 * uniform01()); + double p = uniform01(); + BOOST_TEST(is_random_graph_closure_correct(n, p, uniform01)); } - cout << "Passed." << endl; + + BOOST_TEST(is_fixed_graph_closure_correct()); + + return boost::report_errors(); } diff --git a/test/transitive_closure_test2.cpp b/test/transitive_closure_test2.cpp deleted file mode 100644 index 8b7127918..000000000 --- a/test/transitive_closure_test2.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2004 Jeremy Siek -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#include -#include -#include -#include -using namespace std; - -using namespace boost; -typedef adjacency_list<> graph_t; - -int main(int argc, char* argv[]) -{ - graph_t g(5), g_TC; - - add_edge(0, 2, g); - add_edge(1, 0, g); - add_edge(1, 2, g); - add_edge(1, 4, g); - add_edge(3, 0, g); - add_edge(3, 2, g); - add_edge(4, 2, g); - add_edge(4, 3, g); - - transitive_closure(g, g_TC); - - cout << "original graph: 0->2, 1->0, 1->2, 1->4, 3->0, 3->2, 4->2, 4->3" - << endl; - cout << "transitive closure: "; - graph_t::edge_iterator i, iend; - for (boost::tie(i, iend) = edges(g_TC); i != iend; ++i) - { - cout << source(*i, g_TC) << "->" << target(*i, g_TC) << " "; - } - cout << endl; -} diff --git a/test/two_graphs_common_spanning_trees_test.cpp b/test/two_graphs_common_spanning_trees_test.cpp index 0a4609487..19bb517fe 100644 --- a/test/two_graphs_common_spanning_trees_test.cpp +++ b/test/two_graphs_common_spanning_trees_test.cpp @@ -100,7 +100,7 @@ void two_graphs_common_spanning_trees_test() } -int main(int argc, char** argv) +int main() { boost::two_graphs_common_spanning_trees_test(); return boost::report_errors(); diff --git a/test/undirected_dfs.cpp b/test/undirected_dfs.cpp index 8d2f86465..097d53420 100644 --- a/test/undirected_dfs.cpp +++ b/test/undirected_dfs.cpp @@ -126,7 +126,7 @@ template < typename Graph > struct dfs_test typename Traits::vertex_iterator vi, vi_end, ui, ui_end; typename Traits::edge_iterator ei, ei_end; - boost::mt19937 gen; + boost::mt19937 gen(42); for (i = 0; i < max_V; ++i) for (j = 0; j < i * i; ++j) diff --git a/test/undirected_dfs_visitor.cpp b/test/undirected_dfs_visitor.cpp index da43b2950..f152c813b 100644 --- a/test/undirected_dfs_visitor.cpp +++ b/test/undirected_dfs_visitor.cpp @@ -38,10 +38,10 @@ struct DFSVisitorLogger : boost::default_dfs_visitor { log.push_back("edge (" + std::to_string(boost::source(e, g)) + "," + std::to_string(boost::target(e, g)) + ") " + event); } - void discover_vertex(Vertex v, const Graph &g) { + void discover_vertex(Vertex v, const Graph &) { log_vertex(v, "discovered"); } - void finish_vertex(Vertex v, const Graph &g) { + void finish_vertex(Vertex v, const Graph &) { log_vertex(v, "finished"); } void examine_edge(Edge e, const Graph &g) { @@ -95,7 +95,7 @@ int main() { // check if all vertices and edges have been visited in the correct order BOOST_TEST(expected_answer.size() == actual_answer.size()); if (expected_answer.size() == actual_answer.size()) { - for (int i = 0; i < expected_answer.size(); ++i) { + for (std::size_t i = 0; i < expected_answer.size(); ++i) { BOOST_TEST(expected_answer[i] == actual_answer[i]); } } diff --git a/test/vf2_sub_graph_iso_test.cpp b/test/vf2_sub_graph_iso_test.cpp index 01020e955..f36139fb1 100644 --- a/test/vf2_sub_graph_iso_test.cpp +++ b/test/vf2_sub_graph_iso_test.cpp @@ -67,7 +67,7 @@ void randomly_permute_graph(Graph1& g1, const Graph2& g2) typedef typename graph_traits< Graph1 >::vertex_iterator vertex_iterator; typedef typename graph_traits< Graph2 >::edge_iterator edge_iterator; - random_generator_type gen; + random_generator_type gen(42); // Decide new order std::vector< vertex2 > orig_vertices; @@ -109,7 +109,7 @@ void generate_random_digraph(Graph& g, double edge_probability, BOOST_TEST(0 <= max_vertex_name); typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator; - random_generator_type random_gen; + random_generator_type random_gen(42); boost::uniform_real< double > dist_real(0.0, 1.0); boost::variate_generator< random_generator_type&, boost::uniform_real< double > > diff --git a/test/vf2_sub_graph_iso_test_2.cpp b/test/vf2_sub_graph_iso_test_2.cpp index 437150a85..0fa9ab766 100644 --- a/test/vf2_sub_graph_iso_test_2.cpp +++ b/test/vf2_sub_graph_iso_test_2.cpp @@ -201,7 +201,7 @@ BOOST_TEST(!got_hit); } } -int main(int argc, char* argv[]) +int main() { test_empty_graph_cases(); test_return_value();