[
  {
    "path": ".ci/Dockerfile.static",
    "content": "FROM ubuntu:20.04\n\nARG BOOST_VERSION=1_68_0\n\nSHELL [\"/bin/bash\", \"-c\"]\n\n# Install apt packages\nRUN export DEBIAN_FRONTEND=noninteractive\nRUN ln -fs /usr/share/zoneinfo/America/New_York /etc/localtime\nRUN apt-get -y update && \\\n    apt-get -y install \\\n        autoconf \\\n        build-essential \\\n        clang \\\n        clang-format \\\n        cmake \\\n        curl \\\n        git \\\n        libprotobuf-dev \\\n        libprotoc-dev \\\n        libtool \\\n        protobuf-compiler \\\n        unzip \\\n        wget \\\n        software-properties-common\nRUN TARBALL=boost_${BOOST_VERSION}.tar.bz2 && \\\n    curl -L https://archives.boost.io/release/1.68.0/source/${TARBALL} \\\n        -o /tmp/${TARBALL} --fail && \\\n    tar xf /tmp/${TARBALL} --one-top-level=/tmp && \\\n    cd /tmp/boost_${BOOST_VERSION} && \\\n    ./bootstrap.sh --prefix=/usr/local && \\\n    ./b2 include=/usr/include/python3.8 link=static install && \\\n    cd / && \\\n    rm -rf /tmp/${TARBALL} /tmp/boost_${BOOST_VERSION}\n"
  },
  {
    "path": ".ci/Dockerfile.ubuntu20",
    "content": "FROM ubuntu:20.04\n\n# Install apt packages\nENV VIRTUAL_ENV=/opt/venv\nENV PATH=\"$VIRTUAL_ENV/bin:$PATH\"\nRUN apt-get -y update && \\\n    DEBIAN_FRONTEND=noninteractive \\\n    apt-get -y install \\\n        autoconf \\\n        build-essential \\\n        clang \\\n        clang-format \\\n        cmake \\\n        curl \\\n        default-jdk \\\n        doxygen \\\n        elpa-paredit \\\n        emacs-nox \\\n        git \\\n        graphviz \\\n        libprotobuf-dev \\\n        libprotoc-dev \\\n        libtool \\\n        libboost-dev \\\n        maven \\\n        protobuf-compiler \\\n        python3 \\\n        python3-pip \\\n        python3-setuptools \\\n        python3-venv \\\n        wget \\\n        software-properties-common \\\n        sbcl \\\n        slime && \\\n    python3 -m venv $VIRTUAL_ENV && \\\n    python3 -m pip install --upgrade pip\n\n# The default version of maven from the ubuntu repositories contains a bug that\n# causes warnings about illegal reflective accesses. The build on apache's\n# website fixes this bug, so we use that build instead.\nRUN wget https://archive.apache.org/dist/maven/maven-3/3.9.3/binaries/apache-maven-3.9.3-bin.tar.gz -P /tmp\nRUN tar xf /tmp/apache-maven-*.tar.gz -C /opt\nRUN update-alternatives --install /usr/bin/mvn mvn /opt/apache-maven-3.9.3/bin/mvn 392\n\n# Install python dependencies\nCOPY python/requirements-dev.txt /tmp/requirements-dev.txt\nRUN pip3 install -r /tmp/requirements-dev.txt\n"
  },
  {
    "path": ".ci/Dockerfile.ubuntu22",
    "content": "FROM ubuntu:22.04\n\nENV VIRTUAL_ENV=/opt/venv\nENV PATH=\"$VIRTUAL_ENV/bin:$PATH\"\nRUN apt-get -y update && \\\n    DEBIAN_FRONTEND=noninteractive \\\n    apt-get -y install \\\n        autoconf \\\n        build-essential \\\n        clang \\\n        clang-format \\\n        cmake \\\n        curl \\\n        default-jdk \\\n        doxygen \\\n        elpa-paredit \\\n        emacs-nox \\\n        git \\\n        graphviz \\\n        libprotobuf-dev \\\n        libprotoc-dev \\\n        libtool \\\n        libboost-dev \\\n        maven \\\n        protobuf-compiler \\\n        python3 \\\n        python3-pip \\\n        python3-setuptools \\\n        python3-venv \\\n        wget \\\n        software-properties-common \\\n        sbcl \\\n        slime && \\\n    python3 -m venv $VIRTUAL_ENV && \\\n    python3 -m pip install --upgrade pip\n\nCOPY python/requirements-dev.txt /tmp/requirements-dev.txt\nRUN pip3 install -r /tmp/requirements-dev.txt\n"
  },
  {
    "path": ".ci/Dockerfile.ubuntu24",
    "content": "FROM ubuntu:24.04\n\nENV VIRTUAL_ENV=/opt/venv\nENV PATH=\"$VIRTUAL_ENV/bin:$PATH\"\nRUN apt-get -y update && \\\n    DEBIAN_FRONTEND=noninteractive \\\n    apt-get -y install \\\n        autoconf \\\n        build-essential \\\n        clang \\\n        clang-format \\\n        cmake \\\n        curl \\\n        default-jdk \\\n        doxygen \\\n        elpa-paredit \\\n        emacs-nox \\\n        git \\\n        graphviz \\\n        libprotobuf-dev \\\n        libprotoc-dev \\\n        libtool \\\n        libboost-dev \\\n        # As of 24.04.1 LTS, the clang package depends on libstdc++-13-dev but\n        # appears to be compiled for libstdc++-14-dev, which we need to install\n        # explicitly here.\n        libstdc++-14-dev \\\n        maven \\\n        protobuf-compiler \\\n        python3 \\\n        python3-pip \\\n        python3-setuptools \\\n        python3-venv \\\n        wget \\\n        software-properties-common \\\n        sbcl \\\n        slime && \\\n    python3 -m venv $VIRTUAL_ENV && \\\n    python3 -m pip install --upgrade pip\n\nCOPY python/requirements-dev.txt /tmp/requirements-dev.txt\nRUN pip3 install -r /tmp/requirements-dev.txt\n"
  },
  {
    "path": ".ci/PKGBUILD",
    "content": "# Contributor: Eric Schulte <eschulte@grammatech.com>\n# Maintainer: Eric Schulte <eschulte@grammatech.com>\n_srcname=gtirb\npkgname=gtirb-git\npkgver=v1.4.7.r0.gb3094954\npkgrel=1\npkgdesc=\"GrammaTech Intermediate Representation for Binaries\"\narch=('x86_64')\nurl=\"https://github.com/grammatech/gtirb\"\nlicense=('MIT')\ndepends=('protobuf' 'python-networkx')\nmakedepends=('git' 'cmake' 'python' 'doxygen' 'graphviz' 'boost')\nprovides=('gtirb')\nsource=('git://github.com/grammatech/gtirb.git')\nsha512sums=('SKIP')\n\npkgver() {\n  cd \"$_srcname\"\n  git describe --long --tags --exclude \"gt/*\" | sed 's/\\([^-]*-g\\)/r\\1/;s/[-:/ ]/./g'\n}\n\nbuild() {\n    cd \"$_srcname/\"\n    cmake . -Bbuild -DCMAKE_INSTALL_PREFIX=/usr -DGTIRB_CL_API=OFF \\\n      -DCMAKE_BUILD_TYPE=${BUILD_TYPE-RelWithDebInfo} \\\n      -DCMAKE_CXX_COMPILER=${COMPILER-g++}\n    cmake --build build --target all doc\n}\n\npackage() {\n  cd \"$_srcname/\"\n  make -Cbuild DESTDIR=\"$pkgdir\" install\n  mkdir -p \"$pkgdir\"/usr/share/doc/$_srcname\n  cp -R build/doc/html/ \"$pkgdir\"/usr/share/doc/$_srcname\n}\n"
  },
  {
    "path": ".ci/adjust-coverage-paths.py",
    "content": "#!/usr/bin/env python3\n\nimport os\nfrom argparse import ArgumentParser\nfrom pathlib import Path\nfrom xml.etree import ElementTree\n\nparser = ArgumentParser(\n    description=\"\"\"\n    Adjusts the source paths in coverage.xml to satisfy GitLab's expectations.\n    Specifically, it removes the build tree prefix from the sources and\n    replaces it with the source tree prefix. These prefixes are determined via\n    command-line arguments or CI environment variables.\n    \"\"\"\n)\nparser.add_argument(\n    \"coverage\",\n    metavar=\"coverage.xml\",\n    type=Path,\n    help=\"path of cobertura coverage file to fix\",\n)\ngroup = parser.add_mutually_exclusive_group(required=True)\ngroup.add_argument(\n    \"-i\", \"--in-place\", action=\"store_true\", help=\"rewrite coverage in place\"\n)\ngroup.add_argument(\n    \"-o\", \"--output\", metavar=\"file\", help=\"write modified coverage to file\"\n)\nparser.add_argument(\n    \"--source-dir\",\n    metavar=\"path\",\n    default=os.environ.get(\"CI_PROJECT_DIR\"),\n    help=\"root of the GTIRB repository\",\n)\nparser.add_argument(\n    \"--build-dir\",\n    metavar=\"path\",\n    type=Path,\n    help=\"path where coverage was run (default coverage.xml parent directory)\",\n)\nargs = parser.parse_args()\n\nif args.source_dir is None:\n    parser.error(\"either --source-dir or CI_PROJECT_DIR is required\")\nargs.source_dir = Path(args.source_dir).resolve()\n\nif args.build_dir is None:\n    args.build_dir = args.coverage.parent\nargs.build_dir = args.build_dir.resolve()\n\net = ElementTree.parse(args.coverage)\nfor source in et.iter(\"source\"):\n    if source.text:\n        relpath = Path(source.text).relative_to(args.build_dir)\n        fixed = str(Path(args.source_dir, relpath))\n        print(\"mapping\", source.text, \"to\", fixed)\n        source.text = fixed\n\nif args.output:\n    et.write(args.output)\nelse:\n    et.write(args.coverage)\n"
  },
  {
    "path": ".ci/build.py",
    "content": "#!/usr/bin/env python\nimport subprocess\nimport sys\n\nimport conanfile\n\n\ndef run_conan(args):\n    cmd = [\"conan\"] + args\n    print(\"running: %s\" % \" \".join(cmd))\n    sys.stdout.flush()\n    subprocess.check_call(cmd)\n\n\ndef build(argv):\n    props = conanfile.Properties()\n    run_conan([\"create\", \".\", props.conan_ref] + argv)\n    archived_channels = props.archived_channels\n    if props.conan_channel in archived_channels:\n        run_conan(\n            [\"upload\", props.conan_recipe, \"--all\", \"--remote\", \"gitlab\"]\n        )\n    else:\n        print(\n            \"Conan channel not archived. Update archived_branches in \"\n            \"conanfile.py to get archival.\"\n        )\n        print(\"archived channels: \")\n        print(*archived_channels, sep=\", \")\n        print(\"channel built: \" + props.conan_channel)\n\n\nif __name__ == \"__main__\":\n    build(sys.argv[1:])\n"
  },
  {
    "path": ".ci/gitlab-ci.yml",
    "content": "variables:\n  # The IMAGE_TAG is derived from the branch name so that if a branch modifies\n  # the CI images, it builds and runs using the new images without conflicting\n  # with master.\n  IMAGE_TAG: \"$CI_COMMIT_REF_SLUG\"\n  GIT_SUBMODULE_STRATEGY: recursive\n  EXTRA_INDEX_URL: https://__token__:$GL_PKG_API_TOKEN@git.grammatech.com/api/v4/projects/1587/packages/pypi/simple\n  # The follow two variables are used by the package-uploader.\n  PROJECT_ID: $CI_PROJECT_ID\n  PIPELINE_ID: $CI_PIPELINE_ID\n  CONAN_PASSWORD: $CI_JOB_TOKEN\n  CONAN_VERSION: \"1.59\"\n  # Limit build parallelism to avoid overwhelming CI servers.\n  MAKE_JOBS: 8\n\nstages:\n  - build-images\n  - prebuild\n  - build\n  - build-installers\n  - test-setup\n  - test-packages1\n  - test-packages2\n  - deploy\n  - deploy-apt\n  - upload\n\ndefault:\n  tags: [shared]\n\n.build-ci-image: &build-ci-image\n  stage: build-images\n  image:\n    name: quay.io/buildah/stable\n  script:\n    # Configure authentication credentials for GitLab\n    - buildah login -u \"$CI_REGISTRY_USER\" -p \"$CI_REGISTRY_PASSWORD\" \"$CI_REGISTRY\"\n    - buildah login -u \"$DOCKERHUB_USERNAME\" -p \"$DOCKERHUB_PASSWORD\" https://index.docker.io/v1/\n    # Build our image (using a cache if available)\n    - >-\n      buildah build\n      -f \"$CI_PROJECT_DIR/$DOCKERFILE_PATH\"\n      --cache-from \"$DOCKER_REGISTRY/$CI_PROJECT_PATH/$IMAGE_NAME/cache\"\n      --cache-to \"$DOCKER_REGISTRY/$CI_PROJECT_PATH/$IMAGE_NAME/cache\"\n      --layers\n      --tag \"$DOCKER_REGISTRY/$CI_PROJECT_PATH/$IMAGE_NAME:$IMAGE_TAG\"\n      \"$CI_PROJECT_DIR\"\n    # Push to our internal registry\n    - buildah push \"$DOCKER_REGISTRY/$CI_PROJECT_PATH/$IMAGE_NAME:$IMAGE_TAG\"\n    # If we're on the master branch, also push the latest tag.\n    - >-\n      if [ \"$CI_COMMIT_BRANCH\" = \"$CI_DEFAULT_BRANCH\" ]; then\n        buildah push \"$DOCKER_REGISTRY/$CI_PROJECT_PATH/$IMAGE_NAME:$IMAGE_TAG\" \\\n            \"$DOCKER_REGISTRY/$CI_PROJECT_PATH/$IMAGE_NAME:latest\"\n      fi\n\nbuild-ci-image-ubuntu20:\n  <<: *build-ci-image\n  variables:\n    DOCKERFILE_PATH: .ci/Dockerfile.ubuntu20\n    IMAGE_NAME: ubuntu20\n\nbuild-ci-image-ubuntu22:\n  <<: *build-ci-image\n  variables:\n    DOCKERFILE_PATH: .ci/Dockerfile.ubuntu22\n    IMAGE_NAME: ubuntu22\n\nbuild-ci-image-ubuntu24:\n  <<: *build-ci-image\n  variables:\n    DOCKERFILE_PATH: .ci/Dockerfile.ubuntu24\n    IMAGE_NAME: ubuntu24\n\nbuild-ci-image-static:\n  <<: *build-ci-image\n  variables:\n    DOCKERFILE_PATH: .ci/Dockerfile.static\n    IMAGE_NAME: static\n\ncheck-format:\n  stage: prebuild\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu20:$IMAGE_TAG\n  script:\n    - |+\n      pre-commit run --all-files --show-diff-on-failure || ( (cat <<EOF\n      ================================================================================\n      If this stage fails, the formatting of your changes may be incorrect.\n      To automatically format your files, install pre-commit:\n          pip3 install pre-commit\n          pre-commit install\n      pre-commit will now automatically format any files before commit.\n      To fix any misformatted files, run:\n          pre-commit run --all-files\n      And then commit any changes.\n      More information regarding pre-commit can be found at https://pre-commit.com.\n\n      NOTE FOR PROJECTS WITH C/C++ CODE:\n      pre-commit will by default use the correct version of every formatting tool\n      EXCEPT FOR clang-format. You need to ensure the version of clang-format you\n      use is EXACTLY version 10.0.0. This is available in Ubuntu 20 by default.\n\n      See also:\n          https://git.grammatech.com/research/meta/-/wikis/infrastructure/infrastructure#running-ci-jobs-locally-for-debugging\n          http://otsego.grammatech.com/u4/Videos/2020-09-11-Lunchtime-Seminar/\n      ================================================================================\n      EOF\n      ) && exit 1)\n\nbuild-docs:\n  stage: build\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu24:$IMAGE_TAG\n  artifacts:\n    name: \"$CI_COMMIT_REF_NAME-$CI_JOB_NAME\"\n    paths:\n      - html\n  script:\n    - pip install -r python/requirements-dev.txt -r python/requirements-mypy.txt\n    - cmake -Bbuild . -DGTIRB_ENABLE_TESTS=OFF\n    - cd build\n    - pip install ./python/\n    - make doc\n    - mv doc/html ..\n\n.build-template: &build\n  stage: build\n  image: $DOCKER_REGISTRY/rewriting/gtirb/$IMAGE_NAME:$IMAGE_TAG\n  artifacts:\n    name: \"$CI_COMMIT_REF_NAME-$CI_JOB_NAME\"\n    paths:\n      - build\n  script:\n    - mkdir build\n    - cd build\n    - RELEASE_VERSION=OFF\n    - '[[ ! $CI_COMMIT_REF_NAME =~ ^release-.* ]] || RELEASE_VERSION=ON'\n    - >\n      cmake ../\n      -DCMAKE_BUILD_TYPE=$BUILD_TYPE\n      -DCMAKE_CXX_COMPILER=${CXX_COMPILER:-g++}\n      -DCPACK_DEBIAN_PACKAGE_RELEASE=\"$(lsb_release -sc)\"\n      -DENABLE_CODE_COVERAGE=${ENABLE_CODE_COVERAGE:-OFF}\n      -DGTIRB_BUILD_SHARED_LIBS=${GTIRB_BUILD_SHARED_LIBS:-ON}\n      -DGTIRB_PACKAGE_POLICY=$PACKAGE_POLICY\n      -DGTIRB_RELEASE_VERSION=$RELEASE_VERSION\n      -DGTIRB_STRIP_DEBUG_SYMBOLS=On\n      -DGTIRB_CL_API=${GTIRB_CL_API:-OFF}\n      -DGTIRB_CXX_API=${GTIRB_CXX_API:-OFF}\n      -DGTIRB_JAVA_API=${GTIRB_JAVA_API:-OFF}\n      -DGTIRB_PY_API=${GTIRB_PY_API:-OFF}\n    - make -j${MAKE_JOBS}\n    - ctest --output-on-failure\n\nbuild-ubuntu20-gcc:\n  variables:\n    IMAGE_NAME: 'ubuntu20'\n    GTIRB_CXX_API: 'ON'\n    CXX_COMPILER: 'g++'\n    CPACK_GENERATOR: 'DEB'\n    BUILD_TYPE: 'RelWithDebInfo'\n    PACKAGE_POLICY: \"unix\"\n  <<: *build\n\nbuild-ubuntu22-gcc:\n  variables:\n    IMAGE_NAME: 'ubuntu22'\n    GTIRB_CXX_API: 'ON'\n    CXX_COMPILER: 'g++'\n    CPACK_GENERATOR: 'DEB'\n    BUILD_TYPE: 'RelWithDebInfo'\n    PACKAGE_POLICY: \"unix\"\n  <<: *build\n\nbuild-ubuntu24-gcc:\n  variables:\n    IMAGE_NAME: 'ubuntu24'\n    GTIRB_CXX_API: 'ON'\n    CXX_COMPILER: 'g++'\n    CPACK_GENERATOR: 'DEB'\n    BUILD_TYPE: 'RelWithDebInfo'\n    PACKAGE_POLICY: \"unix\"\n  <<: *build\n\nbuild-ubuntu24-gcc-debug:\n  variables:\n    IMAGE_NAME: 'ubuntu24'\n    GTIRB_CXX_API: 'ON'\n    CXX_COMPILER: 'g++'\n    BUILD_TYPE: 'Debug'\n    PACKAGE_POLICY: \"unix\"\n  <<: *build\n\nbuild-ubuntu24-clang-debug:\n  variables:\n    IMAGE_NAME: 'ubuntu24'\n    GTIRB_CXX_API: 'ON'\n    CXX_COMPILER: 'clang++'\n    BUILD_TYPE: 'Debug'\n    PACKAGE_POLICY: \"unix\"\n  <<: *build\n\nbuild-static:\n  variables:\n    IMAGE_NAME: 'static'\n    GTIRB_CXX_API: 'ON'\n    CXX_COMPILER: 'g++'\n    BUILD_TYPE: 'RelWithDebInfo'\n    GTIRB_BUILD_SHARED_LIBS: 'OFF'\n  <<: *build\n\nbuild-java:\n  variables:\n    IMAGE_NAME: 'ubuntu24'\n    GTIRB_JAVA_API: 'ON'\n  <<: *build\n\nbuild-lisp:\n  variables:\n    IMAGE_NAME: 'ubuntu20'\n    GTIRB_CL_API: 'ON'\n  <<: *build\n\nbuild-ubuntu20-python:\n  variables:\n    IMAGE_NAME: 'ubuntu20'\n    GTIRB_PY_API: 'ON'\n  <<: *build\n\nbuild-ubuntu24-python:\n  variables:\n    IMAGE_NAME: 'ubuntu24'\n    GTIRB_PY_API: 'ON'\n  <<: *build\n\ngenerate-coverage:\n  variables:\n    IMAGE_NAME: 'ubuntu24'\n    BUILD_TYPE: 'Debug'\n    CXX_COMPILER: 'g++'\n    ENABLE_CODE_COVERAGE: 'ON'\n    GTIRB_CXX_API: 'ON'\n    GTIRB_PY_API: 'ON'\n  artifacts:\n    # Upload coverage reports and source for report-coverage-* jobs to use.\n    paths:\n      - build/**/*.gcno\n      - build/**/*.gcda\n      - build/python/.coverage*\n      - build/**/*.py\n      - build/**/*.h\n      - build/**/*.cc\n      - build/**/*.cpp\n  before_script:\n    - pip install \"gcovr>=8.6\" coverage\n  <<: *build\n\n# > If there is more than one matched line in the job output, the last line is used\n# https://docs.gitlab.com/ee/ci/yaml/index.html#coverage\n# We output the two coverage numbers in separate jobs(report-coverage-*) so\n# that both can be reported to GitLab.\nreport-coverage-cpp:\n  stage: build\n  needs: [generate-coverage]\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu24:$IMAGE_TAG\n  coverage: '/^TOTAL.*\\s+(\\d+\\%)$/'\n  script:\n    - pip install \"gcovr>=8.6\"\n    - cd build\n    - gcovr --exclude=googletest-src --exclude=doc --exclude=..*/proto --exclude=..*/test --root ..\n\nreport-coverage-py:\n  stage: build\n  needs: [generate-coverage]\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu24:$IMAGE_TAG\n  coverage: '/^TOTAL.*\\s+(\\d+\\%)$/'\n  artifacts:\n    reports:\n      coverage_report:\n        coverage_format: cobertura\n        path: build/python/coverage.xml\n  script:\n    - pip install -r python/requirements-dev.txt\n    - cd build/python\n    - tox run -e report\n    - ../../.ci/adjust-coverage-paths.py --in-place coverage.xml --build-dir ..\n\n\n# The build artifact timestamps may be out-of-date relative to the newly cloned\n# repository for later jobs. These commands will update the timestamps to bring\n# them up to date without actually building much. This is significantly faster\n# than rebuilding out-of-date files in the later jobs.\n.update-artifact-timestamps: &update-artifact-timestamps\n  - make -C build --touch\n\npython-wheel:\n  stage: build-installers\n  needs: [build-ubuntu24-python]\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu24:$IMAGE_TAG\n  artifacts:\n    name: \"$CI_COMMIT_REF_NAME-$CI_JOB_NAME\"\n    paths:\n      - gtirb-*-py*-none-any.whl\n  script:\n    - *update-artifact-timestamps\n    - pip3 wheel --no-deps build/python\n\npython-wheel-unstable:\n  stage: build-installers\n  needs: [python-wheel]\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu24:$IMAGE_TAG\n  rules:\n    - if: '$CI_COMMIT_BRANCH == \"master\"'\n  artifacts:\n    name: \"$CI_COMMIT_REF_NAME-$CI_JOB_NAME\"\n    paths:\n      - gtirb-unstable-py3-none-any.whl\n  script:\n    - cp gtirb-*-py*-none-any.whl ./gtirb-unstable-py3-none-any.whl\n\ntest-capstone-example:\n  stage: test-packages1\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu24:$IMAGE_TAG\n  needs: ['build-ubuntu24-gcc']\n  script:\n    - *update-artifact-timestamps\n    - cd build\n    - '[[ ! -f bin/ex-jumps ]]'\n    - apt-get install -y libcapstone-dev\n    - cmake ..\n    - make -j${MAKE_JOBS}\n    - '[[ -f bin/ex-jumps ]]'\n\ntest-default-install:\n  stage: test-packages1\n  image: $DOCKER_REGISTRY/rewriting/gtirb/$IMAGE_NAME:$IMAGE_TAG\n  variables:\n    IMAGE_NAME: 'ubuntu24'\n    COMPILER: 'g++-9'\n  needs: ['build-ubuntu24-gcc']\n  script:\n    - *update-artifact-timestamps\n    - make -C build install && rm -rf build\n    - LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH .ci/test-install-all.sh\n\ntest-default-install-static:\n  stage: test-packages1\n  image: $DOCKER_REGISTRY/rewriting/gtirb/static:$IMAGE_TAG\n  needs: ['build-static']\n  script:\n    - *update-artifact-timestamps\n    - '[ -e build/lib/libgtirb.a ]'\n    - '[ ! -e build/lib/libgtirb.so ]'\n    - make -C build install\n    - rm -rf build\n    - LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH .ci/test-install-static.sh\n\ntest-install-different-prefix:\n  stage: test-packages1\n  image: $DOCKER_REGISTRY/rewriting/gtirb/$IMAGE_NAME:$IMAGE_TAG\n  variables:\n    IMAGE_NAME: 'ubuntu24'\n    COMPILER: 'g++-9'\n  needs: ['build-ubuntu24-gcc']\n  script:\n    - *update-artifact-timestamps\n    - cmake . -B build -DCMAKE_INSTALL_PREFIX=/tmp/prefix\n    - make -C build install\n    - rm -rf build\n    - >\n      CPPFLAGS=-I/tmp/prefix/include\n      LDFLAGS=-L/tmp/prefix/lib\n      LD_LIBRARY_PATH=/tmp/prefix/lib\n      .ci/test-install-all.sh\n\ntest-install-with-destdir:\n  stage: test-packages1\n  image: $DOCKER_REGISTRY/rewriting/gtirb/$IMAGE_NAME:$IMAGE_TAG\n  variables:\n    IMAGE_NAME: 'ubuntu24'\n    COMPILER: 'g++-9'\n  needs: ['build-ubuntu24-gcc']\n  script:\n    - *update-artifact-timestamps\n    - DESTDIR=/tmp/destdir make -C ./build install\n    - >\n      CPPFLAGS=-I/tmp/destdir/usr/local/include\n      LDFLAGS=-L/tmp/destdir/usr/local/lib\n      LD_LIBRARY_PATH=/tmp/destdir/usr/local/lib\n      .ci/test-install-all.sh\n\ntest-interop:\n  stage: test-packages1\n  needs: ['build-ubuntu24-gcc', 'python-wheel']\n  image: ${DOCKER_REGISTRY}/rewriting/gtirb/ubuntu24:$IMAGE_TAG\n  script:\n    - *update-artifact-timestamps\n    - pip3 install gtirb-*-py*-none-any.whl\n    - .ci/test-interop.sh\n\n.conan-linux: &conan-linux\n  stage: deploy\n  needs: [check-format]\n  image: $DOCKER_REGISTRY/rewriting/gtirb/$IMAGE_NAME:$IMAGE_TAG\n  script:\n    - python3 -m pip install --upgrade conan~=$CONAN_VERSION\n    - conan profile new default --detect\n    - conan profile update settings.compiler.libcxx=libstdc++11 default\n    - conan remote add gitlab ${CI_API_V4_URL}/packages/conan\n    - conan user ci_user -r gitlab -p\n    - export PYTHONPATH=\"$(pwd)\"\n    - python3 .ci/build.py\n\nconan-linux-gcc9:\n  variables:\n    IMAGE_NAME: ubuntu20\n  <<: *conan-linux\n\nconan-linux-gcc11:\n  variables:\n    IMAGE_NAME: ubuntu22\n  <<: *conan-linux\n\n.conan-windows: &conan-windows\n  stage: deploy\n  needs: [check-format]\n  tags: [ddisasm-windows]\n  artifacts:\n    name: \"$CI_COMMIT_REF_NAME-$CI_JOB_NAME\"\n    paths:\n      - gtirb*.zip\n  script:\n    # Setting CI_PROJECT_DIR to $(pwd) because CI doesn't properly set CI_PROJECT_DIR with VirtualBox runners.\n    - export CI_PROJECT_DIR=`cygpath -w $(pwd)`\n    # Initialize\n    - systeminfo\n    - python -m pip install --upgrade conan~=$CONAN_VERSION\n    - export PYTHONPATH=$CI_PROJECT_DIR\n    # Setup Remote and Authenticate\n    - conan remote add gitlab ${CI_API_V4_URL}/packages/conan\n    - conan user ci_user -r gitlab -p\n    # Build\n    - export GTIRB_DISABLE_PARALLEL_BUILD=1\n    - python .ci/build.py -s build_type=$BUILD_TYPE\n    # Install\n      # Python print() on Windows returns CRLF and will cause issues in CI - use \"print('string', end='')\" when outputting from python.\n    - export PKG_INSTALL_NAME=`python -c \"import conanfile; print(conanfile.Properties().conan_recipe, end='')\"`\n    - conan install $PKG_INSTALL_NAME -g deploy --build=missing --install-folder=\"./packages\"\n    # Package\n    - export PKG_NAME=`conan inspect . --raw name`\n    - export PKG_VERSION=`conan inspect . --raw version`\n    - export PKG_ARCH=`uname -m`\n    - cd ./packages\n      # Library Package\n    - export PKG_FILENAME=\"${CI_PROJECT_DIR}\\\\${PKG_NAME}-${PKG_VERSION}.win10.${PKG_ARCH}.zip\"\n    - export PKG_MANIFEST=(\n        \"gtirb/bin/gtirb.dll\"\n        \"gtirb/licenses/LICENSE.txt\"\n      )\n    - zip -r $PKG_FILENAME ${PKG_MANIFEST[@]}\n      # Development Package\n    - export PKG_FILENAME_DEV=\"${CI_PROJECT_DIR}\\\\${PKG_NAME}-dev-${PKG_VERSION}.win10.${PKG_ARCH}.zip\"\n    - export PKG_MANIFEST_DEV=(\n        \"${PKG_MANIFEST[@]}\"\n        \"gtirb/lib/gtirb.lib\"\n        \"gtirb/include/gtirb\"\n      )\n    - zip -r $PKG_FILENAME_DEV ${PKG_MANIFEST_DEV[@]}\n\nconan-windows-debug:\n  variables:\n    BUILD_TYPE: Debug\n  <<: *conan-windows\n\nconan-windows-release:\n  variables:\n    BUILD_TYPE: Release\n  <<: *conan-windows\n\nconan-windows-32:\n  stage: deploy\n  tags: [ddisasm-windows]\n  needs: []\n  variables:\n    ARCHITECTURE: x64\n  script:\n    - systeminfo\n    - export PATH=\"C:\\\\Program Files\\\\Python38;$PATH\"\n    - export PYTHONPATH=\"$(cygpath -w $(pwd))\"\n    # Install conan\n    - python -m pip install --upgrade conan~=$CONAN_VERSION\n    # Setup Remote and Authenticate\n    - conan remote add gitlab ${CI_API_V4_URL}/packages/conan\n    - conan user ci_user -r gitlab -p\n    # The boost options disable building boost with libiconv.  This is important, because we can't get the package to build with --build=libiconv.\n    - CI_PROJECT_DIR=$(cygpath -w $(pwd)) python .ci/build.py -s arch=x86 -s compiler.runtime=MT --build=protobuf -o protobuf:with_zlib=False --build=gtirb --build=boost -o boost:zlib=False -o boost:bzip2=False -o boost:without_locale=True -o boost:without_log=True --build=missing\n\nexternal-pypi:\n  stage: deploy\n  needs: [build-ubuntu24-gcc, python-wheel]\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu24:$IMAGE_TAG\n  rules:\n    - if: '$CI_COMMIT_REF_NAME =~ /^release-.*/'\n  script:\n    - pip3 install twine wheel setuptools pkginfo --upgrade\n    - pip3 install gtirb-*-py*-none-any.whl\n    - GTIRB_VERSION=$(python3 -c \"import gtirb; print(gtirb.__version__)\")\n    # We won't be releasing our dev packages externally, so fail if this is a\n    # .dev package.\n    - if [[ \"$GTIRB_VERSION\" =~ \\.dev[[:digit:]]*(\\+.*)?$ ]]; then exit 1; fi\n    - twine check gtirb-*-py*-none-any.whl\n    - twine upload gtirb-*-py*-none-any.whl -u __token__ -p $PYPI_API_KEY\n\n# On master, we only upload and overwrite `.dev` versions of the python\n# package.  Non-.dev versions should only be uploaded on versioned\n# release-.* branches.  This is so the versioning of our python packages\n# coincides with that of our conan packages, where dev packages are\n# produced from master, and stable, versioned packages are produced\n# on release-.* branches.\ninternal-pypi:\n  stage: deploy\n  needs: [build-ubuntu24-gcc, python-wheel]\n  image: python:3.9\n  rules:\n    - if: '$CI_COMMIT_BRANCH == \"master\"'\n    - if: '$CI_COMMIT_REF_NAME =~ /^release-.*/'\n  script:\n    - pip3 install twine wheel setuptools pkginfo --upgrade\n    - wget https://git.grammatech.com/research/templates/python-module/raw/master/.pypirc\n    - sed \"s/password = <access token>/password = $GL_PKG_API_TOKEN/\" .pypirc > ~/.pypirc\n    - pip3 install gtirb-*-py*-none-any.whl\n    - NEW_VERSION=$(python3 -c \"import gtirb; print(gtirb.__version__)\")\n    - if [[ \"$NEW_VERSION\" =~ \\.dev[[:digit:]]*(\\+.*)?$ && \"$CI_COMMIT_REF_NAME\" =~ ^release-.* ]]; then exit 1; fi\n    - if [[ \"$CI_COMMIT_BRANCH\" == \"master\" ]]; then\n        if [[ ! \"$NEW_VERSION\" =~ \\.dev[[:digit:]]*$ ]]; then\n          echo \"[ERROR] Only .dev versions can be uploaded from the master branch.\";\n          exit 1;\n        fi;\n        if pip3 install --extra-index-url=$EXTRA_INDEX_URL \"gtirb>$NEW_VERSION\" 2>/dev/null; then\n          echo \"[ERROR] The package version being published on master should always be >= the version in the repository.\";\n          exit 1;\n        fi;\n        wget https://git.grammatech.com/research/templates/python-module/raw/master/delete_remote_packages.py;\n        python3 delete_remote_packages.py $GL_PKG_API_TOKEN gtirb-*-py*-none-any.whl;\n      fi\n    - twine check gtirb-*-py*-none-any.whl\n    - twine upload --verbose --repository repypi gtirb-*-py*-none-any.whl\n\n# Apt packaging related jobs\n.build-ubuntu-packages: &build-ubuntu-packages\n  stage: build-installers\n  artifacts:\n    name: \"$CI_COMMIT_REF_NAME-$CI_JOB_NAME\"\n    paths:\n      - build\n  script:\n    - pip3 install setuptools wheel --upgrade\n    - cd build\n    - cpack -G \"DEB\" -D CPACK_GTIRB_PACKAGE=debian-lib;\n    - cpack -G \"DEB\" -D CPACK_GTIRB_PACKAGE=debian-dev;\n    - cpack -G \"DEB\" -D CPACK_GTIRB_PACKAGE=debian-debug;\n\nbuild-ubuntu20-packages:\n  needs: [build-ubuntu20-gcc]\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu20:$IMAGE_TAG\n  <<: *build-ubuntu-packages\n\nbuild-ubuntu22-packages:\n  needs: [build-ubuntu22-gcc]\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu22:$IMAGE_TAG\n  <<: *build-ubuntu-packages\n\nbuild-ubuntu24-packages:\n  needs: [build-ubuntu24-gcc]\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu24:$IMAGE_TAG\n  <<: *build-ubuntu-packages\n\n.setup-test-apt-repo: &setup-test-apt-repo\n  stage: test-setup\n  artifacts:\n    name: \"$CI_COMMIT_REF_NAME-$CI_JOB_NAME\"\n    paths:\n      - apt-repo\n  script:\n    - mkdir apt-repo\n    - cp build/*.deb apt-repo\n    - cd apt-repo && dpkg-scanpackages . /dev/null > Packages\n\n\n.test-ubuntu-libgtirb-dev: &test-ubuntu-libgtirb-dev\n  stage: test-packages1\n  artifacts:\n    name: \"$CI_COMMIT_REF_NAME-$CI_JOB_NAME\"\n    paths:\n      - test-install\n  script:\n    - echo -e \"\\ndeb [trusted=yes] file:$(pwd)/apt-repo ./\\n\" >> /etc/apt/sources.list\n    - cat /etc/apt/sources.list\n    - 'TEST_PKG_NAME=$(dpkg --info apt-repo/libgtirb-dev_*.deb | sed -n \"s/Package: //p\")'\n    - apt-get update -y && apt-get install -y --allow-unauthenticated $TEST_PKG_NAME\n    - cp .ci/test-install.cpp ./\n    - g++ test-install.cpp -std=c++17 -o test-install -lgtirb -lstdc++\n    - ./test-install\n\n.test-ubuntu-libgtirb: &test-ubuntu-libgtirb\n  stage: test-packages2\n  script:\n    - echo -e \"\\ndeb [trusted=yes] file:$(pwd)/apt-repo ./\\n\" >> /etc/apt/sources.list\n    - 'TEST_PKG_NAME=$(dpkg --info apt-repo/libgtirb_*.deb | sed -n \"s/Package: //p\")'\n    - apt-get update -y && apt-get install -y --allow-unauthenticated $TEST_PKG_NAME\n    - ./test-install\n\n.test-ubuntu-libgtirb-dbg: &test-ubuntu-libgtirb-dbg\n  stage: test-packages1\n  script:\n    - echo -e \"\\ndeb [trusted=yes] file:$(pwd)/apt-repo ./\\n\" >> /etc/apt/sources.list\n    - 'TEST_PKG_NAME=$(dpkg --info apt-repo/libgtirb-dbg_*.deb | sed -n \"s/Package: //p\")'\n    - apt-get update -y && apt-get install -y --allow-unauthenticated $TEST_PKG_NAME\n    - '[ -f /usr/lib/debug/.build-id/$(readelf -n /usr/lib/libgtirb.so | grep ''Build ID: '' | cut -d\":\" -f2 | sed -E ''s/ ([a-f0-9]{2,})([a-f0-9]{30,})/\\1\\/\\2/g'').debug ];'\n\nsetup-ubuntu20-test-apt-repo:\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu20:$IMAGE_TAG\n  needs: [build-ubuntu20-packages]\n  <<: *setup-test-apt-repo\n\nsetup-ubuntu22-test-apt-repo:\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu22:$IMAGE_TAG\n  needs: [build-ubuntu22-packages]\n  <<: *setup-test-apt-repo\n\nsetup-ubuntu24-test-apt-repo:\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu24:$IMAGE_TAG\n  needs: [build-ubuntu24-packages]\n  <<: *setup-test-apt-repo\n\ntest-ubuntu20-libgtirb-dev:\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu20:$IMAGE_TAG\n  needs: [setup-ubuntu20-test-apt-repo]\n  <<: *test-ubuntu-libgtirb-dev\n\ntest-ubuntu22-libgtirb-dev:\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu22:$IMAGE_TAG\n  needs: [setup-ubuntu22-test-apt-repo]\n  <<: *test-ubuntu-libgtirb-dev\n\ntest-ubuntu24-libgtirb-dev:\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu24:$IMAGE_TAG\n  needs: [setup-ubuntu24-test-apt-repo]\n  <<: *test-ubuntu-libgtirb-dev\n\ntest-ubuntu20-libgtirb-dbg:\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu20:$IMAGE_TAG\n  needs: [setup-ubuntu20-test-apt-repo]\n  <<: *test-ubuntu-libgtirb-dbg\n\ntest-ubuntu22-libgtirb-dbg:\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu22:$IMAGE_TAG\n  needs: [setup-ubuntu22-test-apt-repo]\n  <<: *test-ubuntu-libgtirb-dbg\n\ntest-ubuntu24-libgtirb-dbg:\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu24:$IMAGE_TAG\n  needs: [setup-ubuntu24-test-apt-repo]\n  <<: *test-ubuntu-libgtirb-dbg\n\ntest-ubuntu20-libgtirb:\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu20:$IMAGE_TAG\n  needs: [setup-ubuntu20-test-apt-repo,test-ubuntu20-libgtirb-dev]\n  <<: *test-ubuntu-libgtirb\n\ntest-ubuntu22-libgtirb:\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu22:$IMAGE_TAG\n  needs: [setup-ubuntu22-test-apt-repo,test-ubuntu22-libgtirb-dev]\n  <<: *test-ubuntu-libgtirb\n\ntest-ubuntu24-libgtirb:\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu24:$IMAGE_TAG\n  needs: [setup-ubuntu24-test-apt-repo,test-ubuntu24-libgtirb-dev]\n  <<: *test-ubuntu-libgtirb\n\n.debian-installer: &debian-installer\n  stage: deploy\n  artifacts:\n    name: \"$CI_COMMIT_REF_NAME-$CI_JOB_NAME\"\n    paths:\n      - '*gtirb*.deb'\n  script:\n    - cp build/*gtirb*.deb ./\n\ndebian-installer-ubuntu20:\n  image: $DOCKER_REGISTRY/rewriting/gtirb/ubuntu20:$IMAGE_TAG\n  needs: [test-ubuntu20-libgtirb, build-ubuntu20-packages]\n  <<: *debian-installer\n\n.apt-upload: &apt-upload\n  stage: deploy-apt\n  trigger:\n    project: rewriting/utility/package-uploader\n    strategy: depend\n\napt-public-ubuntu20-unstable:\n  <<: *apt-upload\n  rules:\n    - if: '$CI_COMMIT_BRANCH == \"master\"'\n  variables:\n    JOB_NAME: debian-installer-ubuntu20\n    APT_REPO: public\n    APT_REPO_CODENAMES: focal\n    APT_REPO_COMPONENT: unstable\n\napt-public-ubuntu20-stable:\n  <<: *apt-upload\n  rules:\n    - if: '$CI_COMMIT_REF_NAME =~ /^release-.*/'\n  variables:\n    JOB_NAME: debian-installer-ubuntu20\n    APT_REPO: public\n    APT_REPO_CODENAMES: focal\n    APT_REPO_COMPONENT: stable\n\napt-internal-ubuntu20-unstable:\n  <<: *apt-upload\n  rules:\n    - if: '$CI_COMMIT_BRANCH == \"master\"'\n  variables:\n    JOB_NAME: debian-installer-ubuntu20\n    APT_REPO: internal\n    APT_REPO_CODENAMES: focal\n    APT_REPO_COMPONENT: unstable\n\napt-internal-ubuntu20-stable:\n  <<: *apt-upload\n  rules:\n    - if: '$CI_COMMIT_REF_NAME =~ /^release-.*/'\n  variables:\n    JOB_NAME: debian-installer-ubuntu20\n    APT_REPO: internal\n    APT_REPO_CODENAMES: focal\n    APT_REPO_COMPONENT: stable\n\nmaven-central-upload:\n  stage: deploy\n  needs: [build-java]\n  trigger:\n    project: rewriting/utility/package-uploader\n    strategy: depend\n  rules:\n    - if: '$CI_COMMIT_REF_NAME == \"master\"'\n    - if: '$CI_COMMIT_REF_NAME =~ /^release-.*/'\n  variables:\n    JOB_NAME: build-java\n    JAVA_POM_SUBDIR: ./build/java\n\n.windows-upload: &windows-upload\n  stage: upload\n  trigger:\n    project: rewriting/utility/package-uploader\n    strategy: depend\n  needs: [conan-windows-release]\n\nwindows-upload-public:\n  <<: *windows-upload\n  rules:\n    - if: '$CI_COMMIT_REF_NAME =~ /^release-.*/'\n    - if: '$CI_COMMIT_REF_NAME == \"master\"'\n  variables:\n    JOB_NAME: conan-windows-release\n    FILESERVER: public\n    FILESERVER_SUBDIR_NAME: windows-release\n\nwindows-upload-internal:\n  <<: *windows-upload\n  rules:\n    - if: '$CI_COMMIT_REF_NAME =~ /^release-.*/'\n    - if: '$CI_COMMIT_REF_NAME == \"master\"'\n  variables:\n    JOB_NAME: conan-windows-release\n    FILESERVER: internal\n    FILESERVER_SUBDIR_NAME: windows-release\n\nwheel-upload-public:\n  stage: upload\n  trigger:\n    project: rewriting/utility/package-uploader\n    strategy: depend\n  needs: [python-wheel-unstable]\n  rules:\n    - if: '$CI_COMMIT_REF_NAME == \"master\"'\n  variables:\n    JOB_NAME: python-wheel-unstable\n    FILESERVER: public\n    FILESERVER_SUBDIR_NAME: python\n"
  },
  {
    "path": ".ci/pre-commit",
    "content": "#!/bin/bash\nOUTPUT=$(git clang-format --diff)\nif [ \"${OUTPUT}\" == \"no modified files to format\" ] ||\n   [ \"${OUTPUT}\" == \"clang-format did not modify any files\" ];then\n    exit 0\nelse\n    echo \"Run git clang-format, then commit.\"\n    exit 1\nfi\n"
  },
  {
    "path": ".ci/test-install-all.sh",
    "content": "#!/bin/sh -e\n\nset -o xtrace\nset -o nounset\nset -o errexit\n\nbuilddir=$(pwd)\nworkdir=`mktemp -d`\ntrap 'cd / ; rm -rf $workdir' EXIT\ncd $workdir\n\n# Compile and run a C++ file that links to libgtirb\ncp $builddir/.ci/test-install.cpp ./\nmake CXXFLAGS=-std=c++17 LDLIBS=-lgtirb test-install\n./test-install\n"
  },
  {
    "path": ".ci/test-install-static.sh",
    "content": "#!/bin/sh -e\n\nset -o xtrace\nset -o nounset\nset -o errexit\n\nbuilddir=$(pwd)\nworkdir=`mktemp -d`\ntrap 'cd / ; rm -rf $workdir' EXIT\ncd $workdir\n\n# Compile and run a C++ file that links to libgtirb statically\ncp $builddir/.ci/test-install.cpp ./\nmake 'CXXFLAGS=-std=c++17' 'LDLIBS=-lgtirb -lgtirb_proto -lprotobuf -lpthread' test-install\n./test-install\n"
  },
  {
    "path": ".ci/test-install.cpp",
    "content": "#include <gtirb/gtirb.hpp>\n#include <cstdio>\n#include <fstream>\n\nint main() {\n  auto filename = std::tmpnam(nullptr);\n  std::ofstream ofs{filename, std::ios_base::binary};\n  auto ctx1 = gtirb::Context();\n  auto ir1 = gtirb::IR::Create(ctx1);\n  ir1->save(ofs);\n  ofs.close();\n  std::ifstream ifs{filename, std::ios_base::binary};\n  auto ctx2 = gtirb::Context();\n  if (auto ir2 = gtirb::IR::load(ctx2, ifs)) {\n\n    return ir2.get()->modules().empty() ? 0 : 1;\n  };\n  return 1;\n}\n"
  },
  {
    "path": ".ci/test-install.lisp",
    "content": "(in-package :gtirb)\n\n(uiop/stream:with-temporary-file (:pathname path :keep nil)\n  (let ((it (make-instance 'gtirb))\n        (test-string \"Something.\"))\n    (push (cons \"test\" (make-instance 'aux-data)) (aux-data it))\n    (setf (aux-data-type (cdar (aux-data it))) :string\n          (aux-data-data (cdar (aux-data it))) test-string)\n    (write-gtirb it path)\n    (assert (string= (aux-data-data (cdar (aux-data (read-gtirb path))))\n                     test-string)\n            (path) \"AuxData in GTIRB at ~s holds ~s.\" path test-string)))\n"
  },
  {
    "path": ".ci/test-install.py",
    "content": "import sys\nimport tempfile\n\nimport gtirb\n\nfilename = tempfile.mktemp()\nir = gtirb.IR()\nir.save_protobuf(filename)\nir = gtirb.IR.load_protobuf(filename)\nsys.exit(len(ir.modules))\n"
  },
  {
    "path": ".ci/test-interop.sh",
    "content": "#!/bin/bash\nset -e\ncd build\n\nfailures=0\n\ncheck() {\n    local creator=$1\n    local auxdata=$2\n    local consumer=$3\n    shift 3\n\n    if \"$@\" ; then\n        echo $creator $auxdata AuxData work in $consumer\n    else\n        failures=$(( failures + 1))\n    fi\n}\n\n### floating-point compatiblity test\n\nbin/test_floats -w floats_cpp.gtirb\npython3 src/test/testInterop/test_floats.py -w floats_py.gtirb\n\ncheck python float c++ \\\n    bin/test_floats -r floats_py.gtirb\ncheck c++ float python \\\n    python3 src/test/testInterop/test_floats.py -r floats_cpp.gtirb\n\nrm floats_{cpp,py}.gtirb\n\n### variant compatibility test\n\nbin/test_variants -w variants_cpp.gtirb\npython3 src/test/testInterop/test_variants.py -w variants_py.gtirb\n\ncheck c++ variant python \\\n    python3 src/test/testInterop/test_variants.py -r variants_cpp.gtirb\ncheck python variant c++ \\\n    bin/test_variants -r variants_py.gtirb\n\nrm variants_{cpp,py}.gtirb\n\ntest $failures = 0\n"
  },
  {
    "path": ".clang-format",
    "content": "---\nLanguage:        Cpp\n# BasedOnStyle:  LLVM\nAccessModifierOffset: -2\nAlignAfterOpenBracket: Align\nAlignConsecutiveAssignments: false\nAlignConsecutiveDeclarations: false\nAlignEscapedNewlinesLeft: false\nAlignOperands:   true\nAlignTrailingComments: true\nAllowAllParametersOfDeclarationOnNextLine: true\nAllowShortBlocksOnASingleLine: false\nAllowShortCaseLabelsOnASingleLine: false\nAllowShortFunctionsOnASingleLine: All\nAllowShortIfStatementsOnASingleLine: false\nAllowShortLoopsOnASingleLine: false\nAlwaysBreakAfterDefinitionReturnType: None\nAlwaysBreakAfterReturnType: None\nAlwaysBreakBeforeMultilineStrings: false\nAlwaysBreakTemplateDeclarations: false\nBinPackArguments: true\nBinPackParameters: true\nBraceWrapping:\n  AfterClass:      false\n  AfterControlStatement: false\n  AfterEnum:       false\n  AfterFunction:   false\n  AfterNamespace:  false\n  AfterObjCDeclaration: false\n  AfterStruct:     false\n  AfterUnion:      false\n  BeforeCatch:     false\n  BeforeElse:      false\n  IndentBraces:    false\nBreakBeforeBinaryOperators: None\nBreakBeforeBraces: Attach\nBreakBeforeTernaryOperators: true\nBreakConstructorInitializersBeforeComma: false\nBreakAfterJavaFieldAnnotations: false\nBreakStringLiterals: true\nColumnLimit:     80\nCommentPragmas:  '^ IWYU pragma:'\nConstructorInitializerAllOnOneLineOrOnePerLine: false\nConstructorInitializerIndentWidth: 4\nContinuationIndentWidth: 4\nCpp11BracedListStyle: true\nDerivePointerAlignment: false\nDisableFormat:   false\nExperimentalAutoDetectBinPacking: false\nForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]\n# IncludeBlocks: Regroup\nIncludeCategories:\n  - Regex:           '^\".*\"'\n    Priority:        1\n  - Regex:           '^<gtirb/.*'\n    Priority:        2\n  - Regex:           '^<proto/.*'\n    Priority:        2\n#IncludeIsMainRegex: '([-_](test|unittest))?$'\nIndentCaseLabels: false\nIndentWidth:     2\nIndentWrappedFunctionNames: false\nJavaScriptQuotes: Leave\nJavaScriptWrapImports: true\nKeepEmptyLinesAtTheStartOfBlocks: true\nMacroBlockBegin: ''\nMacroBlockEnd:   ''\nMaxEmptyLinesToKeep: 1\nNamespaceIndentation: None\nObjCBlockIndentWidth: 2\nObjCSpaceAfterProperty: false\nObjCSpaceBeforeProtocolList: true\nPenaltyBreakBeforeFirstCallParameter: 19\nPenaltyBreakComment: 300\nPenaltyBreakFirstLessLess: 120\nPenaltyBreakString: 1000\nPenaltyExcessCharacter: 1000000\nPenaltyReturnTypeOnItsOwnLine: 60\nPointerAlignment: Left\nReflowComments:  true\nSortIncludes:    true\nSpaceAfterCStyleCast: false\nSpaceAfterTemplateKeyword: true\nSpaceBeforeAssignmentOperators: true\nSpaceBeforeParens: ControlStatements\nSpaceInEmptyParentheses: false\nSpacesBeforeTrailingComments: 1\nSpacesInAngles:  false\nSpacesInContainerLiterals: true\nSpacesInCStyleCastParentheses: false\nSpacesInParentheses: false\nSpacesInSquareBrackets: false\nStandard:        Cpp11\nTabWidth:        8\nUseTab:          Never\n---\nLanguage:        Proto\n---\nLanguage:        Java\nIndentWidth:     4\n...\n"
  },
  {
    "path": ".clang-tidy",
    "content": "---\nChecks:          '-*,clang-analyzer-*,bugprone*,modernize*,performance*,-modernize-pass-by-value,-modernize-use-auto,-modernize-use-using,-performance-unnecessary-value-param,-modernize-use-trailing-return-type'\nWarningsAsErrors: ''\nHeaderFilterRegex: ''\nAnalyzeTemporaryDtors: false\nFormatStyle:     none\n...\n"
  },
  {
    "path": ".cmake-format.yaml",
    "content": "# disable splitting of arguments based on the sheer number of them;\n# prefer to split by line length\nmax_subargs_per_line: 9999\n# layout parens in CMake like how we layout brackets in C++\ndangle_parens: true\n# match the case of intrinsics as used through most of the codebase previosly\ncommand_case: lower\nkeyword_case: upper\n# try autosort (disable this if it causes bugs)\nautosort: true\n"
  },
  {
    "path": ".dockerignore",
    "content": ".git/\n.ci/\n"
  },
  {
    "path": ".flake8",
    "content": "# Black feels free to violate some rules because they're PEP8 extensions and\n# not PEP8 itself. So we must ignore:\n#   E203: Whitespace before ':': Black does \"a[b : c]\"; flake8 wants \"a[b:c]\".\n#   W503: Line break occurred before a binary operator: Black puts operators in front of lines, flake8 wants them after.\n# more detail is available at https://black.readthedocs.io/en/stable/the_black_code_style.html.\n\n[flake8]\nignore = E203,W503\n\n# Ignore unused variables in tests, which tend to come up when building gtirb.\nper-file-ignores =\n  python/tests/*:F841\n"
  },
  {
    "path": ".github/workflows/actions.yml",
    "content": "name: GTIRB Docs\non: [push]\n\njobs:\n  docker:\n    runs-on: ubuntu-latest\n    permissions:\n      packages: write\n    strategy:\n      matrix:\n        os: [focal]\n        include:\n          - os: focal\n            file_suffix: ubuntu20\n    outputs:\n      image_tag: ${{ steps.vars.outputs.image_tag }}\n      image_path: ${{ steps.vars.outputs.image_path }}\n    steps:\n        # We must generate output variables here in order to ensure the\n        # reference is lowercase, even if the repository reference is not\n        # (e.g., because of the organization \"GrammaTech\").\n        # For the tag, we replace forward slashes with hyphens and use the tag\n        # the \"latest\" for the \"master\" branch.\n        # We'd like to just generate the environment variables, but the `env`\n        # context is not available in the \"jobs.<id>.container\" field, despite\n        # what the Context Availability documentation says. See:\n        # https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability\n      - id: vars\n        run: |\n          export IMAGE_TAG=$([ \"${{ github.ref_name }}\" == \"master\" ] && echo latest || echo ${{ github.ref_name }} | sed -e \"s/\\//-/g\")\n          echo \"image_tag=$IMAGE_TAG\" >> $GITHUB_ENV\n          echo \"image_tag=$IMAGE_TAG\" >> $GITHUB_OUTPUT\n          export IMAGE_PATH=$(echo ghcr.io/${{ github.repository }}/ | awk '{print tolower($0)}')\n          echo \"image_path=$IMAGE_PATH\" >> $GITHUB_ENV\n          echo \"image_path=$IMAGE_PATH\" >> $GITHUB_OUTPUT\n      - uses: actions/checkout@master\n      - name: Build image\n        env:\n          image_reference: ${{ env.image_path }}${{ matrix.os }}\n        run: |\n          buildah login -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} ghcr.io\n          buildah build \\\n              -f .ci/Dockerfile.${{ matrix.file_suffix }} \\\n              --cache-from ${{ env.image_reference }}-cache \\\n              --cache-to ${{ env.image_reference }}-cache \\\n              --layers \\\n              --tag ${{ env.image_reference }}:${{ env.image_tag }}\n          buildah push ${{ env.image_reference }}:${{ env.image_tag }}\n\n  docs:\n    runs-on: ubuntu-latest\n    permissions:\n      packages: read\n    strategy:\n      matrix:\n        os: [focal]\n    needs: docker\n    container: ${{ needs.docker.outputs.image_path }}${{ matrix.os }}:${{ needs.docker.outputs.image_tag }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v3\n      - name: Generate documentation\n        run: |\n          cmake -DGTIRB_ENABLE_TESTS=OFF -B build .\n          cd build/python\n          pip install -e '.[doc]'\n          cd ..\n          cmake ..\n          make doc\n          mv doc/html ../public\n      - name: Upload GitHub Pages artifact\n        uses: actions/upload-pages-artifact@v3\n        with:\n          path: public\n\n  deploy-pages:\n    needs: docs\n    if: github.ref == 'refs/heads/master'\n    permissions:\n      pages: write\n      id-token: write\n\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n\n    runs-on: ubuntu-latest\n    steps:\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v4\n"
  },
  {
    "path": ".gitignore",
    "content": "*~\n*.fasl\n*.o\n*.out\n*.pc\nout.gtir\nCMakeCache.txt\nCMakeFiles\nCMakeScripts\nTesting\nMakefile\ncmake_install.cmake\ninstall_manifest.txt\ncompile_commands.json\nCTestTestfile.cmake\nbuild/\nbuild-doc/\nbin/\ndoc/html/\ngoogletest-download/\ngoogletest-src/\ngsl-download/\ngsl-src/\ninclude/gsl/\ninclude/proto/\nwiki/\nscratch.lisp\n/include/gtirb/version.h\n/java/com/grammatech/gtirb/proto/\n.mypy_cache/\n__pycache__/\n.vscode/\n\n.gtirb.pdf\n"
  },
  {
    "path": ".gtirb.tex",
    "content": "\\begin{tikzpicture}%% Caption: GrammaTech IR for Binaries is a data structure that implicitly represents binary structures required for modification.  Elements postifxed with \"(1)\" are singleton in any IR instance every other structure can appear in multiple.  Every elements is assigned a Universal Unique Identifier (UUID) which can be used to reference the element from an AuxData table.  AuxData tables hold open-ended analysis results.\n  %% #fig:gtirb\n  [\n    object/.style = {draw},\n    owner/.style = {thick},\n    owner-many/.style = {-triangle 90 reversed,thick},\n    reference/.style = {owner, dashed, ->},\n  ]\n  \\node[object, ] (ir) {IR (1)};\n  \\node[object, below right=1em and 2em of ir, text width=6.25em] (ad0) {AuxData};\n  \\node[below=0.25em of ad0.south] (ad1) {ID1 \\& DATA1};\n  \\node[below=0em of ad1] (ad2) {ID2 \\& DATA2};\n  \\node[below=0em of ad2] (ad3) {ID3 \\& DATA3};\n  \\node[below=0em of ad3] (ad4) {\\ldots{}};\n  \\node[fit={(ad1) (ad4)}, draw, thick, dotted, inner sep=0.25em] (auxdata) {};\n  \\node[right=2em of auxdata] (anything) {{\\em any UUID}};\n  \\node[object, above right=4.5em and 2em of ir] (cfg) {CFG (1)};\n  \\node[object, right=4em of cfg, text width=5em] (edges) {Edges};\n\n  \\node[object, right=4em of ir, text width=6em] (modules) {Modules};\n  \\node[object, below right=1em and 4em of modules, text width=6em] (symbols) {Symbols};\n\n  \\node[object, right=4em of modules, text width=6em] (sections) {Sections};\n\n  \\node[object, right=2em of sections, text width=8em] (byteintervals) {ByteIntervals};\n\n  \\node[object, above=2em of byteintervals, text width=8em] (proxies) {Proxy blocks};\n  \\node[object, right=2.5em of proxies, text width=7em] (codeblocks) {Code Blocks};\n  \\node[object, below=0.5em of codeblocks, text width=7em] (datablocks) {Data Blocks};\n  \\node[fit={(proxies) (codeblocks)}, draw, thick, dotted] (edgeblocks) {};\n  \\node[] at (edges -| proxies) (eblocks) {Edge Blocks};\n  \\node[fit={(codeblocks) (datablocks)}, draw, thick, dotted, inner sep=0.75em] (byteblocks) {};\n  \\node[] at (eblocks -| byteblocks) (bblocks) {Byte Blocks};\n\n  \\node[object, below right=1em and 2.5em of byteintervals, text width=10.5em] (symexpr) {SymbolicExpressions};\n\n  %% References\n  \\draw[reference] (edges.east) |- (eblocks);\n  \\draw[reference] (edges.east) -| ++(2,1) -| (bblocks.north);\n  \\draw[reference] (symbols.east) -| ++(2,-1) -| (symexpr.south);\n  \\draw[reference] (auxdata) -- (anything);\n\n  %% Ownership\n  \\draw[owner-many] (ir) -- (modules);\n  \\draw[owner] (ir) -- ++(1.0,0) |- (cfg);\n  \\draw[owner-many] (ir) -- ++(1.0,0) |- (ad0);\n  \\draw[owner-many] (cfg) -- (edges);\n  \\draw[owner-many] (modules) -- ++(1.5,0) |- (symbols);\n  \\draw[owner-many] (modules) -- (sections);\n  \\draw[owner-many] (modules) -- ++(1.5,0) |- (edgeblocks);\n  \\draw[owner-many] (modules.south) -- (ad0.north-|modules.south);\n  \\draw[owner-many] (sections) -- (byteintervals);\n  \\draw[owner-many] (byteintervals) -- ++(1.75,0) |- (symexpr);\n  \\draw[owner-many] (byteintervals) -- ++(1.75,0) |- (bblocks);\n\n  %% Local Variables:\n  %% mode: latex\n  %% end:\n\\end{tikzpicture}\n"
  },
  {
    "path": ".isort.cfg",
    "content": "# Settings are chosen to be compatible with black:\n#   https://black.readthedocs.io/en/stable/the_black_code_style.html#how-black-wraps-lines\n# For details on each setting:\n#   https://github.com/timothycrosley/isort/wiki/isort-Settings\n[settings]\nline_length=79\nmulti_line_output=3\ninclude_trailing_comma=true\nforce_grid_wrap=0\n"
  },
  {
    "path": ".lisp-format",
    "content": ";;;; -*- emacs-lisp -*-\n;;;;\n;;;; For information about how to use lisp-format see it's\n;;;; documentation, which is available in a comment at the top of the\n;;;; lisp-format script or, equivalently, in the README available at:\n;;;;\n;;;;     https://github.com/eschulte/lisp-format\n;;;;\n(mapc (lambda (dir) (add-to-list 'load-path dir))\n      (apply #'append\n             (mapcar\n              (lambda (pkg-glob)\n                (cl-loop for path in\n                   (directory-files\n                    ;; Use quicklisp if the user has it setup.\n                    (if (getenv \"QUICK_LISP\")\n                        (concat (getenv \"QUICK_LISP\") \"/dists/quicklisp/software/\")\n                      ;; Search for the site-lisp path in load-path\n                      (add-to-list 'load-path \"/usr/share/emacs25/site-lisp/elpa/\")\n                      (add-to-list 'load-path \"/usr/share/emacs/site-lisp/elpa/\")\n                      (cl-loop for path in load-path\n                         if (and (string-match-p \"site-lisp\" path)\n                                 (file-expand-wildcards (concat (file-name-as-directory path) \"slime*\")))\n                         do (cl-return path)))\n                    t pkg-glob)\n                   if (file-directory-p path) collect path))\n              (list \"slime*\" \"paredit*\"))))\n\n(defun verbose-require (package)\n  (unless (ignore-errors (require package))\n    (message \"Failed to load the package '%S'.\" package)\n    (message \"Ensure %s is installed locally, and then edit your\" package)\n    (message \"\\\"~/.lisp-formatrc\\\" file adding %s to your load path.\\n\" package)\n    (message \"    (add-to-list 'load-path </path/to/%s.el>)\\n\" package)\n    ;; After printing the messages require again to trigger the error.\n    (require package)))\n(verbose-require 'slime)\n(verbose-require 'paredit)\n\n(set-default 'indent-tabs-mode nil)\n(pushnew 'untabify *lisp-format-fixers*)\n\n(defun fix-trailing-parens (start end &optional _arg)\n  \"Use `paredit-close-parenthesis' to fix trailing parens.\"\n  (interactive (if current-prefix-arg\n                   (list (point-min) (point-max) current-prefix-arg)\n                 (list (region-beginning) (region-end) nil)))\n  (let ((c (current-column)))\n    (save-excursion\n      (save-restriction\n        (narrow-to-region (point-min) end)\n        (goto-char start)\n        (while (re-search-forward \"^ *)\" nil t)\n        (forward-char -1)\n        (paredit-close-parenthesis))))\n  (move-to-column c)))\n(pushnew 'fix-trailing-parens *lisp-format-fixers*)\n\n;;; Syntax table extension for curry-compose-reader-macros\n(modify-syntax-entry ?\\[ \"(]\" lisp-mode-syntax-table)\n(modify-syntax-entry ?\\] \")[\" lisp-mode-syntax-table)\n(modify-syntax-entry ?\\{ \"(}\" lisp-mode-syntax-table)\n(modify-syntax-entry ?\\} \"){\" lisp-mode-syntax-table)\n(modify-syntax-entry ?\\« \"(»\" lisp-mode-syntax-table)\n(modify-syntax-entry ?\\» \")«\" lisp-mode-syntax-table)\n\n;;; Specify indentation levels for specific functions.\n(mapc (lambda (pair) (put (first pair) 'lisp-indent-function (second pair)))\n      '((make-instance 1)\n        (if-let 1)\n        (if-let* 1)\n        (when-let 1)\n        (when-let* 1)\n        (defixture 1)\n        (lambda-bind 1)\n        (signals 1)\n        (match 1)\n        (start-case 1)\n        (define-proto-backed-class 4)\n        (register-groups-bind 2)))\n\n(defun define-feature-lisp-indent\n    (path state indent-point sexp-column normal-indent)\n  \"Indentation function called by `lisp-indent-function' for define-feature.\"\n  ;; (message \"CALLED: %S\"\n  ;;          (list 'define-feature-lisp-indent\n  ;;                path state indent-point sexp-column normal-indent))\n  (cond\n   ((equalp path '(2)) 2)   ; Doc string for enclosing define-feature.\n   ((equalp path '(3)) 2)   ; Extractor function definition.\n   ((equalp path '(3 2)) 4) ; Doc string for extractor.\n   ((equalp path '(4)) 2)   ; Merge function definition.\n   (t nil)))                ; Otherwise do the default.\n(put 'define-feature 'lisp-indent-function 'define-feature-lisp-indent)\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "repos:\n  - repo: https://github.com/psf/black\n    rev: 22.3.0\n    hooks:\n      - id: black\n        args: [\"--line-length\", \"79\"]\n      - id: black\n        name: black (.pyi)\n        args: [\"--line-length\", \"79\"]\n        types: [pyi]\n  - repo: local\n    hooks:\n      - id: clang-format\n        name: clang-format\n        language: system\n        files: \\.(c|h|cpp|hpp|proto|java)$\n        entry: clang-format -i\n  - repo: https://github.com/eschulte/lisp-format\n    rev: master\n    hooks:\n      - id: lisp-format\n        name: lisp-format\n        args: [-style=file]\n  - repo: https://github.com/pre-commit/pre-commit-hooks\n    rev: v2.4.0\n    hooks:\n      - id: end-of-file-fixer\n      - id: trailing-whitespace\n        args: [\"--chars\",\" \\t\"]\n      - id: check-merge-conflict\n      - id: check-yaml\n        args: [--allow-multiple-documents]\n      - id: debug-statements\n      - id: mixed-line-ending\n  - repo: https://github.com/iconmaster5326/cmake-format-pre-commit-hook\n    rev: v0.6.2\n    hooks:\n      - id: cmake-format\n        exclude: build\n  - repo: https://github.com/timothycrosley/isort\n    rev: 5.13.2\n    hooks:\n      - id: isort\n        files: \\.py$\n  - repo: https://github.com/PyCQA/flake8\n    rev: 7.1.0\n    hooks:\n      - id: flake8\n"
  },
  {
    "path": "AlignOf.cmake",
    "content": "macro(ALIGNOF TYPE LANG NAME)\n  if(NOT ALIGNOF_${NAME})\n    #\n    # Try to compile and run a foo grogram. The alignment result will be stored\n    # in ALIGNOF_${CHECK_TYPE}\n    #\n\n    set(INCLUDE_HEADERS\n        \"#include <stddef.h>\n\t\t\t#include <stdio.h>\n\t\t\t#include <stdlib.h>\"\n    )\n\n    foreach(File ${CMAKE_REQUIRED_INCLUDES})\n      set(INCLUDE_HEADERS \"${INCLUDE_HEADERS}\\n#include <${File}>\\n\")\n    endforeach()\n\n    set(INCLUDE_HEADERS \"${INCLUDE_HEADERS}\\n#include <stdint.h>\\n\")\n\n    file(\n      WRITE\n      \"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/c_get_${NAME}_alignment.${LANG}\"\n      \"${INCLUDE_HEADERS}\n\t\t\tint main(){\n\t\t\t\tchar diff;\n\t\t\t\tstruct foo {char a; ${TYPE} b;};\n\t\t\t\tstruct foo *p = (struct foo *) malloc(sizeof(struct foo));\n\t\t\t\tdiff = ((char *)&p->b) - ((char *)&p->a);\n\t\t\t\treturn diff;\n\t\t\t}\"\n    )\n\n    try_run(\n      ALIGNOF_${NAME}\n      COMPILE_RESULT\n      \"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/\"\n      \"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/c_get_${NAME}_alignment.${LANG}\"\n      COMPILE_OUTPUT_VARIABLE \"ALIGNOF_${NAME}_COMPILE_VAR\"\n    )\n\n    if(NOT COMPILE_RESULT)\n      message(\n        FATAL_ERROR\n          \"Check alignment of ${TYPE} in ${LANG}: compilation failed: ${ALIGNOF_${NAME}_COMPILE_VAR}\"\n      )\n    else()\n      message(\n        STATUS \"Check alignment of ${TYPE} in ${LANG}: ${ALIGNOF_${NAME}}\"\n      )\n    endif()\n  endif()\nendmacro()\n"
  },
  {
    "path": "AuxData.md",
    "content": "Standard AuxData Schemata\n=========================\n\nThe \\ref AUXDATA_GROUP class provides generic storage for\napplication-specific data. This allows data to be attached to either\nthe IR or Module classes in GTIRB.\n\nWe specify a small number of standard gtirb::AuxData schemata to\nsupport interoperability. These are listed below, in two sets:\n\n- [Sanctioned](#sanctioned-auxdata-tables) Recommended for GTIRB\n  users. Individual schemata are unlikely to change in future,\n  although the set of Sanctioned schemata may grow.\n\n- [Provisional](#provisional-auxdata-tables) Under consideration for\n  'sanctioned' status.\n\nFor example, if you want to store alignment requirements for blocks\nand data objects, you can use an [alignment](#alignment) table.\n\n```c++\n// Leverage definitions for the sanctioned AuxData tables.\n#include <gtirb/AuxDataSchema.hpp>\n\n// Define your own custom AuxData tables.\n// By convention, we put these in the namespace gtirb::schema.\n//\n// Note that if the custom type requires custom serialization, a\n// specialization of the auxdata_traits template also has to be\n// provided. We provide default specializations for many standard\n// types.\nnamespace gtirb {\nnamespace schema {\nstruct MyAuxDataFoo {\n  static constexpr const char* Name = \"foo\";\n  typedef Foo Type;\n};\n}\n}\n\nusing namespace gtirb;\nusing namespace schema;\n\n// Register AuxData types before using GTIRB.\nvoid call_me_from_main()\n{\n  AuxDataContainer::registerAuxDataType<Alignment>();\n  AuxDataContainer::registerAuxDataType<MyAuxDataFoo>();\n}\n\nvoid do_stuff_with_gtirb()\n{\n  Context C;\n  IR& ir = *IR::Create(C);\n  ir.addModule(Module::Create(C));\n  Module& module = *ir.modules_begin();\n\n  // Attach an empty alignment table to the internal representation\n  module.addAuxData<Alignment>(std::map<UUID, uint64_t>{});\n\n  //...\n\n  // Create a new block\n  Section* section = module.addSection(C, \".text\");\n  ByteInterval* interval = section->addByteInterval(C, Addr(400), 1000);\n  CodeBlock* b1 = interval->addBlock<CodeBlock>(C, 64, 6);\n\n  // Record that the block should be aligned to 8-byte boundaries.\n  // First fetch the map AuxData.\n  auto* align_map = module.getAuxData<Alignment>();\n\n  // Check for null if you don't know that the module definitely has\n  // an existing Alignment AuxData attached.\n  if (align_map)\n    (*align_map)[b1->getUUID()] = 8;\n\n  // Attach a custom \"Foo\" object.\n  // Note that AuxData uses a move reference\n  Foo my_foo = BuildAFoo();\n  module.addAuxData<MyAuxDataFoo>(std::move(my_foo));\n\n  // Subsequently access the Foo table through the AuxData interface.\n  module.getAuxData<MyAuxDataFoo>()->some_member_function();\n}\n```\n\n\n## Sanctioned AuxData Tables\n\nThe following are the sanctioned AuxData table schemata.\n\n\n| Label                                     | Type                                               |\n|-------------------------------------------|----------------------------------------------------|\n| [`\"elfDynamicInit\"`](#elfDynamicInit)     | ```gtirb::UUID```                                  |\n| [`\"elfDynamicFini\"`](#elfDynamicFini)     | ```gtirb::UUID```                                  |\n| [`\"elfSoname\"`](#elfSoname)               | ```std::string```                                  |\n| [`\"elfStackExec\"`](#elfStackExec)         | ```bool```                                         |\n| [`\"elfStackSize\"`](#elfStackSize)         | ```uint64_t```                                     |\n| [`\"functionBlocks\"`](#functionblocks)     | ```std::map<gtirb::UUID, std::set<gtirb::UUID>>``` |\n| [`\"functionEntries\"`](#functionentries)   | ```std::map<gtirb::UUID, std::set<gtirb::UUID>>``` |\n| [`\"functionNames\"`](#functionnames)       | ```std::map<gtirb::UUID, gtirb::UUID>```           |\n| [`\"types\"`](#types)                       | ```std::map<gtirb::UUID, std::string>```           |\n| [`\"alignment\"`](#alignment)               | ```std::map<gtirb::UUID, uint64_t>```              |\n| [`\"comments\"`](#comments)                 | ```std::map<gtirb::Offset, std::string>```         |\n| [`\"symbolForwarding\"`](#symbolforwarding) | ```std::map<gtirb::UUID, gtirb::UUID>```           |\n| [`\"padding\"`](#padding)                   | ```std::map<gtirb::Offset, uint64_t>```            |\n\n\n### elfDynamicInit\n\n| <!-- --> | <!-- -->                                           |\n|----------|----------------------------------------------------|\n| Label    | ```\"elfDynamicInit\"```                             |\n| Type     | ```gtirb::UUID```                                  |\n| Value    |  CodeBlock UUID                                    |\n| AttachedTo | gtirb::Module |\n| Note     | The CodeBlock to which a DT_INIT entry in an ELF file's .dynamic section refers. |\n\n### elfDynamicFini\n\n| <!-- --> | <!-- -->                                           |\n|----------|----------------------------------------------------|\n| Label    | ```\"elfDynamicFini\"```                             |\n| Type     | ```gtirb::UUID```                                  |\n| Value    |  CodeBlock UUID                                    |\n| AttachedTo | gtirb::Module |\n| Note     | The CodeBlock to which a DT_FINI entry in an ELF file's .dynamic section refers. |\n\n### elfSoname\n\n| <!-- --> | <!-- -->                                           |\n|----------|----------------------------------------------------|\n| Label    | ```\"elfSoname\"```                                  |\n| Type     | ```std::string```                                  |\n| Value    | The SONAME of a library.                           |\n| AttachedTo | gtirb::Module |\n| Note     | The string value which the DT_SONAME entry in an ELF file's .dynamic section contains. |\n\n### elfStackExec\n\n| <!-- --> | <!-- -->                                           |\n|----------|----------------------------------------------------|\n| Label    | ```\"elfStackExec\"```                               |\n| Type     | ```bool```                                         |\n| Value    | Stack executable flag specified by PT_GNU_STACK segment in ELF files. |\n| AttachedTo | gtirb::Module |\n\n### elfStackSize\n\n| <!-- --> | <!-- -->                                           |\n|----------|----------------------------------------------------|\n| Label    | ```\"elfStackSize\"```                               |\n| Type     | ```uint64_t```                                     |\n| Value    | The size of the PT_GNU_STACK segment in ELF files, which may influence the runtime stack size in certain environments. |\n| AttachedTo | gtirb::Module |\n\n### functionBlocks\n\n| <!-- --> | <!-- -->                                           |\n|----------|----------------------------------------------------|\n| Label    | ```\"functionBlocks\"```                             |\n| Type     | ```std::map<gtirb::UUID, std::set<gtirb::UUID>>``` |\n| Key      | Function UUID.                                     |\n| Value    | The set of UUIDs of all the blocks (gtirb::CodeBlock) in the function. |\n| AttachedTo | gtirb::Module |\n| Note     | This table identifies all of the gtirb::CodeBlocks that belong to each function. These do not necessarily have to be contiguous in the address space. Note that there is no function notion in the core GTIRB IR. A function's UUID is just a unique identifier that is consistently used across all function-related AuxData tables. |\n\n\n### functionEntries\n\n| <!-- --> | <!-- -->                                           |\n|----------|----------------------------------------------------|\n| Label    | ```\"functionEntries\"```                            |\n| Type     | ```std::map<gtirb::UUID, std::set<gtirb::UUID>>``` |\n| Key      | Function UUID.                                     |\n| Value    | The set of UUIDs of all the entry blocks (gtirb::CodeBlock) for the function. |\n| AttachedTo | gtirb::Module |\n| Note     | This table identifies all gtirb::CodeBlocks that represent entry points to each function. A single function may have more than one entry point. Note that there is no function notion in the core GTIRB IR. A function's UUID is just a unique identifier that is consistently used across all function-related AuxData tables. |\n\n\n### functionNames\n\n| <!-- --> | <!-- -->                                                            |\n|----------|---------------------------------------------------------------------|\n| Label    | ```\"functionNames\"```                                               |\n| Type     | ```std::map<gtirb::UUID, gtirb::UUID>```                            |\n| Key      | Function UUID.                                                      |\n| Value    | The UUID of a gtrb::Symbol whose `name` field contains the name of the function. |\n| AttachedTo | gtirb::Module |\n| Note     | There may be more than one gtirb::Symbol associated with the address(es) corresponding to the entry point(s) of a function. This table identifies a canonical gtirb::Symbol to be used for each function. Note that there is no function notion in the core GTIRB IR. A function's UUID is just a unique identifier that is consistently used across all function-related AuxData tables. |\n\n\n### types\n\n| <!-- --> | <!-- -->                                |\n|----------|-----------------------------------------|\n| Label    | ```\"types\"```                           |\n| Type     | ```std::map<gtirb::UUID,std::string>``` |\n| Key      | The gtirb::UUID of a gtirb::DataBlock. |\n| Value    | The type of the data, expressed as a std::string containing a C++ type specifier. |\n| AttachedTo | gtirb::Module |\n| Note     | An entry in this table indicates that the given gtirb::DataBlock contains content that exhibits the given C++ type. |\n\n\n### alignment\n\n| <!-- --> | <!-- -->                                                  |\n|----------|-----------------------------------------------------------|\n| Label    | ```\"alignment\"```                                         |\n| Type     | ```std::map<gtirb::UUID, uint64_t>```                     |\n| Key      | The gtirb::UUID of a gtirb::CodeBlock, gtirb::DataBlock, or gtirb::Section. |\n| Value    | Alignment requirements for the block/data object/section. |\n| AttachedTo | gtirb::Module |\n| Note     |  An entry in this table indicates that the given object's address is required to be evenly divisible by the alignment value. Typically the alignment value is a power of 2. |\n\n\n### comments\n\n| <!-- --> | <!-- -->                                   |\n|----------|--------------------------------------------|\n| Label    | ```\"comments\"```                           |\n| Type     | ```std::map<gtirb::Offset, std::string>``` |\n| Key      | The gtirb::Offset of a comment.            |\n| Value    | A comment string relevant to the specified offset in the specified GTIRB entry. |\n| AttachedTo | gtirb::Module |\n| Note     | The gtirb::Offset refers to the UUID of an entity in memory and a byte offset within that entity to indicate the point at which the comment applies. Comments can contain arbitrary content and are likely generated by analysis tools. They often do not (but may) represent comments present in the original source code of the binary. |\n\n\n### symbolForwarding\n\n| <!-- --> | <!-- -->                                     |\n|----------|----------------------------------------------|\n| Label    | ```\"symbolForwarding\"```                     |\n| Type     | ```std::map<gtirb::UUID,gtirb::UUID>```      |\n| Key      | The gtirb::UUID of the \"from\" gtirb::Symbol. |\n| Value    | The gtirb::UUID of the \"to\" gtirb::Symbol.   |\n| AttachedTo | gtirb::Module |\n| Note     | This table is intended to support cross-module references. A \"from\" symbol in one gtirb::Module may be dynamically bound at runtime to the \"to\" symbol in another gtirb::Module, thereby modeling dynamic library runtime linkage. |\n\n\n### padding\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"padding\"```                                |\n| Type     | ```std::map<gtirb::Offset, uint64_t>```        |\n| Key      | The gtirb::Offset at which padding is present. |\n| Value    | The length of the padding, in bytes.           |\n| AttachedTo | gtirb::Module |\n| Note     | Padding here may be 0's or it may be valid instructions. An entry in this table indicates that an analysis has determined that at the given gtirb::Offset (UUID of an entity in memory and byte offset into that entity) and length of bytes indicated constitute content that is unused by the program and is only present to ensure alignment of neighboring objects. Note: some disassemblers may still create a gtirb::CodeBlock or gtirb::DataBlock for the same portion of address space that a padding entry covers. |\n\n\n## Provisional AuxData Tables\n\nThe following are the provisional AuxData table schemata.\n\n\n| Label                                                       | Type                                                                                                         |\n|-------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|\n| [`\"binaryType\"`](#binarytype)                               | ```std::vector<std::string>```                                                                               |\n| [`\"cfiDirectives\"`](#cfidirectives)                         | ```std::map<gtirb::Offset, std::vector<std::tuple<std::string, std::vector<int64_t>, gtirb::UUID>>>```       |\n| [`\"elfSymbolInfo\"`](#elfsymbolinfo)                         | ```std::map<gtirb::UUID, std::tuple<uint64_t, std::string, std::string, std::string, uint64_t>>```           |\n| [`\"elfSymbolVersions\"`](#elfsymbolversions)                 | ```std::tuple<std::map<uint16_t, std::tuple<std::vector<std::string>, uint16_t>>, std::map<std::string, std::map<uint16_t, std::string>>, std::map<gtirb::UUID, std::tuple<uint16_t, bool>>>```           |\n| [`\"encodings\"`](#encodings)                                 | ```std::map<gtirb::UUID, std::string>```                                                                     |\n| [`\"functionNameProbabilities\"`](#functionnameprobabilities) | ```std::map<std::string, std::map<gtirb::UUID, std::vector<std::tuple<std::string, std::string, float>>>>``` |\n| [`\"includedLibraryNames\"`](#includedlibrarynames)           | ```std::map<gtirb::UUID, std::string>```                                                                     |\n| [`\"includedLibraryVersions\"`](#includedlibraryversions)     | ```std::map<gtirb::UUID, std::string>```                                                                     |\n| [`\"libraries\"`](#libraries)                                 | ```std::vector<std::string>```                                                                               |\n| [`\"libraryPaths\"`](#librarypaths)                           | ```std::vector<std::string>```                                                                               |\n| [`\"peExportEntries\"`](#peexportentries)                     | ```std::vector<std::tuple<uint64_t, int64_t, std::string>>```                                                |\n| [`\"peExportedSymbols\"`](#peexportedsymbols)                 | ```std::vector<gtirb::UUID>```                                                                               |\n| [`\"peImportEntries\"`](#peimportentries)                     | ```std::vector<std::tuple<uint64_t, int64_t, std::string, std::string>>```                                   |\n| [`\"peImportedSymbols\"`](#peimportedsymbols)                 | ```std::vector<gtirb::UUID>```                                                                               |\n| [`\"peResource\"`](#peresource)                               | ```std::vector<std::tuple<std::vector<uint8_t>, gtirb::Offset, uint64_t>>```                                 |\n| [`\"profile\"`](#profile)                                     | ```std::map<gtirb::UUID, uint64_t>```                                                                        |\n| [`\"prototypeTable\"`](#prototypetable)                       | ```std::map<gtirb::UUID, gtirb::UUID>```                                                                     |\n| [`\"sccs\"`](#sccs)                                           | ```std::map<gtirb::UUID, int64_t>```                                                                         |\n| [`\"sectionProperties\"`](#sectionproperties)           | ```std::map<gtirb::UUID, std::tuple<uint64_t, uint64_t>>>>```                                                |\n| [`\"symbolicExpressionSizes\"`](#symbolicexpressionsizes)     | ```std::map<gtirb::Offset, uint64_t>```                                                                      |\n| [`\"typeTable\"`](#typetable)                                 | ```std::map<gtirb::UUID, std::variant<uint64_t, std::tuple<uint8_t>, std::tuple<int8_t, uint64_t>, uint64_t, uint64_t, std::tuple<gtirb::UUID, std::vector<gtirb::UUID>>, gtirb::UUID, std::tuple<gtirb::UUID, uint64_t>, tuple<uint64_t, std::vector<tuple<uint64_t, gtirb::UUID>>>, std::tuple<uint8_t>, gtirb::UUID>>``` |\n\n\n### encodings\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"encodings\"```                                |\n| Type     | ```std::map<gtirb::UUID, std::string>```        |\n| Key      | The gtirb::UUID of a data object. |\n| Value    | The encoding of the data object.           |\n| AttachedTo | gtirb::Module |\n| Note     | Map from (typed) data objects to the encoding of the data,  expressed as a std::string containing an assembler encoding specifier: \"string\", \"uleb128\" or \"sleb128\". |\n\n\n### elfSymbolVersions\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"elfSymbolVersions\"```                                |\n| Type     | ```std::tuple<std::map<uint16_t, std::tuple<std::vector<std::string>, uint16_t>>, std::map<std::string, std::map<uint16_t, std::string>>, std::map<gtirb::UUID, std::tuple<uint16_t, bool>>>```        |\n| Key      | The gtirb::UUID of a section. |\n| Value    | The tuple with the ELF section types and flag.           |\n| AttachedTo | gtirb::Module |\n| Note     | Tuple with symbol version definitions, needed symbol versions, and a mapping of symbol UUIDs to symbol versions. Symbol version definitions are  `ElfSymDefs = std::map<SymbolVersionId, std::tuple<std::vector<std::string>>, uint16_t>`, a map from symbol version identifiers version definitions. These correspond to `ELFxx_Verdef` entries in the ELF section `.gnu.version_d`. The values in the map are tuples containing the list of versions strings and the verdef flags. The verdef flag may be `VER_FLG_BASE` (0x1), which indicates that the given version definiton is the file itself, and must not be used for matching a symbol. The first element of the list is the version itself, the subsequent elements are predecessor versions. The needed symbol versions are `ElfSymVerNeeded = std::map<std::string, std::map<SymbolVersionId, std::string>>`, a map from dynamic library names to the symbol versions that they need. For each library, we have a map from version identifiers to version strings. Finally, symbol UUIDs are mapped to symbol versions as `ElfSymbolVersionsEntries = std::map<gtirb::UUID, std::tuple<SymbolVersionId,bool>>`, where the `bool` represents the `HIDDEN` attribute. Symbol version identifiers are `SymbolVersionId = uint16_t` integers. |\n\n\n### cfiDirectives\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"cfiDirectives\"```                                |\n| Type     | ```std::map<gtirb::Offset, std::vector<std::tuple<std::string, std::vector<int64_t>, gtirb::UUID>>>```        |\n| Key      | The gtirb::Offset of a cfi directive. |\n| Value    | cfi directive contains: a string describing the directive, a vector  of numeric arguments, and an optional symbolic argument (represented with the UUID of the symbol           |\n| AttachedTo | gtirb::Module |\n| Note     | Map from Offsets to  vector of cfi directives. A cfi directive contains: a string describing the directive, a vector  of numeric arguments, and an optional symbolic argument (represented with the UUID of the symbol). |\n\n\n### elfSymbolInfo\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"elfSymbolInfo\"```                                |\n| Type     | ```std::map<gtirb::UUID, std::tuple<uint64_t, std::string, std::string, std::string, uint64_t>>```        |\n| Key      | The gtirb::UUID of a symbol. |\n| Value    | The type, binding, and visibility categories of the symbol.           |\n| AttachedTo | gtirb::Module |\n| Note     | On ELF targets only: Map from symbols to their type, binding, and visibility categories. |\n\n\n### libraries\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"libraries\"```                                |\n| Type     | ```std::vector<std::string>```        |\n| Value    | The name of a library.           |\n| AttachedTo | gtirb::Module |\n| Note     | Names of the external libraries that are needed dynamically at run time. |\n\n\n### libraryPaths\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"libraryPaths\"```                                |\n| Type     | ```std::vector<std::string>```        |\n| Value    | A path contained in the rpath of the binary.           |\n| AttachedTo | gtirb::Module |\n| Note     | Paths contained in the rpath of the binary. |\n\n\n### binaryType\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"binaryType\"```                                |\n| Type     | ```std::vector<std::string>```        |\n| Value    | A binary type descriptor.           |\n| AttachedTo | gtirb::Module |\n| Note     | A set of binary type descriptors e.g. for ELF whether the binary is PIE \"DYN\" or not, \"EXEC\". PE binaries have additional descriptors, \"DLL\" or \"EXE, and subsystem descriptor, e.g. WINDOWS_GUI or WINDOWS_CUI. |\n\n\n### SCCs\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"SCCs\"```                                |\n| Type     | ```std::map<gtirb::UUID, int64_t>```        |\n| Key      | The gtirb::UUID of a block |\n| Value    | The intra-procedural SCC identifier of the block.           |\n| AttachedTo | gtirb::Module |\n| Note     | The intra-procedural SCC identifier of each block. |\n\n\n### symbolicExpressionSizes\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"symbolicExpressionSizes\"```                                |\n| Type     | ```std::map<gtirb::Offset, uint64_t>```        |\n| Key      | The gtirb::Offset of a symbolic expression. |\n| Value    | The size of the expression, in bytes.           |\n| AttachedTo | gtirb::Module |\n| Note     | Map from an Offset of a symbolic expression in a ByteInterval to its extent, a size in bytes. |\n\n\n### peImportEntries\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"peImportEntries\"```                                |\n| Type     | ```std::vector<std::tuple<uint64_t, int64_t, std::string, std::string>>```        |\n| Value    | A tuples containing details of an imported function.          |\n| AttachedTo | gtirb::Module |\n| Note     | List of tuples detailing an imported function address, ordinal, function name, and library names for PE. |\n\n\n### peExportEntries\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"peExportEntries\"```                                |\n| Type     | ```std::vector<std::tuple<uint64_t, int64_t, std::string>>```        |\n| Value    | A tuples containing details of an exported function.          |\n| AttachedTo | gtirb::Module |\n| Note     | List of tuples detailing an exported address, ordinal, and name for PE. |\n\n\n### peImportedSymbols\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"peImportedSymbols\"```                                |\n| Type     | ```std::vector<gtirb::UUID>```        |\n| Value    | gtirb::UUID of an imported symbol.           |\n| AttachedTo | gtirb::Module |\n| Note     | UUIDs of the imported symbols for PE. |\n\n\n### peExportedSymbols\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"peExportedSymbols\"```                                |\n| Type     | ```std::vector<gtirb::UUID>```        |\n| Value    | gtirb::UUID of an exported symbol.           |\n| AttachedTo | gtirb::Module |\n| Note     | UUIDs of the exported symbols for PE. |\n\n\n### peResource\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"peResource\"```                                |\n| Type     | ```std::vector<std::tuple<std::vector<uint8_t>, gtirb::Offset, uint64_t>>```        |\n| Value    | A resource header, data length, and data pointer.           |\n| AttachedTo | gtirb::Module |\n| Note     | List of PE resources. A resource header, data length, and data pointer. |\n\n### profile\n\n| <!-- --> | <!-- -->                                                 |\n|----------|----------------------------------------------------------|\n| Label    | ```\"profile\"```                                          |\n| Type     | ```std::map<gtirb:UUID,uint64_t>```                      |\n| Key      | The gtirb::UUID of a gtirb::CodeBlock.                   |\n| Value    | The number of times that block was executed.             |\n| AttachedTo | gtirb::Module                                          |\n| Notes    | An entry in this table describes how many times a code block was executed. Blocks that are not present in this aux data table should be assumed to have a value of 0, indicating that they were not executed. |\n\n### functionNameProbabilities\n\n| <!-- -->   | <!-- -->                                                                                                                                                                                                                                |\n|------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| Label      | ```\"functionNameProbabilities\"```                                                                                                                                                                                                       |\n| Type       | ```std::map<std::string, std::map<gtirb::UUID, std::vector<std::tuple<std::string, std::string, float>>>>```                                                                                                                            |\n| Key        | Name of the tool that made the predictions.                                                                                                                                                                                             |\n| Value      | Map from function UUID to a list of weighted predictions.  Each prediction is a tuple of <function name, binary name, score> where the score's meaning is tool dependent. Several existing tools use the convention that higher score is a better match and values ranging from 0.0 to 1.0.                                                      |\n| AttachedTo | gtirb::Module                                                                                                                                                                                                                           |\n| Notes      | Used to collect results from tools that identify functions and their source libraries.  Source library information is tracked in [includedLibraryNames](#includedlibrarynames) and [includedlibraryVersions](#includedlibraryversions). |\n\n\n### includedLibraryNames\n\n| <!-- -->   | <!-- -->                                 |\n|------------|------------------------------------------|\n| Label      | ```\"includedLibraryNames\"```             |\n| Type       | ```std::map<gtirb::UUID, std::string>``` |\n| Key        | Included library UUID.                   |\n| Value      | The name of the library.                 |\n| AttachedTo | gtirb::Module                            |\n| Notes      | Names of libraries that are included in an executable (i.e., their code is intermingled with the executable code). |\n\n\n### includedlibraryVersions\n\n| <!-- -->   | <!-- -->                                                                                                              |\n|------------|-----------------------------------------------------------------------------------------------------------------------|\n| Label      | ```\"includedLibraryVersions\"```                                                                                       |\n| Type       | ```std::map<gtirb::UUID, std::string>```                                                                              |\n| Key        | Included library UUID.                                                                                                |\n| Value      | Version string for the included library.                                                                              |\n| AttachedTo | gtirb::Module                                                                                                         |\n| Notes      | Versions of libraries that are included in an executable (i.e., their code is intermingled with the executable code). |\n\n\n### sectionProperties\n\n| <!-- --> | <!-- -->                                       |\n|----------|------------------------------------------------|\n| Label    | ```\"sectionProperties\"```                                |\n| Type     | ```std::map<gtirb::UUID, std::tuple<uint64_t, uint64_t>>>>```        |\n| Key      | The gtirb::UUID of a section. |\n| Value    | The tuple with the ELF section types and flag.           |\n| AttachedTo | gtirb::Module |\n| Note     | Map from section UUIDs to tuples with the ELF section types and flags. |\n\n\n### typeTable\n\n| <!-- -->   | <!-- -->                                                                                                                                                                                                                                                                                                                    |\n|------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| Label      | ```\"typeTable\"```                                                                                                                                                                                                                                                                                                          |\n| Type       | ```std::map<gtirb::UUID, std::variant<uint64_t, std::tuple<uint8_t>, std::tuple<int8_t, uint64_t>, uint64_t, uint64_t, std::tuple<gtirb::UUID, std::vector<gtirb::UUID>>, gtirb::UUID, std::tuple<gtirb::UUID, uint64_t>, tuple<uint64_t, std::vector<tuple<uint64_t, gtirb::UUID>>>, std::tuple<uint8_t>, gtirb::UUID>>``` |\n| Key        | UUID of the type object                                                                                                                                                                                                                                                                                                     |\n| Value      | Variant of the object type, where the variants field each represent: Unknown, Bool, Int, Char, Float, Function, Pointer, Array, Struct, Void, Alias, in that order.                                                                                                                                                         |\n| AttachedTo | gtirb::Module                                                                                                                                                                                                                                                                                                               |\n| Notes      | Contains structured type information about objects in the variant. Some empty tuples have been replaced with ```std::tuple<uint8_t>``` which is default-initialized to zero since some GTIRB implementations cannot store a 0-length tuple. The corresponding semantics of each type's variant field is the following:<br>- **Unknown**: ```uint64_t``` - Size of the unknown type<br>- **Bool**: ```std::tuple<uint8_t>``` - default initialized to zero<br>- **Int**: ```std::tuple<int8_t, uint64_t>``` - A tuple of signedness (1 for signed, 0 for unsigned) and width of int<br>- **Char**: ```uint64_t``` - Size of the character<br>- **Float**: ```uint64_t``` - size of the floating point number<br>- **Function**: ```std::tuple<gtirb::UUID, std::vector<gtirb::UUID>>``` - A tuple of return type UUID, and a list of parameter type UUIDs<br>- **Pointer**: ```gtirb::UUID``` - UUID of pointed-to type<br>- **Array**: ```std::tuple<gtirb::UUID, uint64_t>``` - A tuple of UUID of the elements of the array, and the number of element sin that array<br>- **Alias**: ```gtirb::UUID``` - The type being aliased (note this is effectively a `typedef`)<br>- **Struct**: ```tuple<uint64_t, std::vector<std::tuple<uint64_t, gtirb::UUID>>>``` - A tuple of the size of the structure in total, and a vector of its fields. Each field is represented as a tuple of the offset at which the field is located, and the UUID of the type of that field.<br>- **Void**: ```std::tuple<uint8_t>``` - default initialized to zero |\n\n### prototypeTable\n\n\n| <!-- -->   | <!-- -->                                   |\n|------------|--------------------------------------------|\n| Label      | ```\"prototypeTable\"```                     |\n| Type       | ```std::map<gtirb::UUID, gtirb::UUID>```   |\n| Key        | UUID of the function                       |\n| Value      | UUID of the function type in the typeTable |\n| AttachedTo | gtirb::Module                              |\n| Notes      | Maps functions' UUIDs to their associated typeTable entry for the purpose of giving them prototypes. NOTE: The associated type table entry **must** be a Function type object. |\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# 2.3.2 (Unreleased)\n\n# 2.3.1\n\n* Fix auxdata table `elfSectionProperties` to `sectionProperties` in the java api\n  to match the cpp and python api\n* Switched to use tox for testing the python API.\n\n# 2.3.0\n\n* Fixed a compatibility problem in the Python API that prevented using recent\n  releases of protobuf. The Python API on PyPI now requires protobuf 4.21.1 or\n  newer.\n* Building the Python API now requires protobuf compiler version 3.19 or later\n  for the generated definitions to be compatible with recent protobuf packages.\n  The API can still be built with older protobuf compilers, but the result will\n  not be compatible with recent protobuf packages.\n* Added support in the C++ API for deserializing set AuxData into unordered_sets.\n* Fixed issue causing compile errors when building with Boost 1.86+.\n* Building the C++ API now requires Boost 1.68 or later.\n* Fixed an obscure build error caused by a missing protobuf compiler. CMake now\n  explicitly checks for the protobuf compiler before generating build files.\n\n# 2.2.0\n\n* Move the following utility functions into the `gtirb` namespace:\n  `alignAddr`, `alignmentAdjustment`, `BumpPtrAllocator`, `isPowerOf2_64`,\n  `SpecificBumpPtrAllocator`, `cast`, `cast_or_null`, `dyn_cast`,\n  `dyn_cast_or_null`, `isa`. For backwards compatibility, these functions\n  remain available, but deprecated, in the global namespace unless\n  `GTIRB_WRAP_UTILS_IN_NAMESPACE` is defined.\n\n# 2.1.0\n\n* Stop generating debian metapackages and packages with the version attached\n  to the package name. Updates in the apt-repository now support multiple\n  package versions and upgrading `gtirb` with `apt-get upgrade`.\n* Fix performance issue when checking references of ProxyBlocks in Python API.\n* Add elfSoname AuxData definition\n* ByteInterval's blocks' sort order is now thoroughly defined: offset, size,\n  kind, decode mode, and UUID. Adjusting these properties during iteration may\n  cause blocks to be skipped or visited twice.\n* Added ByteInterval methods to the Python API to look up blocks by offset on.\n\n# 2.0.0\n\n* The Java API has been substantially reworked. Including:\n  * Most of the core API classes now have a more polished interface.\n  * The API for handling AuxData has been completely redesigned.\n  * New testing infrastructure based on JUnit5 has been added.\n  * More extensive test cases have been added.\n* Add elfStackExec and elfStackSize AuxData definitions\n* Add `IR.modules_named` helper method to Python API.\n* Add `IR.findModules(String name)` helper method to Java API.\n\n# 1.12.0\n\n* Add elfDynamicInit and elfDynamicFini AuxData definitions\n\n# 1.11.0\n\nNote that this release, due to changes to the protobuf definitions of symbolic\nexpression attributes, is backwards-incompatible with previous GTIRB files.\n\n* Replace symbolic expression attributes with composable labels.\n\n# 1.10.9\n\n* Added support for bool values in AuxData.\n* Added elfSymbolVersions provisional AuxData definition.\n* The GTIRB file format has changed to include a prefix containing a \"magic\"\n  identifier and the GTIRB protobuf version number to allow easier id of\n  GTIRB files. The change is not backwards compatible. Newer versions of\n  GTIRB will not be able to load older GTIRB files.\n* Converted the decode mode from an arbitrary integer into a ProtoBuf enum.\n  This obviously breaks compatibility with older GTIRB files.\n\n# 1.10.8\n\n* Ubuntu 18 and gcc7 are no longer supported.\n\n\n# 1.10.7\n\n* Added support for floating-point numbers in AuxData.\n* Disabled testing the Python API using `setup.py test`. The tests can still be\n  run using ctest or Python's unittest module.\n* Improved the performance of the Python API's ByteBlock.references property.\n* Fixed a pair of bugs in C++ support for variants in AuxData\n\n# 1.10.6\n\n* Added type annotations to python API and made them available in package.\n* Removed install-python target.\n\n# 1.10.5\n\n* Added various symbolic expression attributes.\n* Updated Java API\n\n# 1.10.4\n\n* Removed SymStackConst support\n* Added variant (union) support for AuxData\n* Removed address and size from modules\n* Modified Module::findSections(string) to return a range instead of iterator\n* Added IR::findSection(string) to C++ API\n\n# 1.10.3\n\n* Added offset helpers to Python API\n* Better support for `std::byte` when working with `ByteInterval`\n* Fixed a bug which manifested when serializing a big-endian IR\n\n# 1.10.2\n\n* Updated \"address\" iteration order to compare size if addresses are the same\n  and UUIDs if addresses and sizes are the same so that it can be used to\n  store objects in ordered containers.\n* Fixed some bugs where modifying an object's address or size would cause\n  findNodeOn to return incorrect results.\n* Improved performance of findNodeOn and findNodeAt queries.\n\n# 1.10.1\n\n* Added module-level endianess flag, for use in archtectures with multiple\n  possible endians for its code blocks.\n* Introduce iteration helpers cfgPredecessors and cfgSuccessors.\n\n# 1.9.0\n\n* Introduce attributes for symbolic expressions to the core IR.\n* Reduce asymptotic complexity of iterating over blocks in a large number of\n  byte intervals.\n* Fixed bug where searching for blocks by address could return incorrect matches.\n* Fixed bug where `ByteInterval::addBlock` would refuse to move an existing\n  block to a new offset if it was already present.\n\n# 1.8.5\n\n* Make Python Offset objects immutable and make Offsets equivalent when they\n  refer to the same displacement from the same element.\n\n# 1.8.4\n\n* Fix bug where Symbol iteration could get out of order when symbols refer to\n  blocks in byte intervals that are relocated.\n\n# 1.8.3\n\n* Fix bug that didn't add CodeBlocks to the CFG if the CodeBlocks were added to\n  a ByteInterval before it was added to the IR.\n\n# 1.8.2\n\n* The C++ API build no longer generates a `libgtirb.so.1` symlink. This has the\n  effect of requiring clients to link against the full version number (e.g.,\n  `libgtirb.so.1.8.2`) to ensure ABI compatibility while we continue to make\n  rapid improvements to the library.\n\n# 1.5.0\n\n* In the Python API:\n  * Removed `Node.from_uuid` and added `get_by_uuid` to `IR`s.\n    This changes UUID lookup from a global cache to a per-IR cache;\n    this means you can now have two IRs exist that share UUIDs but have\n    different contents, for example.\n  * Added convienience properties to all node types to find the parent nodes\n    they belong to.\n\n# 1.4.6\n\n* Implement std::hash for Addr objects.\n\n# 1.4.5\n\n* Explicitly disable copy and move constructors for the Node class hierarchy in\n  C++. This avoids a class of errors where nodes cannot be found by\n  Node::getByUUID.\n\n# 1.4.4\n\n* Build/install libgtirb.so.1 symlink on linux.\n\n# 1.4.3\n* Remove the python-egg cmake target, add the python-wheel cmake target\n\n# 1.4.2\n\n* Don't use __declspec(dllimport) on Windows.\n\n# 1.4.1\n\n* Add ISA enums for PPC64, ARM64, MIPS32, and MIPS64.\n\n# 1.3.2\n\n* Access functions for converting to/from protobuf are no longer public in the C++ API.\n* The proto library is no longer dllexported.\n* GTIRB_EXPORT_API no longer uses dllimport on the client side.\n\n# 1.3.1\n\n* No longer installs Python files by default. Added a new 'install-python'\n  target to install Python files.\n\n# 1.3.0\n\n* Added a new field to symbols, `at_end`, which allows symbols to point to the end\n  of their referents as well as the beginning.\n\n# 1.2.1\n\n* Moved protobuf definitions into gtirb.proto package (gtirb::proto namespace\n  in C++).\n* Installing the Python API now respects CMAKE_INSTALL_PREFIX and DESTDIR with\n  their usual semantics.\n\n# 1.2.0\n\n* AuxData and AuxDataContainer in the C++ API have been reworked to provide cleaner type safety.\n  * AuxData is now retrieved directly from an AuxDataContainer using\n\ta schema class that specifies both the name of the AuxData object\n\tas well as its type.\n  * Schemata for AuxData types must be registered at process startup\n    before GTIRB objects are constructed or unserialized.\n\n# 1.1.1\n\n* Fixed a bug where changing the address of a block caused lookups of symbol\n  by address to fail in some cases.\n\n# 1.1.0\n\n* Added a new API for accessing GTIRB, written in Java. This API is not yet\n  released, and as such, has missing features, is not yet documented, and may\n  change at any time. For more information, look at the contents of the `java`\n  directory.\n\n# 1.0.0\n\nThis is a major backwards-incompatible release.  The protobuf\nspecification has changed significantly resulting in protobuf version\n1 which is now tracked in `version.txt` in the base of this\nrepository.  (The original protobuf version was version 0.)  The\nchanges in this release are primarily intended to enable *binary\nrewriting* use cases on GTIRB.  Other changes to the protobuf\nspecification are for more general cleanup, simplification, and\nclarification.  In addition, a new Common Lisp GTIRB API is now\nincluded along with the C++ and Python APIs.  A list of specific\nchanges follows.  Complete documentation of all new objects and\nstructures is provided in the GTIRB manual.\n\n* A `version` field is now present on GTIRB IR instances.  The value\n  of this field is now `1`.  The old value of `0` is the protobuf\n  default for a missing field.\n* The control flow graph (CFG) is now a child of the IR instead of\n  living under a specific module.  This means that a multi-module IR\n  now has a single pan-module CFG.\n* The `Block` object has been renamed to `CodeBlock` and the\n  `DataObject` to `DataBlock`.\n* A new object has been added to the GTIRB `Section`s named\n  `ByteInterval`s.  This replaces the `ByteMap` in the previous GTIRB\n  version.  A `ByteInterval` has:\n  * An *optional* fixed address indicating its location in memory.\n    Without an address the location of the `ByteInterval` is not\n    specified allowing it to float to enable easier binary rewriting.\n  * A `size` specifying the extend of the `ByteInterval` in memory.\n    If this size is larger than the contents of the `ByteInterval`\n    then the extension of the `ByteInterval` in memory beyond the end\n    of the contents is un-allocated.\n  * A byte vector named `contents` holding the contents of the `ByteInterval`.\n  * A map from offsets to symbolic expressions.\n  * A list of blocks holding `CodeBlock`s and `DataBlock`s.\n* The `address` field has been removed from `Block`s.\n* The `address` and `size` fields have been removed from `Section`s.\n* An offset from the start of their `ByteInterval` have been added to blocks.\n* The following fields have been removed from `Module`s:\n  * `image_byte_map`\n  * `symbolic_operands`\n  * `blocks` and\n  * `data`.\n* An entry point stored as a `CodeBlock` has been added to `Module`s.\n* A list of `ByteIntervals` has been added to `Section`s.\n* The `ISAID` enumeration on module is renamed to `ISA`.\n* Instead of an `AuxDataContainer` object we now hold a\n  `map<string, AuxData>` on modules and IRs.\n* The following GTIRB enumerations are modified: `ISA`, `FileFormat`,\n  `SymbolKind`, and `SectionFlag`.  The goals of these modifications\n  is to simplify the enumerations and ensure that all included options\n  are both necessary and orthogonal.\n* Sections now include have `SectionFlag`s to store common properties\n  such as `readable`, `writeable`, or `executable`.\n\n# 0.3.0\n\n* You can now enable and disable the building of certain APIs when calling CMake,\n  via the following flags:\n  * `GTIRB_CXX_API` to control the building of the C++ API, on by default\n  * `GTIRB_PY_API` to control the building of the Python API, on by default if `python3` is installed on your system\n* The following changes have been made to the Python API:\n  * `Serialization.decode` can now take a `bytes` object\n    in addition to a `BytesIO` object.\n  * If an unknwon type is encountered while decoding `AuxData`,\n    it will be placed in `data` as a `bytes`-like object\n    instead of throwing a `DecodeError`.\n    Unknown data decoded this way can be then encoded again.\n    It is still an error to encode unknown types of auxdata\n    not in the manner described above.\n* ImageByteMap::setData() has been extended to support arbitrary iterator types.\n* We now build documentation for the Python API using\n  [Sphinx](https://www.sphinx-doc.org/en/master/). To generate all\n  documentation locally, call `make doc` after calling `cmake`; this will\n  generate both C++ and Python API documentation. To only make one or the\n  other, call `make doxy` or `make sphinx`, respectively.\n  * Making the Sphinx documentation will require the following Python packages:\n    ```bash\n    pip3 install sphinx sphinx-autodoc-typehints\n    ```\n\n# 0.2.0\n\n* Added a new Python API, meant to be a high-level wrapper over the\n  Protobuf-generated one. To make use of it, add the `python` folder\n  from your build directory to your `PYTHONPATH`. The package is named `gtirb`.\n* CMake now won't automatically download and install its dependencies,\n  so that the user has control over which versions are in use.\n  The version requirements for Boost and Protobuf are listed in `README.md`.\n* Updated the sanctioned AuxData definitions.\n* Fix for build issue when using Boost 1.71.0.\n\n# 0.1.1\n\n* Initial public release.\n"
  },
  {
    "path": "CMakeLists.googletest",
    "content": "cmake_minimum_required(VERSION 2.8.2)\n\nproject(googletest-download NONE)\n\ninclude(ExternalProject)\nexternalproject_add(\n  googletest\n  GIT_REPOSITORY https://github.com/google/googletest.git\n  GIT_TAG v1.15.2\n  SOURCE_DIR \"${CMAKE_BINARY_DIR}/googletest-src\"\n  BINARY_DIR \"${CMAKE_BINARY_DIR}/googletest-build\"\n  CONFIGURE_COMMAND \"\"\n  BUILD_COMMAND \"\"\n  INSTALL_COMMAND \"\"\n  TEST_COMMAND \"\"\n)\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "#\n# Cmake Configuration\n#\n\n# Need 3.10 to support CXX_STANDARD=17 and protobuf::protoc\ncmake_minimum_required(VERSION 3.10.0)\n\n# The version.txt file is the official record of the version number. We use the\n# contents of that file to set the project version for use in other CMake files.\nfile(READ \"${CMAKE_CURRENT_SOURCE_DIR}/version.txt\" ver)\n\nstring(REGEX MATCH \"VERSION_MAJOR ([0-9]*)\" _ ${ver})\nset(GTIRB_MAJOR_VERSION ${CMAKE_MATCH_1})\n\nstring(REGEX MATCH \"VERSION_MINOR ([0-9]*)\" _ ${ver})\nset(GTIRB_MINOR_VERSION ${CMAKE_MATCH_1})\n\nstring(REGEX MATCH \"VERSION_PATCH ([0-9]*)\" _ ${ver})\nset(GTIRB_PATCH_VERSION ${CMAKE_MATCH_1})\n\nstring(REGEX MATCH \"VERSION_PROTOBUF ([0-9]*)\" _ ${ver})\nset(GTIRB_PROTOBUF_VERSION ${CMAKE_MATCH_1})\n\ncmake_policy(SET CMP0048 NEW)\nproject(\n  GTIRB\n  VERSION \"${GTIRB_MAJOR_VERSION}.${GTIRB_MINOR_VERSION}.${GTIRB_PATCH_VERSION}\"\n)\nset(PACKAGE_BRANCH master)\n\ninclude(CheckFunctionExists)\ninclude(CheckCXXSourceCompiles)\ninclude(CheckIncludeFile)\ninclude(Macros.cmake)\ninclude(AlignOf.cmake)\ninclude(CMakePackageConfigHelpers)\n\noption(ENABLE_CONAN \"Use Conan to inject dependencies\" OFF)\n\nif(ENABLE_CONAN)\n  set(CONAN_SYSTEM_INCLUDES ON)\n  include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)\n  conan_basic_setup()\nendif()\n\n# ---------------------------------------------------------------------------\n# Build options\n# ---------------------------------------------------------------------------\n\nset(GTIRB_MSVC_PARALLEL_COMPILE_JOBS\n    \"0\"\n    CACHE\n      STRING\n      \"Number of parallel compiler jobs used for Visual Studio compiles. 0 means use all processors. Default is 0.\"\n)\n\noption(GTIRB_ENABLE_TESTS \"Enable building and running unit tests.\" ON)\noption(GTIRB_ENABLE_MYPY \"Enable checking python types with mypy.\" ON)\n\n# This just sets the builtin BUILD_SHARED_LIBS, but if defaults to ON instead of\n# OFF.\noption(GTIRB_BUILD_SHARED_LIBS \"Build shared libraries.\" ON)\nif(GTIRB_BUILD_SHARED_LIBS)\n  set(BUILD_SHARED_LIBS ON)\nelse()\n  set(BUILD_SHARED_LIBS OFF)\nendif()\nif(UNIX AND NOT BUILD_SHARED_LIBS)\n  # Find only static libraries\n  set(CMAKE_FIND_LIBRARY_SUFFIXES \".a\")\n  add_compile_options(-static)\nendif()\n\nenable_testing()\n\n# Set ENABEL_CODE_COVERAGE to default off, unless you want to test c++ coverage\noption(ENABLE_CODE_COVERAGE\n       \"Build with instrumentation for collecting code coverage\" OFF\n)\n\nif(ENABLE_CODE_COVERAGE)\n  if(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU OR ${CMAKE_CXX_COMPILER_ID} STREQUAL\n                                              Clang\n  )\n    add_compile_options(--coverage)\n    link_libraries(--coverage)\n  else()\n    message(FATAL_ERROR \"no support for code coverage on this target\")\n  endif()\nendif()\n\n# Whether or not to run clang-tidy (if present)\noption(GTIRB_RUN_CLANG_TIDY \"Enable running of clang-tidy.\" ON)\n\n# Define the cache variables for the API options.\noption(GTIRB_CXX_API \"Whether or not the C++ API is built.\" ON)\noption(GTIRB_PY_API \"Whether or not the Python API is built.\" ON)\noption(GTIRB_CL_API \"Whether or not the Common Lisp API is built.\" ON)\noption(GTIRB_JAVA_API \"Whether or not the Java API is built.\" ON)\n\n# Determine whether or not to strip debug symbols and set the build-id. This is\n# only really needed when we are building ubuntu *-dbg packages\noption(GTIRB_STRIP_DEBUG_SYMBOLS\n       \"Whether or not to strip debug symbols and set the build-id.\" OFF\n)\n\noption(\n  GTIRB_RELEASE_VERSION\n  \"Whether or not to build package versions without dev/SNAPSHOT suffixes.  Applies to the python and java APIs.\"\n  OFF\n)\n\n# Determine whether or not the APIs are REALLY built or not.\n# === C++ ===\nset(CXX_API ${GTIRB_CXX_API})\n\n# === Python ===\nset(PY_API ${GTIRB_PY_API})\nif(GTIRB_PY_API)\n  gtirb_find_python()\n\n  if(PYTHON)\n    set(PYTHON_MINIMUM_VERSION \"3.6\")\n    if(\"${Python3_VERSION}\" VERSION_LESS \"${PYTHON_MINIMUM_VERSION}\")\n      message(\n        WARNING\n          \"${PYTHON} --version is ${Python3_VERSION}, which is less than the minimum required, ${PYTHON_MINIMUM_VERSION}; disabling building of API.\"\n      )\n      set(PY_API OFF)\n    endif()\n  else()\n    message(\n      WARNING\n        \"Python interpreter not found; disabling building of Python API.\nIf this is in error, try giving -DPYTHON=... to CMake to specify what program to use.\"\n    )\n    set(PY_API OFF)\n  endif()\nendif()\n\n# === Common Lisp ===\n# TODO: test the CL API on other CL interpreters and search for those in\n# addition to SBCL when looking for a default CL interpeter\nset(CL_API ${GTIRB_CL_API})\nif(GTIRB_CL_API)\n  find_program(LISP \"sbcl\")\n  set(QUICKLISP\n      \"$ENV{HOME}/quicklisp\"\n      CACHE STRING \"The Quicklisp installation to use.\"\n  )\n  set(LISP_MINIMUM_VERSION \"1.4.5\")\n\n  if(NOT LISP)\n    message(\n      WARNING\n        \"Lisp interpreter not found; disabling building of Lisp API.\nIf this is in error, try giving -DLISP=... to CMake to specify what program to use.\"\n    )\n    set(CL_API OFF)\n  elseif(NOT EXISTS \"${QUICKLISP}\")\n    message(\n      WARNING\n        \"Quicklisp installation not found; disabling building of Lisp API.\nIf this is in error, try giving -DQUICKLISP=... to CMake to specify what directory to use.\"\n    )\n    set(CL_API OFF)\n  else()\n    execute_process(COMMAND \"${LISP}\" \"--version\" OUTPUT_VARIABLE LISP_VERSION)\n    string(REPLACE \"SBCL\" \"\" LISP_VERSION \"${LISP_VERSION}\")\n    string(REPLACE \".debian\" \"\" LISP_VERSION \"${LISP_VERSION}\")\n\n    if(\"${LISP_VERSION}\" VERSION_LESS \"${LISP_VERSION}\")\n      message(\n        WARNING\n          \"${LISP} --version is ${LISP_VERSION}, which is less then the minimum required, ${LISP_MINIMUM_VERSION}; disabling building of API.\"\n      )\n      set(CL_API OFF)\n    endif()\n  endif()\nendif()\n\n# === Java ===\nset(JAVA_API ${GTIRB_JAVA_API})\nif(GTIRB_JAVA_API)\n  find_package(Java 1.8.0 COMPONENTS Development)\n  if(NOT JAVA_FOUND)\n    message(WARNING \"Java 8 compiler not found; disabling building of Java API.\nIf this is in error, try setting the environment variable $JAVA_HOME.\"\n    )\n    set(JAVA_API OFF)\n  else()\n    find_program(MVN mvn)\n    if(NOT MVN)\n      message(\n        WARNING\n          \"Maven not found; disabling building of Java API. If this is in \"\n          \"error, try setting -DMVN=<path-to-maven> on the CMake command-line\"\n      )\n      set(JAVA_API OFF)\n    endif()\n  endif()\nendif()\n\n# Documentation options.\noption(GTIRB_DOCUMENTATION \"Whether or not documentation is built.\" ON)\n\n# ---------------------------------------------------------------------------\n# Global settings\n# ---------------------------------------------------------------------------\n\nset_property(GLOBAL PROPERTY USE_FOLDERS ON)\nset(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src)\nif(WIN32)\n  set(CMAKE_DEBUG_POSTFIX\n      \"d\"\n      CACHE STRING \"add a postfix, usually d on windows\"\n  )\nendif()\nset(CMAKE_RELEASE_POSTFIX\n    \"\"\n    CACHE STRING \"add a postfix, usually empty on windows\"\n)\nset(CMAKE_RELWITHDEBINFO_POSTFIX\n    \"\"\n    CACHE STRING \"add a postfix, usually empty on windows\"\n)\nset(CMAKE_MINSIZEREL_POSTFIX\n    \"\"\n    CACHE STRING \"add a postfix, usually empty on windows\"\n)\nset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)\nset(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)\nset(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)\n\nif(CXX_API)\n  # Use C++17\n  set(CMAKE_CXX_STANDARD 17)\n  # Error if it's not available\n  set(CMAKE_CXX_STANDARD_REQUIRED ON)\n\n  # Specifically check for gcc-7 or later. gcc-5 is installed on many systems\n  # and will accept -std=c++17, but does not fully support the standard.\n  if(CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\")\n    if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS \"7.0.0\")\n      message(FATAL_ERROR \"gcc 7 or later is required to build gtirb\")\n    endif()\n  endif()\n\n  set(CMAKE_CXX_VISIBILITY_PRESET hidden)\n\n  #\n  # Global Options (Compile / Link)\n  #\n  add_compile_options(-DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION)\n\n  # MSVC-specific Options\n  if(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)\n    if(NOT GTIRB_MSVC_PARALLEL_COMPILE_JOBS STREQUAL \"1\")\n      if(GTIRB_MSVC_PARALLEL_COMPILE_JOBS STREQUAL \"0\")\n        add_compile_options(-MP)\n        message(STATUS \"Parallel compilation enabled\")\n      else()\n        add_compile_options(-MP${GTIRB_MSVC_PARALLEL_COMPILE_JOBS})\n        message(\n          STATUS\n            \"Parallel compilation with ${GTIRB_MSVC_PARALLEL_COMPILE_JOBS} jobs\"\n        )\n      endif()\n    else()\n      message(STATUS \"Parallel compilation disabled\")\n    endif()\n\n    add_compile_options(-D_CRT_SECURE_NO_WARNINGS)\n    add_compile_options(-D_MBCS)\n    add_compile_options(-D_SCL_SECURE_NO_WARNINGS)\n    # We need to add both so that there is not a mismatch between Win32 SDK\n    # headers (which use UNICODE) and C Standard Library headers (which use\n    # _UNICODE).\n    add_compile_options(-D_UNICODE)\n    add_compile_options(-DUNICODE)\n    add_compile_options(-D_WIN32)\n    # Disable macro definitions for min and max that conflict with the STL.\n    add_compile_options(-DNOMINMAX)\n    # Enable RTTI. FIXME: stop using typeid so we can disable this and add -fno-\n    # rtti to the Clang/GCC compiler options.\n    add_compile_options(-GR)\n    # Enable exceptions, which are basically required because of our reliance on\n    # boost.\n    add_compile_options(-EHsc)\n    # Enabled a sensible warning level and treat all warnings as errors.\n    add_compile_options(-W4)\n    add_compile_options(-WX)\n\n    # Enable bigobj support, otherwise IR.cpp and Module.cpp will refuse to\n    # compile due to execeeding the number of sections allowed in an object\n    # file. FIXME: we should not have that many template instantiations.\n    add_compile_options(-bigobj)\n\n    add_compile_options(-sdl) # Enable extra security checks\n    add_compile_options(-permissive-) # Disable permissive mode\n\n    add_compile_options(-wd4996) # VC8: Deprecated libc functions.\n    # This is a warning about a change in behavior from old versions of visual\n    # c++.  We want the new (standard-compliant) behavior, so we don't want the\n    # warning.  The warning is that using an array in a class initializer list\n    # will cause its elements to be default initialized.\n    add_compile_options(-wd4351)\n    add_compile_options(-wd4146) # unary minus operator applied to unsigned\n                                 # type, result still unsigned\n\n    # C4505: 'google::protobuf::internal::MapField<...>::ContainsMapKey':\n    # unreferenced local function has been removed\n    add_compile_options(-wd4505)\n\n    # C4267: protobuf-generated headers, at least w/ protobuf 3.9.1, trigger\n    # MSVC's \"conversion from 'size_t' to 'int', possible loss of data\" warning.\n    add_compile_options(-wd4267)\n\n    # Release target options\n    add_compile_options($<$<CONFIG:Release>:-GL>) # Enable whole program\n                                                  # optimization\n    add_link_options($<$<CONFIG:Release>:-ltcg>) # Enable link-time code\n                                                 # generation\n  elseif((${CMAKE_CXX_COMPILER_ID} STREQUAL GNU) OR (${CMAKE_CXX_COMPILER_ID}\n                                                     STREQUAL Clang)\n  )\n    add_compile_options(-Wall -Wextra -Wpointer-arith -Wshadow -Werror)\n    add_compile_options(-fPIC)\n  endif()\nendif()\n\n# ---------------------------------------------------------------------------\n# Boost\n# ---------------------------------------------------------------------------\nif(CXX_API)\n  find_package(Boost 1.68 REQUIRED)\n\n  add_compile_options(-DBOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE)\n  add_compile_options(-DBOOST_SYSTEM_NO_DEPRECATED)\n\n  # Boost versions 1.70.0+ may use Boost's provided CMake support rather than\n  # CMake's internal Boost support. The former uses \"Boost::boost\" and so on,\n  # while the latter uses \"Boost_BOOST\" and so on. This normalizes the two cases\n  # to use Boost_INCLUDE_DIRS and Boost_LIBRARIES.\n  if(TARGET Boost::headers)\n    get_target_property(\n      Boost_INCLUDE_DIRS Boost::headers INTERFACE_INCLUDE_DIRECTORIES\n    )\n  endif()\n\n  include_directories(SYSTEM ${Boost_INCLUDE_DIRS})\nendif()\n\n# ---------------------------------------------------------------------------\n# Google Test Application\n# ---------------------------------------------------------------------------\nif(GTIRB_ENABLE_TESTS AND CXX_API)\n  # Pull in Google Test\n  # https://github.com/google/googletest/tree/master/googletest#incorporating-\n  # into-an-existing-cmake-project\n\n  # Download and unpack googletest at configure time\n  configure_file(CMakeLists.googletest googletest-download/CMakeLists.txt)\n\n  execute_process(\n    COMMAND \"${CMAKE_COMMAND}\" -G \"${CMAKE_GENERATOR}\" .\n    RESULT_VARIABLE result\n    WORKING_DIRECTORY \"${CMAKE_BINARY_DIR}/googletest-download\"\n  )\n\n  if(result)\n    message(WARNING \"CMake step for googletest failed: ${result}\")\n  endif()\n\n  execute_process(\n    COMMAND \"${CMAKE_COMMAND}\" --build .\n    RESULT_VARIABLE result\n    WORKING_DIRECTORY \"${CMAKE_BINARY_DIR}/googletest-download\"\n  )\n\n  if(result)\n    message(WARNING \"Build step for googletest failed: ${result}\")\n  endif()\n\n  # Prevent overriding the parent project's compiler/linker settings on Windows\n  set(gtest_force_shared_crt\n      ON\n      CACHE BOOL \"\" FORCE\n  )\n\n  # Add googletest directly to our build. This defines the gtest and gtest_main\n  # targets.\n  add_subdirectory(\n    \"${CMAKE_BINARY_DIR}/googletest-src\" \"${CMAKE_BINARY_DIR}/googletest-build\"\n    EXCLUDE_FROM_ALL\n  )\n\n  include_directories(\"${gtest_SOURCE_DIR}/include\")\nendif()\n\n# ---------------------------------------------------------------------------\n# JUnit Test Application\n# ---------------------------------------------------------------------------\nif(GTIRB_ENABLE_TESTS AND JAVA_API)\n  include(ExternalProject)\n  externalproject_add(\n    junit\n    PREFIX ${CMAKE_BINARY_DIR}/junit\n    URL \"https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone/1.10.0/junit-platform-console-standalone-1.10.0.jar\"\n    CONFIGURE_COMMAND \"\"\n    BUILD_COMMAND \"\"\n    INSTALL_COMMAND \"\"\n    TEST_COMMAND \"\"\n    DOWNLOAD_NO_EXTRACT ON\n  )\n\n  set(JUNIT_STANDALONE_JAR\n      ${CMAKE_BINARY_DIR}/junit/src/junit-platform-console-standalone-1.10.0.jar\n  )\nendif()\n\n# ---------------------------------------------------------------------------\n# protobuf\n# ---------------------------------------------------------------------------\nif(CL_API)\n  find_package(Protobuf 3.7.0 REQUIRED)\nelse()\n  find_package(Protobuf 3.0.0 REQUIRED)\nendif()\nif(NOT Protobuf_PROTOC_EXECUTABLE)\n  # find_package only fails if the protobuf libraries or headers cannot be\n  # found. It does not treat failing to find the protobuf compiler as an error,\n  # so we do that explicitly here.\n  message(\n    FATAL_ERROR\n      \"Could not find Protobuf compiler 'protoc'. Please make sure the \"\n      \"Protobuf compiler is installed.\"\n  )\nendif()\n\nif(Protobuf_VERSION VERSION_LESS 3.2)\n  add_definitions(-DPROTOBUF_SET_BYTES_LIMIT)\nendif()\n\nif(NOT BUILD_SHARED_LIBS)\n  set(Protobuf_USE_STATIC_LIBS ON)\nendif()\ninclude_directories(SYSTEM ${PROTOBUF_INCLUDE_DIRS})\n\nadd_subdirectory(proto)\n\n# ---------------------------------------------------------------------------\n# gtirb sources\n# ---------------------------------------------------------------------------\nif(CXX_API)\n  add_subdirectory(src)\nendif()\n\nif(PY_API)\n  add_subdirectory(python)\nendif()\n\nif(CL_API)\n  add_subdirectory(cl)\nendif()\n\nif(JAVA_API)\n  add_subdirectory(java)\nendif()\n\nif(GTIRB_DOCUMENTATION)\n  add_subdirectory(doc)\nendif()\n\n# ---------------------------------------------------------------------------\n# Export config for use by other CMake projects\n# ---------------------------------------------------------------------------\n\nif(CXX_API)\n  # --- For direct use from the build directory/cmake registry ---\n  # This exports the targets\n  export(TARGETS gtirb gtirb_proto\n         FILE \"${CMAKE_CURRENT_BINARY_DIR}/gtirbTargets.cmake\"\n  )\n  # This is the main config file that find_package will look for.\n  configure_file(\n    \"${CMAKE_CURRENT_LIST_DIR}/gtirbConfig.cmake.in\"\n    \"${CMAKE_CURRENT_BINARY_DIR}/gtirbConfig.cmake\" @ONLY\n  )\n  # Add the build directory to the user CMake registry, so find_package can\n  # locate it automatically.\n  export(PACKAGE gtirb)\n\n  # --- For the installed copy ---\n  # Main config file for find_package, includes the targets file and defines the\n  # check_gtirb_branch function.\n  if(NOT DEFINED PACKAGE_BRANCH)\n    set(PACKAGE_BRANCH \"No package branch specified\")\n  endif()\n  # FIXME: The installed version of gtirbConfig currently contains the\n  # check_gtirb_branch function, which requires users to explicitly call it. We\n  # ought to move this functionality to gtirbConfig-version, so that checking\n  # the gtirb version also checks the branch, requiring users to opt-out of the\n  # branch check, rather than opt-in by calling check_gtirb_branch. See: GitLab\n  # issue #93\n  configure_file(\n    \"${CMAKE_CURRENT_LIST_DIR}/gtirbConfig.cmake.in\"\n    \"${CMAKE_CURRENT_BINARY_DIR}/export/gtirbConfig.cmake\" @ONLY\n  )\n\n  # In this mode, find_package also seems to require a version file\n  set(version_file \"${CMAKE_CURRENT_BINARY_DIR}/gtirbConfig-version.cmake\")\n  write_basic_package_version_file(\n    ${version_file}\n    VERSION ${GTIRB_VERSION}\n    COMPATIBILITY AnyNewerVersion\n  )\n\n  # Copy the config files to the install location\n  install(\n    FILES ${CMAKE_CURRENT_BINARY_DIR}/export/gtirbConfig.cmake ${version_file}\n    DESTINATION lib/gtirb\n    COMPONENT cmake_config\n  )\n  # This exports the targets to the install location.\n  install(\n    EXPORT gtirbTargets\n    COMPONENT cmake_target\n    DESTINATION lib/gtirb\n  )\nendif()\n\n# ---------------------------------------------------------------------------\n# Package policy enforcement\n# ---------------------------------------------------------------------------\n\nif(GTIRB_PACKAGE_POLICY)\n  set(PACKAGE_POLICY ${GTIRB_PACKAGE_POLICY})\nelseif(ENABLE_CONAN OR WIN32)\n  set(PACKAGE_POLICY conan)\nelse()\n  set(PACKAGE_POLICY unix)\nendif()\n\nif(PACKAGE_POLICY STREQUAL \"unix\")\n\n  # Provides copyright file for Unix packages.\n  install(\n    FILES ${CMAKE_SOURCE_DIR}/LICENSE.txt\n    COMPONENT license\n    DESTINATION share/doc/gtirb\n    RENAME copyright\n  )\n\nelseif(PACKAGE_POLICY STREQUAL \"conan\")\n\n  # Provides LICENSE.txt for Conan packages\n  install(\n    FILES ${CMAKE_SOURCE_DIR}/LICENSE.txt\n    COMPONENT license\n    DESTINATION licenses\n  )\n\nendif()\n\n# ---------------------------------------------------------------------------\n# Package generation with cpack\n# ---------------------------------------------------------------------------\nset(CPACK_PROJECT_CONFIG_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cpack-config.cmake)\n\nset(CMAKE_PROJECT_HOMEPAGE_URL https://github.com/GrammaTech/gtirb)\nset(CPACK_PACKAGE_VERSION_MAJOR ${GTIRB_MAJOR_VERSION})\nset(CPACK_PACKAGE_VERSION_MINOR ${GTIRB_MINOR_VERSION})\nset(CPACK_PACKAGE_VERSION_PATCH ${GTIRB_PATCH_VERSION})\nset(CPACK_PACKAGE_VENDOR \"GrammaTech Inc.\")\nset(CPACK_PACKAGE_CONTACT gtirb@grammatech.com)\nset(CPACK_PACKAGE_DESCRIPTION_FILE ${CMAKE_CURRENT_SOURCE_DIR}/README.md)\nset(CPACK_PACKAGE_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.md)\nset(CPACK_PACKAGE_DESCRIPTION_SUMMARY\n    \"The GrammaTech Intermediate Representation for Binaries (GTIRB) is a machine code analysis and rewriting data structure.\"\n)\nset(CPACK_DEBIAN_PACKAGE_SECTION devel)\n\nstring(REGEX MATCH \"([^\\.]+)\\.([^\\.]+)\\.([^\\.]+)\" PROTOBUF_VERSION_MATCH\n             ${Protobuf_VERSION}\n)\nset(PROTOBUF_MAJOR_VERSION ${CMAKE_MATCH_1})\nset(PROTOBUF_MINOR_VERSION ${CMAKE_MATCH_2})\nset(PROTOBUF_PATCH_VERSION ${CMAKE_MATCH_3})\nmath(EXPR NEXT_PROTOBUF_PATCH \"${PROTOBUF_PATCH_VERSION}+1\")\nset(CPACK_PROTOBUF_VERSION_UPPER_BOUND\n    \"${PROTOBUF_MAJOR_VERSION}.${PROTOBUF_MINOR_VERSION}.${NEXT_PROTOBUF_PATCH}\"\n)\nset(CPACK_PROTOBUF_VERSION_LOWER_BOUND \"${Protobuf_VERSION}\")\nset(CPACK_GTIRB_VERSION \"${GTIRB_VERSION}\")\nset(CPACK_SOURCE_DIR ${CMAKE_SOURCE_DIR})\n\ninclude(CPack)\n\n# ---------------------------------------------------------------------------\n# Report APIs and features built\n# ---------------------------------------------------------------------------\n\nmessage(\"APIs to be built:\")\nmessage(\"    C++     ${CXX_API}\")\nmessage(\"    Python  ${PY_API}\")\nmessage(\"    Lisp    ${CL_API}\")\nmessage(\"    Java    ${JAVA_API}\")\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n  advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies within all project spaces, and it also applies when\nan individual is representing the project or its community in public spaces.\nExamples of representing a project or community include using an official\nproject e-mail address, posting via an official social media account, or acting\nas an appointed representative at an online or offline event. Representation of\na project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at gtirb-conduct@grammatech.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Contributing\n============\n\n\n## Code of Conduct\n\nPlease read the [GTIRB Code of Conduct](CODE_OF_CONDUCT.md).\n\n## General Guidelines\n\n- Text files may not have trailing whitespace.\n\n- Text files must end with a trailing newline.\n\n- All tests should be able to run and pass.\n  This can be checked by running `make check` on your build directory\n  after running `cmake`.\n\n- All CMake files shall be formatted with\n  [cmake-format](https://pypi.org/project/cmake-format/).  A\n  `.cmake-format` file is provided in the root directory for the\n  project, and a pass through this tool is included as part of our\n  `pre-commit` configuration (see below for details).\n\n- The GTIRB version saved in `version.txt` uses\n  [semantic versioning](https://semver.org)\n\n- We also track a Protobuf version number in `version.txt` (as\n  `VERSION_PROTOBUF`).  This number is incremented whenever our\n  protobuf files (under `proto/` in the GTIRB repository) are changed\n  in any way that affects the serialized protobuf -- even if the\n  change could potentially be backwards compatible because of the way\n  protobuf gracefully handles unknown new fields.\n\n- We ask that all contributors complete our Contributor License\n  Agreement (CLA), which can be found at\n  [GrammaTech-CLA-GTIRB.pdf](./GrammaTech-CLA-GTIRB.pdf), and email\n  the completed form to `CLA@GrammaTech.com`.  Under this agreement\n  contributors retain the copyright to their work but grants\n  GrammaTech unlimited license to the work.\n\n### pre-commit\n\nIn general, code must follow a unified format. To make compliance with\nthis format easier, we recommend the use of\n[`pre-commit`](https://pre-commit.com/) with the provided\nconfiguration file, `.pre-commit-config.yaml`, to manage formatting.\nTo use `pre-commit`:\n\n1. If `pre-commit` is not already installed on your system, install it\n   now with [`pip`](https://pypi.org/project/pip/).\n   ```shell\n      pip3 install pre-commit\n   ```\n2. If [`clang-format`](https://clang.llvm.org/docs/ClangFormat.html)\n   is not already installed on your system, install it now.\n3. Install the formatters as a pre-commit hook. In the gtirb root directory:\n   ```shell\n    pre-commit install\n   ```\n   If you prefer to run `pre-commit` manually instead, run this before all commits:\n   ```shell\n   pre-commit run\n   ```\n\n## C++ Code Requirements\n\n- All code shall be formatted with [clang-format](https://clang.llvm.org/docs/ClangFormat.html).\n  A `.clang-format` is provided in the root directory for the project,\n  and a pass through this tool is included as part of our `pre-commit` configuration.\n\n- Code should generally follow the C++ Core Guidelines recommendations.\n\n- Code should generally allow for thread safety.\n\t- No static variables.\n\t- No globals\n\t- Free functions should not maintain state.\n\t- Use caution when using iterators to guard against invalidation.\n\n- Maintain const-correctness.\n\n- Use UpperCamelCase for type names.\n\n- Use UpperCamelCase for enum members.\n\n- Use UpperCamelCase for variable and class members.\n\n- Use lowerCamelCase for function and method names.\n\n- Avoid `using namespace std`\n\n- Use `auto` when the deduced type is explicitly spelled out in the\n  initialization or if the deduced type is an abstract type\n  alias.  Always explicitly specify type qualifiers, pointers, and\n  references.  E.g.,\n  ```cpp\n  const auto *Ptr = dynamic_cast<const Foo *>(SomePtr);\n  auto Val = static_cast<unsigned>(SomeValue);\n  for (auto Iter = SomeContainer.begin(), End = SomeContainer.end(); Iter != End; ++Iter) {}\n  ```\n\n- Use `auto` to make code more readable, but prefer `auto &` or `auto *`\n  to avoid unexpected copies.\n\n- `#include` as little as possible to reduce compile times. Use\n  forward declarations of classes when possible to avoid including\n  their definitions.\n\n- Do not introduce variables to the code that would require a client\n  to dllimport them. Export.hpp does not setup dllimport declarations\n  for clients. For example, do not add static function-local variables\n  in inline functions in header files.\n\n## Build Performance Tips\n\nSome tips to keep in mind to not needlessly regress build performance when\nworking with GTIRB:\n\n- Do not include a protobuf header from within a .hpp file unless you need the\n  enum values from protobuf. A forward declare + include in the .cpp file is\n  sufficient and cuts out 100s of transitive headers to parse.\n- CFG.hpp and ByteInterval.hpp are the most expensive headers you can possibly\n  include. Avoid including these whenever humanly possible (getting rid of 2\n  includes of CFG.hpp cut out ~2500 transitive header includes).\n- Boost headers are extremely heavy to parse, try to push as much of their\n  inclusions down into a .cpp file as possible. For instance, including boost's\n  endian header requires ~200 transitive headers by itself. Things like the\n  boost containers are considerably more expensive. This is what contributes to\n  ByteInterval and CFG being so expensive to include. Be wary when adding\n  includes to boost headers or adding new boost dependencies.\n- Do not blindly trust the output from tools like include what you use; they\n  sometimes do silly things like include a header file when a forward declare is\n  sufficient. When adding an include to a .hpp file, try hard to avoid adding\n  the include.\n\n### Testing Development\n\n- All code you care about should be tested.\n- Any code you don't care about should be removed.\n- C++ code should be tested on Linux using GCC and Clang, and on Windows using Visual Studio.\n- Code testing is done via Google Test.\n- Test names are prefixed with the type of test they are (`Unit_`, `System_`, `Integration_`).\n- No unit test should take more than 0.5 seconds.\n\n## Building under Windows\n\nMost of the build issues on Windows arise from having to define the location of\nmany dependencies.\n\n### Troubleshooting\n- When using a batch file to call `cmake`, make sure to quote all paths and\n  escape all backshlases in paths.  i.e. `-DCMAKE_PREFIX_PATH=\"c:\\\\Program\nFiles\\\\capstone\"` and do not leave a trailing backslash on paths.\n- Use `-Dprotobuf_DEBUG=ON` for protobuf related build issues in general.\n- `'../src/gtirb/proto/protobuf::protoc', needed by\n  'src/gtirb/proto/AuxData.pb.h', missing and no known rule to make it`\n  - due to missing or unusable protoc protobuf compiler.  You may need to define\n    `-Dprotobuf_EXECUTABLE=\"<path to protoc.exe>\"`, or check that the\nCMAKE_PREFIX_PATH has a path to the protobuf dir (resulting from `ninja install`\nafter building).\n- `CMAKE_PREFIX_PATH` is not additive.  If you set it again, it will silently\n  overwrite prior settings.  Add to the one definition, separtaing with\nsemi-colons.\n\n## Python Code Requirements\n\n- Code must be [PEP8](https://www.python.org/dev/peps/pep-0008/) compliant.\n  To check for PEP8 compliance, [flake8](https://pypi.org/project/flake8/) is recommended,\n  and included as part of our `pre-commit` configuration.\n\n- All code must be formatted with [Black](https://pypi.org/project/black/)\n  (set to line lengths of 79, for PEP8 compliance).\n  A pass through this tool is included as part of our `pre-commit` configuration.\n\n- The Python API should be made to run on all versions of Python 3.\n\n- Use `UpperCamelCase` for type names, `UPPER_CASE` for constant names,\n  and `snake_case` for other identifier names.\n\n### Testing Development\n\n- All code you care about should be tested.\n- Any code you don't care about should be removed.\n- Code testing is done via the built-in `unittest` framework.\n- Code testing uses [`tox`](https://tox.wiki/en/stable/) and\n  [`pytest`](https://docs.pytest.org/en/stable/) to simplify testing supported\n  configurations.\n- No unit test should take more than 0.5 seconds.\n\n## Documentation\n\nThe GTIRB documentation consists of complete documentation for all\ncomponents of the GTIRB API, along with examples and other usage\ninformation.\n\n\n### Building Documentation\n\nAt minimum, you will need [CMake](https://cmake.org/) and\n[Doxygen](http://www.doxygen.nl/). To build the documentation:\n\n1. Create and change to a temporary build directory. We will refer to\n   this directory as `build`.\n\n   ```bash\n   > mkdir build\n   > cd build\n   ```\n\n2. Build the documentation.\n\n   ```bash\n   build> cmake <PATH_TO_GTIRB> [<api_options>]\n   build> cmake --build . --target doc\n   ```\n\n3. Open the documentation home page `build/doc/html/index.html`\n   in your browser.\n\n\nThe `<api_options>` are as follows\n\n- `-DGTIRB_CXX_API=OFF` : do not generate C++ API documentation.\n\n  If this option is not specified, `cmake` will attempt to generate\n  C++ API documentation, failing (along with the documentation build\n  as a whole) if [Doxygen](http://www.doxygen.nl/) is not available.\n\n\n- `-DGTIRB_CL_API=OFF` : do not generate Common Lisp API documentation.\n\n  If this option is not specified, `cmake` will attempt to generate\n  Common Lisp API documentation if and only if it can locate a\n  SBCL/Quicklisp installation, failing if\n  [simpler-documentation-template\n  (SDT)](https://github.com/eschulte/simpler-documentation-template)\n  is not available.\n\n- `-DGTIRB_PY_API=OFF` : do not generate Python API documentation.\n\n  If this option is not specified, `cmake` will attempt to generate\n  Python API documentation if and only if it can locate a Python\n  installation, failing if [Sphinx](https://www.sphinx-doc.org/en/master/),\n  [sphinx-autodoc-typehints](https://pypi.org/project/sphinx-autodoc-typehints/),\n  or the Python API dependencies are not available.\n\n\n### Contributing Markdown Documentation\n\nTo add a new markdown document to the documentation:\n\n1. Create the new document as a child of `/doc`.\n   - File names start with `gtirb`.\n   - File extension is `.md`.\n   - Use github markdown syntax.\n   - Wrap your markdown documents at 80 columns.\n\n2. Edit `/doc/general/Doxyfile.in` to add the basename of your new markdown\n   document to the `INPUT` rule setting.\n\n3. Edit `/doc/general/CMakeLists.txt` to add your new markdown document\n   to  `MDFILES_IN`. Ordering is not important.\n\n4. Integrate your new markdown document into the documentation, either\n   by linking to it from an existing page or by updating\n   `/doc/general/DoxygenLayout.xml` to add an entry to the **More Information**\n   tab.\n\n5. [Build the documentation](#building-documentation) and check that\n   your new page is present and rendered correctly.\n   - If it is not rendered correctly, you may need to add a new\n     preprocessing step to `doc/general/preprocmd.py` to rewrite the\n     corresponding github-style markdown into something Doxygen\n     can handle correctly.\n\n### Graphviz\n\n- File names start with `gtirb`.\n- The color palette is `black`, `lightblue`, `cornflowerblue`, and `coral`.\n- Render `.dot` files to the same file name with a `.png` extension.\n\t* Example: `dot -Tpng gtirbScope.dot > gtirbScope.png`\n- Use the `arial` font.\n\n### Python\n\nFor the Python API, [Sphinx](https://www.sphinx-doc.org/en/master/)\nand [related plugins](https://pypi.org/project/sphinx-autodoc-typehints/)\nare required. To install these via [pip](https://pip.pypa.io/en/stable/), run:\n\n```bash\npip3 install sphinx sphinx-autodoc-typehints\n```\n\nYou will also need all the dependencies of the GTIRB Python API\nitself. If you haven't already installed the Python API (and don't\nwant to do so now) you can install just its dependencies as follows.\n\n```bash\ncd <PATH_TO_GTIRB>/build/python\npython3 setup.py egg_info\npip3 install -r gtirb.egg-info/requires.txt\n```\n\n### Common Lisp\n\nFor the Common Lisp API, [simpler-documentation-template (SDT)](https://github.com/eschulte/simpler-documentation-template)\nis required. This package should automatically be downloaded via the build process;\nsee `cl/README.md` for details on how to prepare the Common Lisp API.\n"
  },
  {
    "path": "FAQ.md",
    "content": "Frequently Asked Questions\n--------------------------\n\n- [I get compiler errors when I try to compile programs using GTIRB. How can I make them go away?](#compiler-errors)\n\n- [Linking error with \"undefined reference\" to gtirb::](#linking-error-with-undefined-reference-to-gtirb)\n\n#### Compiler Errors\n\n__Q: I get compiler errors when I try to compile programs using GTIRB. How can I make them go away?__\n\nA: GTIRB requires C++17, including the C++17 standard library. If your\ncompiler does not use C++17 by default, you will need to explicitly\nspecify it when compiling programs that use GTIRB.\n\nFor example:\n```\ng++ --std=c++17 my_gtirb_program.cpp -lgtirb -o my_gtirb_program\n```\n\n\n#### Linking error with \"undefined reference\" to gtirb\n\n__Q: I get linker errors when I try to compile and link programs using GTIRB. How can I make them go away?__\n\nA: This isn't GTIRB specific, but if you place the `-lgtirb` on your\ncompilation line *before* the source file the linker will sometimes\nthrow away the symbols from the GTIRB library which it doesn't think\nit needs (and if it hasn't read your source yet it won't think it\nneeds much).  So if for example,\n\n```\ng++ --std=c++17 -lgtirb my_gtirb_program.cpp\n```\n\ndoesn't work for you, then try this instead.\n\n```\ng++ --std=c++17 my_gtirb_program.cpp -lgtirb\n```\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "==============================================================================\nGTIRB is under the MIT License:\n==============================================================================\n\nMIT License\n\nCopyright (c) 2018 GrammaTech, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n==============================================================================\nSoftware from third parties included in GTIRB:\n==============================================================================\n\nGTIRB contains third party software which is under different license terms.\nAll such code will be identified clearly using at least one of two mechanisms:\n\n1) It will be in a separate directory tree with its own `LICENSE.txt` or\n   `LICENSE` file at the top containing the specific license and restrictions\n   which apply to that software, or\n2) It will contain specific license and restriction terms at the top of every\n   file.\n\n==============================================================================\nApache License v2.0 with LLVM Exceptions:\n==============================================================================\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n    1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n    2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n    3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n    4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n    5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n    6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n    7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n    8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n    9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n    END OF TERMS AND CONDITIONS\n\n    APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n    Copyright [yyyy] [name of copyright owner]\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n\n\n---- LLVM Exceptions to the Apache 2.0 License ----\n\nAs an exception, if, as a result of your compiling your source code, portions\nof this Software are embedded into an Object form of such source code, you\nmay redistribute such embedded portions in such Object form without complying\nwith the conditions of Sections 4(a), 4(b) and 4(d) of the License.\n\nIn addition, if you combine or link compiled forms of this Software with\nsoftware that is licensed under the GPLv2 (\"Combined Software\") and if a\ncourt of competent jurisdiction determines that the patent provision (Section\n3), the indemnity provision (Section 9) or other Section of the License\nconflicts with the conditions of the GPLv2, you may retroactively and\nprospectively choose to deem waived or otherwise exclude such Section(s) of\nthe License, but only in their entirety and only with respect to the Combined\nSoftware.\n\n==============================================================================\nUniversity of Illinois Open Source License:\n==============================================================================\nUniversity of Illinois/NCSA\nOpen Source License\n\nCopyright (c) 2003-2019 University of Illinois at Urbana-Champaign.\nAll rights reserved.\n\nDeveloped by:\n\n    LLVM Team\n\n    University of Illinois at Urbana-Champaign\n\n    http://llvm.org\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal with\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimers.\n\n    * Redistributions in binary form must reproduce the above copyright notice,\n      this list of conditions and the following disclaimers in the\n      documentation and/or other materials provided with the distribution.\n\n    * Neither the names of the LLVM Team, University of Illinois at\n      Urbana-Champaign, nor the names of its contributors may be used to\n      endorse or promote products derived from this Software without specific\n      prior written permission.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\nCONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE\nSOFTWARE.\n"
  },
  {
    "path": "Macros.cmake",
    "content": "macro(IMPL_GTIRB_ADD_LINKER_FLAG flag)\n  if(NOT ${CMAKE_EXE_LINKER_FLAGS} MATCHES \"(${flag}.*)\")\n    set(CMAKE_EXE_LINKER_FLAGS\n        \"${CMAKE_EXE_LINKER_FLAGS} ${flag}\"\n        CACHE STRING \"Linker Flags\" FORCE\n    )\n  endif()\n\n  if(NOT ${CMAKE_SHARED_LINKER_FLAGS} MATCHES \"(${flag}.*)\")\n    set(CMAKE_SHARED_LINKER_FLAGS\n        \"${CMAKE_SHARED_LINKER_FLAGS} ${flag}\"\n        CACHE STRING \"Linker Flags\" FORCE\n    )\n  endif()\nendmacro()\n\nmacro(GTIRB_ADD_MSVC_LINKER_FLAG flag)\n  if(MSVC)\n    impl_gtirb_add_linker_flag(${flag})\n  endif()\nendmacro()\n\nmacro(GTIRB_ADD_GCC_LINKER_FLAG flag)\n  if(CMAKE_COMPILER_IS_GNUCXX)\n    impl_gtirb_add_linker_flag(${flag})\n  endif()\nendmacro()\n\nmacro(GTIRB_ADD_CLANG_LINKER_FLAG flag)\n  if(${CMAKE_CXX_COMPILER_ID} STREQUAL Clang)\n    impl_gtirb_add_linker_flag(${flag})\n  endif()\nendmacro()\n\nmacro(GTIRB_ADD_LIBRARY)\n  add_library(\n    ${PROJECT_NAME} ${${PROJECT_NAME}_H} ${${PROJECT_NAME}_SRC}\n                    ${${PROJECT_NAME}_PROTO}\n  )\n\n  set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER \"gtirb\")\nendmacro()\n\nmacro(GTIRB_ADD_LIBRARY_STATIC)\n  add_library(\n    ${PROJECT_NAME} STATIC ${${PROJECT_NAME}_H} ${${PROJECT_NAME}_SRC}\n  )\n\n  set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER \"gtirb\")\nendmacro()\n\nmacro(GTIRB_ADD_LIBRARY_HEADERONLY)\n  add_library(${PROJECT_NAME} INTERFACE)\n  target_include_directories(\n    ${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}\n  )\nendmacro()\n\nmacro(GTIRB_ADD_EXECUTABLE)\n  add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_H} ${${PROJECT_NAME}_SRC})\n  set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER \"gtirb/applications\")\nendmacro()\n\nmacro(GTIRB_ADD_EXECUTABLE_GTEST)\n  add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_H} ${${PROJECT_NAME}_SRC})\n\n  add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME})\n  set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER \"gtirb/test\")\nendmacro()\n\nmacro(GTIRB_GET_ALL_SUBDIRS result curdir)\n  file(\n    GLOB children\n    RELATIVE ${curdir}\n    ${curdir}/*\n  )\n  set(dirlist \"\")\n  foreach(child ${children})\n    if(IS_DIRECTORY ${curdir}/${child})\n      list(APPEND dirlist ${child})\n    endif()\n  endforeach()\n  set(${result} ${dirlist})\nendmacro()\n\nmacro(GTIRB_ADD_ALL_SUBDIRS)\n  gtirb_get_all_subdirs(SUBDIRS ${CMAKE_CURRENT_SOURCE_DIR})\n  foreach(subdir ${SUBDIRS})\n    add_subdirectory(${subdir})\n  endforeach()\nendmacro()\n\n# Provide a vaguely consistent interface to find a Python 3 interpreter. Just\n# use FindPython3 if it exists, but fall back to looking for the interpreter\n# program if we have to.\nif(${CMAKE_VERSION} VERSION_GREATER_EQUAL \"3.12\")\n  macro(GTIRB_FIND_PYTHON)\n    find_package(Python3 REQUIRED COMPONENTS Interpreter)\n    if(Python3_EXECUTABLE)\n      set(PYTHON ${Python3_EXECUTABLE})\n    endif()\n  endmacro()\nelse()\n  macro(GTIRB_FIND_PYTHON)\n    find_program(PYTHON NAMES python3 python py)\n    if(PYTHON)\n      execute_process(\n        COMMAND \"${PYTHON}\" --version OUTPUT_VARIABLE Python3_VERSION\n      )\n      string(REPLACE \"Python \" \"\" Python3_VERSION \"${Python3_VERSION}\")\n      if(\"${Python3_VERSION}\" VERSION_LESS 3)\n        unset(PYTHON)\n        unset(Python3_VERSION)\n      endif()\n    endif()\n  endmacro()\nendif()\n"
  },
  {
    "path": "PROTOBUF.md",
    "content": "Using Serialized GTIRB Data\n===========================\n\n> Note that for language with GTIRB APIs (at least C++, Python, Common\n> Lisp) using the GTIRB API is preferrable to manipulating protobuf\n> directly.\n\nGTIRB uses a serialized format that consists of an 8-byte signature\nfollowed by serialized [protobuf](https://github.com/google/protobuf/wiki)\ndata. The protobuf data allows for exploration and manipulation in the\nlanguage of your choice.\nThe [Google protocol buffers](https://developers.google.com/protocol-buffers/)\nhomepage lists the languages in which protocol buffers can be used directly;\nusers of other languages can convert the protobuf-formatted data to\nJSON format and then use the JSON data in their applications. In the\nfuture we intend to define a standard JSON schema for GTIRB.\n\nThe 8-byte signature that prefixes the protobuf data includes both\nGTIRB's magic number and the version fot GTIRB's protobuf specification\nthat is in use. The layout is as follows:\n\n - Bytes 0-4 contain the ASCII characters: `GTIRB`.\n - Bytes 5-6 are considered reserved for future use and should be 0.\n - Byte 7 contains the GTIRB protobuf spec version in use.\n\nDirectory `gtirb/src/proto` contains the protocol buffer message type\ndefinitions for GTIRB. You can inspect these `.proto` files to\ndetermine the structure of the various GTIRB message types. The\ntop-level message type is `IR`.\n\n\n- [General Guidelines](#general-guidelines)\n- [Python Applications](#python-applications)\n- [Java Applications](#java-applications)\n\n\n# General Guidelines\n\nIf you have not used protocol buffers before, there are several useful\nresources available at\nhttps://developers.google.com/protocol-buffers/, including an\ninstallation guide and a tutorial.\n\nIn general, writing an application to use GTIRB data in protocol\nbuffer format will involve the following steps.\n\n1. Install the protocol buffer compiler (`protoc`) from\n   https://github.com/protocolbuffers/protobuf/releases, if you\n   haven't already done so.\n\n2. Install any required protocol buffer library or libraries for the\n   programming language you are using.\n\n3. Invoke the protocol buffer compiler on the `.proto` files in\n   `gtirb/src/proto/` to generate code in the language you wish to use.\n\n4. Write your application, importing/including the file or files you\n   generated in step 3.\n\nThe [Protocol Buffers API\nReference](https://developers.google.com/protocol-buffers/docs/reference/overview)\nprovides language-specific instructions for the various supported\nprogramming languages, along with links to information for cases where\nsupport is provided by third-party plug-ins.\n\n\n# Python Applications\n\nTo create a Python application that uses serialized GTIRB data, do the\nfollowing.\n\n1. Install the protocol buffer compiler (`protoc`).\n\n2. Install the Python protobuf library, if you haven't already done so.\n\n       $ pip install protobuf\n\n3. Generate Python message definitions in a dedicated directory (for\n   example, `python/`).\n\n       $ mkdir -p python\n       $ for f in src/proto/*.proto; do\n            protoc -Isrc/proto --python_out=python $f\n         done\n\n   This will create a number of files with names of the form\n   `<bn>_pb2.py` in the `python/` subdirectory of your working\n   directory: one for each `<bn>.proto` in src/proto/, including\n   `IR_pb2.py`.\n\n4. Write your application. Make sure that it imports `IR_pb2`, or the\n   parts of it that you require.\n\n5. Run your application, making sure that the directory containing\n   your message definitions is in the `PYTHONPATH`.\n\n## Python Examples\n\nDirectory `gtirb/doc/examples` contains several example Python scripts\nthat use protocol buffers to explore serialized GTIRB data.\n- [cfg-paths.py](doc/examples/cfg-paths.py)\n- [data-symbols.py](doc/examples/data-symbols.py)\n\n\n# Java Applications\n\n\nTo create a Java application that uses serialized GTIRB data, do the\nfollowing.\n\n1. Install the protocol buffer compiler (`protoc`).\n\n2. Download the `protobuf` Java runtime from\n   [https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java](https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java)\n   and save it somewhere suitable.\n\n3. Generate Java message definitions in a dedicated directory (for example,\n   `java/`).\n\n       $ mkdir -p java\n       $ for f in src/proto/*.proto; do\n            protoc -Isrc/proto --java_out=java $f\n         done\n\n   This will create a subdirectory `java/proto/', containing a number\n   of files with names of the form `<bn>OuterClass.java`: one for each\n   `<bn>.proto` in `src/proto/`.\n\n4. Compile the Java message definitions, making sure the `protobuf`\n   Java runtime `.jar` file is in your `CLASSPATH`.\n\n     $ mkdir -p java/classfiles\n     $ CLASSPATH=<path/to/protobuf_jar> \\\n       javac -d java/classfiles java/proto/*.java\n\n   (If you want to build a `.jar` file to combine all these\n   `.class` files, do so at this stage.)\n\n5. Write your application. Make sure that it imports all the classes\n   you need from the `proto` package.\n\n6. Compile and run your application, making sure that your CLASSPATH\n   contains both the `protobuf` Java runtime `.jar` file and the\n   location of the your compiled message definition classes.\n\n\n## Java Examples\n\nDirectory `gtirb/doc/examples` contains several example Java programs\nthat use protocol buffers to explore serialized GTIRB data.\n\n- [datasymbols.java](doc/examples/datasymbols.java)\n"
  },
  {
    "path": "README.md",
    "content": "# GTIRB\n\nThe GrammaTech Intermediate Representation for Binaries (GTIRB) is a\nmachine code analysis and rewriting data structure.  It is intended to\nfacilitate the communication of binary IR between programs performing\nbinary disassembly, analysis, transformation, and pretty printing.\nGTIRB is modeled on LLVM-IR, and seeks to serve a similar\nfunctionality of encouraging communication and interoperability\nbetween tools.\n\nThe remainder of this file describes various aspects of GTIRB:\n- [Structure](#structure)\n- [Installing](#installing)\n- [Building](#building)\n- [Usage](#usage)\n\n# Structure\n\nGTIRB has the following structure.  Solid lines denote inheritance.\nDotted lines denote reference by UUID.\n\n![GTIRB Data Structure](.gtirb.svg)\n\n## IR\n\nAn instance of GTIRB may include multiple modules (`Module`) which\nrepresent loadable objects such as executables or libraries, an\ninter-procedural control flow graph (`IPCFG`), and Auxiliary Data tables\n(`AuxData`) which can hold arbitrary analysis results in user-defined\nformats which can easily reference other elements of the IR.  Each\nmodule holds information such as symbols (`Symbol`) and sections which\nthemselves hold the actual bytes and data and code blocks of the\nmodule.  The CFG consists of basic blocks (`Block`) and control flow\nedges between these blocks.  Each data or code block references a\nrange of bytes in a byte interval (`ByteInterval`).  A section may\nhold one large byte interval holding all blocks---if the relative\npositions of blocks in that section are defined---or may hold one byte\ninterval per block---if the relative positions of blocks is not\ndefined, e.g. for the code blocks in the `.text` section during\nprogram rewriting.  Each symbol holds a pointer to the block or datum\nit references.\n\n\n## Instructions\n\nGTIRB explicitly does NOT represent instructions or instruction\nsemantics but does provide symbolic operand information and access to\nthe bytes.  There are many *intermediate languages* (IL)s for\nrepresentation of instruction semantics (e.g., [BAP][]'s [BIL][],\n[Angr][]'s [Vex][], or [Ghidra][]'s P-code).  GTIRB works with these\nor any other IL by storing instructions generally and efficiently as\n*raw machine-code bytes* and separately storing the symbolic and\ncontrol flow information.  The popular [Capstone][]/[Keystone][]\ndecoder/encoder provide an excellent option to read and write\ninstructions from/to GTIRB's machine-code byte representation without\ncommitting to any particular semantic IL.  By supporting multiple ILs\nand separate storage of analysis results in auxiliary data tables\nGTIRB enables collaboration between independent binary analysis and\nrewriting teams and tools.\n\n[BAP]: https://github.com/BinaryAnalysisPlatform/bap\n[BIL]: https://github.com/BinaryAnalysisPlatform/bil/releases/download/v0.1/bil.pdf\n[Angr]: http://angr.io\n[Vex]: https://github.com/angr/pyvex\n[Ghidra]: https://www.nsa.gov/resources/everyone/ghidra/\n[Capstone]: https://www.capstone-engine.org\n[Keystone]: https://www.keystone-engine.org\n\n\n## Auxiliary Data\n\nGTIRB provides for the sharing of additional information,\ne.g. analysis results, in the form of `AuxData` objects.  These can\nstore maps and vectors of basic GTIRB types in a portable way. The\n[GTIRB manual][] describes the structure for common types of auxiliary\ndata such as function boundary information, type information, or\nresults of common analyses in [Standard AuxData Schemata][].\n\n[GTIRB manual]: https://grammatech.github.io/gtirb/\n[Standard AuxData Schemata]: https://grammatech.github.io/gtirb/md__aux_data.html\n\n\n## UUIDs\n\nEvery element of GTIRB---e.g., modules (`Module`), symbols (`Symbol`),\nand blocks (`Block`)---has a universally unique identifier (UUID).\nUUIDs allow both first-class IR components and AuxData tables to\nreference elements of the IR.\n\nInstructions and symbolic operands can be addressed by the class\n`Offset` which encapsulates a UUID (that refers to the instruction's\nblock) and an offset.\n\n\n# Installing\n\nPackages currently exist for easily installing GTIRB (and attendant\ntooling including the [ddisasm][] disassembler and [gtirb-pprinter][]\npretty printer) on Windows, and Ubuntu 20. See below for\ninstructions. Additionally, a public Docker image exists at\n[grammatech/ddisasm][] with all of these tools installed. GTIRB is\nversioned with Major.Minor.Patch versioning where Major version\nincrements will require significant source changes but should be very\nrare, Minor version increments may require small source changes, and\nPatch version increments shouldn't break any downstream builds. We do\nnot yet provide ABI compatibility across any version changes.\n\n[ddisasm]: https://github.com/GrammaTech/ddisasm\n[gtirb-pprinter]: https://github.com/GrammaTech/gtirb-pprinter\n[grammatech/ddisasm]: https://hub.docker.com/r/grammatech/ddisasm\n\n\n## Python API\n\nThe latest stable GTIRB Python API may be installed from PyPI using pip:\n\n```sh\npip install gtirb\n```\n\nThe latest unstable version of the Python API can be installed from a\nprebuilt wheel:\n\n```sh\npip install https://download.grammatech.com/gtirb/files/python/gtirb-0.dev-py3-none-any.whl\n```\n\nIt is critical that the choice of a `stable` or `unstable` package matches the\ninstalled ddisasm and gtirb-pprinter packages.\n\n## Windows\n\nWindows releases are packaged as .zip files and are available at\nhttps://download.grammatech.com/gtirb/files/windows-release/.\n\n## Ubuntu\n\nPackages for Ubuntu 20 are available in the GTIRB apt repository and may\nbe installed per the following instructions.\n\nFirst, add GrammaTech's APT key.\n```sh\nwget -O - https://download.grammatech.com/gtirb/files/apt-repo/conf/apt.gpg.key | apt-key add -\n```\n\nNext update your sources.list file.\n```sh\necho \"deb [arch=amd64] https://download.grammatech.com/gtirb/files/apt-repo [distribution] [component]\"| sudo tee -a /etc/apt/sources.list\n```\nWhere:\n- `[distribution]` is `focal` (currently, only Ubuntu 20 packages are available)\n- `[component]` is either `stable`, which holds the last versioned release, or\n`unstable`, which holds the HEAD of the repository.\n\nFinally update your package database and install the core GTIRB tools:\n```sh\nsudo apt-get update\nsudo apt-get install gtirb-pprinter ddisasm\n```\n\n**Warning**:  Stable versions gtirb-2.0.0, gtirb-pprinter-2.1.0, ddisasm-1.8.0\nand OLDER rely on metapackages which cause conflicts if you try `apt-get upgrade`\n(see https://github.com/GrammaTech/gtirb/issues/63).  In this case,\nuninstall and reinstall the packages you got from the GTIRB repository.  You\nmay need to use `dpkg --remove` to remove the metapackages (e.g. `ddisasm`)\nbefore removing the concrete versioned packages (e.g. `ddisasm-1.5.1`).\nNEWER stable versions no longer rely on metapackages and can be upgraded\nwithout problems.\n\n# Building\n\nGTIRB's C++ API should successfully build in 64-bits with GCC, Clang,\nand Visual Studio compilers supporting at least C++17.  GTIRB uses\nCMake which must be installed with at least version 3.10.\n\nThe common build process looks like this:\n```sh\nmkdir build\ncd build\n# Note: You may wish to add some -D arguments to the next command. See below.\ncmake <path/to/gtirb>\ncmake --build .\n# Run the test suite.\nctest\n```\n\nFor customizing the GTIRB build, you can get a list of customization options by\nnavigating to your build directory and running:\n\n```sh\ncmake -LH\n```\n\n## Requirements\n\nTo build and install GTIRB, the following requirements should be installed:\n\n- [CMake][], version 3.10.0 or higher.\n   - Ubuntu 18 provides this version via the APT package `cmake`.\n   - Ubuntu 16 and earlier provide out of date versions; build from\n     source on those versions.\n- [Protobuf][], version\n  3.0.0 or later.\n  - Ubuntu 18 provides this version via the APT packages\n    `libprotobuf-dev` and `protobuf-compiler`.\n  - Ubuntu 16 and earlier provide out of date versions; build from\n    source on those versions.\n- Boost [(non-standard Ubuntu package from launchpad.net)][], version 1.68 or later.\n  - Ubuntu 18 only has version 1.65 in the standard repository.  See Ubuntu instructions above.\n\n[CMake]: https://cmake.org/\n[Protobuf]: https://developers.google.com/protocol-buffers/\n[(non-standard Ubuntu package from launchpad.net)]: https://launchpad.net/~mhier/+archive/ubuntu/libboost-latest\n\n\n# Usage\n\nGTIRB is designed to be serialized using [Google protocol buffers][]\n(i.e., [protobuf][]), enabling [easy and efficient use from any\nprogramming language](#using-serialized-gtirb-data).\n\nGTIRB may also be used through a dedicated API implemented in multiple\nlanguages. The APIs provide efficient data structures suitable for use\nby binary analysis and rewriting applications; see\n[below](#gtirb-api-implementations) for details.\n\n[Google protocol buffers]: https://developers.google.com/protocol-buffers/\n[protobuf]: https://github.com/google/protobuf/wiki\n\n\n## Using Serialized GTIRB Data\n\nGTIRB uses a serialized format that consists of an 8-byte signature\nfollowed by serialized [protobuf][] data. The protobuf data allows\nfor exploration and manipulation in the language of your choice.\nThe [Google protocol buffers][] homepage lists the languages in which\nprotocol buffers can be used directly; users of other languages can\nconvert the protobuf-formatted data to JSON format and then use the\nJSON data in their applications.\n\nThe `proto` directory in this repository contains the protocol buffer\nmessage type definitions for GTIRB. You can inspect these `.proto`\nfiles to determine the structure of the various GTIRB message\ntypes. The top-level message type is `IR`.\n\nFor more details, see [Using Serialized GTIRB Data](PROTOBUF.md).\n\n\n## GTIRB API Implementations\n\nThe GTIRB API is currently available in C++, Python, and Common Lisp.\nThere is a *partial* Java API which is not ready for external use.\nFor language-independent API information, see [GTIRB\nComponents](doc/general/ComponentsIndex.md). For information about the\ndifferent API implementations, see:\n\n  - [C++ API](doc/cpp/README.md)\n  - [Python API](python/README.md)\n  - [Common Lisp API](cl/README.md)\n  - Java API **incomplete**\n"
  },
  {
    "path": "cl/CMakeLists.txt",
    "content": "file(GLOB CL_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.lisp\n     ${CMAKE_CURRENT_SOURCE_DIR}/*.asd\n)\n\nset(CL_EXECUTABLE_STEMS dot update)\n\nforeach(CL_EXECUTABLE_STEM ${CL_EXECUTABLE_STEMS})\n  set(CL_EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/gtirb-${CL_EXECUTABLE_STEM})\n  list(APPEND CL_EXECUTABLES ${CL_EXECUTABLE})\n\n  add_custom_command(\n    OUTPUT ${CL_EXECUTABLE}\n    DEPENDS ${CL_SOURCES} ${PROTO_FILES}\n    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}\n    COMMAND\n      ${LISP} --noinform --dynamic-space-size 16384 --no-userinit --no-sysinit\n      --disable-debugger --load ${QUICKLISP}/setup.lisp --eval\n      \"(asdf:initialize-source-registry `(:source-registry (:tree \\\"${CMAKE_CURRENT_SOURCE_DIR}\\\") :inherit-configuration))\"\n      --eval \"(ql:quickload :gtirb/${CL_EXECUTABLE_STEM})\" --eval\n      \"(setf uiop/image::*lisp-interaction* nil)\" --eval\n      \"(asdf:make :gtirb/run-${CL_EXECUTABLE_STEM} :type :program :monolithic t)\"\n      --eval \"(uiop/image:quit)\"\n    COMMAND ${CMAKE_COMMAND} -E copy gtirb-${CL_EXECUTABLE_STEM}\n            ${CMAKE_CURRENT_BINARY_DIR}\n    COMMAND ${CMAKE_COMMAND} -E remove gtirb-${CL_EXECUTABLE_STEM}\n    VERBATIM\n  )\nendforeach(CL_EXECUTABLE_STEM)\n\nadd_custom_target(clgtirb ALL DEPENDS ${CL_EXECUTABLES})\n\nif(GTIRB_ENABLE_TESTS)\n  add_test(\n    NAME testgtirbcl\n    COMMAND\n      ${LISP} --noinform --dynamic-space-size 16384 --no-userinit --no-sysinit\n      --disable-debugger --load \"${QUICKLISP}/setup.lisp\" --eval\n      \"(asdf:initialize-source-registry `(:source-registry (:tree \\\"${CMAKE_CURRENT_SOURCE_DIR}\\\") :inherit-configuration))\"\n      --eval \"(ql:quickload :gtirb/test)\" --eval \"(gtirb/test:batch-test)\"\n    WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}/\"\n  )\nendif()\n"
  },
  {
    "path": "cl/README.md",
    "content": "Common Lisp library for GTIRB\n=============================\n\nThe Common Lisp API for GrammaTech's IR for Binaries (GTIRB).  GTIRB\nis a data structure designed to support the analysis and rewriting of\nbinary executables.  There are a number of tools that produce, process\nand consume GTIRB.  See the following for more information on GTIRB:\n- [https://github.com/grammatech/gtirb](https://github.com/grammatech/gtirb) the main GTIRB source repository.\n- [https://grammatech.github.io/gtirb/](https://grammatech.github.io/gtirb/) the GTIRB manual repository.\n- [https://arxiv.org/abs/1907.02859](https://arxiv.org/abs/1907.02859) a white-paper describing the design goals of GTIRB.\n- [https://github.com/grammatech/ddisasm](https://github.com/grammatech/ddisasm) a very high performance reassembleable disassembler producing GTIRB.\n- [https://github.com/grammatech/gtirb-pprinter](https://github.com/grammatech/gtirb-pprinter) a pretty printer from GTIRB to assembler.\n\n## Requirements and Installation\nHopefully, eventually, it will be possible to install everything by\n(1) installing\n[Protobuf](https://developers.google.com/protocol-buffers/), version\n3.7.0 or later, and then (2) installing this Common Lisp GTIRB library\nwith QuickLisp `(ql:quickload :gtirb)`.\n\nWe're a ways away from that currently.  So after you've installed\nProtobuf, you should clone and install the Common Lisp `PROTOBUF`\npackage manually according to the instructions at\n[https://github.com/brown/protobuf](https://github.com/brown/protobuf)\nensuring that the `protoc-gen-lisp` executable has been built and is\non your path.  At that point you should be able to load the GTIRB\npackage.\n\n## Usage\nThe Common Lisp API attempts to provide access to the underlying GTIRB\ndata-structure described above in idiomatic common lisp.  The main\nProtobuf data structures are wrapped in CLOS objects.  All fields are\nmodifiable with `setf`.  Invariant are maintained automatically by the\nAPI, e.g. using `:around` methods.\n\nIn some cases accessors are provided beyond the fields directly\npresent in the Protobuf.  For example, every GTIRB element has a UUID\n(which supports referencing elements from AuxData tables).  The Common\nLisp API provides uniform access to any element through the `get-uuid`\nmethod which operates similarly to `gethash` only it may be called on\nany top-level GTIRB `IR` object (which itself maintains a hash of\nevery contained element by UUID).\n\nThe GTIRB CFG is represented as a graph using the Common Lisp graph\nlibrary from\n[https://github.com/eschulte/graph](https://github.com/eschulte/graph).\nThis simple representation should promote easy exploration and\nmodification of the control flow graph, and the many graph analysis\nfunctions defined in that library may be directly applied to the CFG.\nEvery node of the graph holds the UUID for a code block.\n\nThe bytes of any code and data block may be accessed by calling the\n`bytes` method, which provides directly access to the bytes of the\nblock's `byte-interval`.\n\n### Example Usage\nSee the test suite for a large number of basic usage examples.\nHowever, the following gives a simple usage example.\n\n1.  From the command-line.  Use the datalog disassembler `ddisasm` to\n    disassemble the `ls` executable into a GTIRB instance.\n\n        ddisasm --ir $(which ls) /tmp/ls.gtirb\n\n2.  From the Common Lisp REPL.  Load the GTIRB API, and then load the\n    GTIRB instance created in step (1) into a common lisp GTIRB object.\n\n        (ql:quickload :gtirb)\n        (use-package :gtirb)\n        (defparameter ls (read-gtirb \"/tmp/ls.gtirb\"))\n\n3.  At this point you can explore the CFG, perform analyses, or even\n    modify the contents of the GTIRB object.  Results of analyses may\n    be saved into new AuxData tables which become part of the GTIRB\n    object for later use by other sessions or by other tools\n    potentially written in other languages.\n\n        ;; Do stuff with the GTIRB, maybe make changes.\n\n4.  Finally, the resulting GTIRB object may be written back to the\n    file system.\n\n        (write-gtirb ls \"/tmp/ls-modified.gtirb\")\n\n5.  At the command line.  A new executable may be created from the\n    modified gtirb file using the `gtirb-pprinter`.\n\n        gtirb-pprinter --ir /tmp/ls-modified.gtirb --binary /tmp/ls-modified\n"
  },
  {
    "path": "cl/dot.lisp",
    "content": "(defpackage :gtirb/dot\n  (:use :common-lisp :alexandria :graph :graph/dot :gtirb\n        :command-line-arguments\n        :named-readtables :curry-compose-reader-macros)\n  (:import-from :uiop :nest)\n  (:import-from :uiop/image :quit)\n  (:shadowing-import-from :proto-v0 :ir)\n  (:shadowing-import-from :gtirb :symbol)\n  (:export :to-dot :to-dot-file))\n(in-package :gtirb/dot)\n(in-readtable :curry-compose-reader-macros)\n\n(defun dot-edge-label (graph edge)\n  (let ((obj (edge-value graph edge)))\n    (format nil \"\\\"~a[~:[U~;C~]:~:[I~;D~]]\\\"\"\n            (edge-type obj) (conditional obj) (direct obj))))\n\n(defmethod to-dot ((obj gtirb) &rest rest)\n  \"Write the CFG of MODULE to the Graphviz graphing language.\"\n  (apply #'to-dot (cfg obj)\n         :edge-attrs (list (cons :label {dot-edge-label (cfg obj)}))\n         rest))\n\n(eval-when (:compile-toplevel :load-toplevel :execute)\n  (defparameter +udpate-args+\n    '(((\"help\" #\\h #\\?) :type boolean :optional t\n       :documentation \"display help output\"))))\n\n;;; NOTE: When Quicklisp updates graph to the latest this can be removed.\n(defmethod to-dot-file\n    ((object t) path &key attributes node-attrs edge-attrs\n                       subgraphs ranks)\n  (with-open-file (out path :direction :output :if-exists :supersede)\n    (to-dot object :stream out :attributes attributes :node-attrs node-attrs\n            :edge-attrs edge-attrs :subgraphs subgraphs :ranks ranks)))\n\n(define-command dot (gtirb-file dot-file &spec +udpate-args+)\n  \"Write first GTIRB module in GTIRB-FILE to DOT-FILE.\" \"\"\n  (when help (show-help-for-dot) (quit))\n  (to-dot-file (read-gtirb gtirb-file) dot-file))\n"
  },
  {
    "path": "cl/gtirb.asd",
    "content": "(defsystem \"gtirb\"\n    :name \"gtirb\"\n    :author \"GrammaTech\"\n    :licence \"MIT\"\n    :description \"Common Lisp library for GTIRB\"\n    :long-description \"A Common Lisp front end to the GrammaTech\n  Intermediate Representation for Bianries (GTIRB).  GTIRB is\n  serialized using Google's protocol buffers.  This library wraps the\n  raw protocol buffer serialization with a more Lispy interface.\"\n    :depends-on (:gtirb/gtirb)\n    :class :package-inferred-system\n    :defsystem-depends-on (:asdf-package-system :protobuf)\n    :in-order-to ((test-op (load-op \"gtirb/test\")))\n    :perform (test-op (o c) (symbol-call :gtirb/test '#:test)))\n\n(defsystem \"proto-v0\"\n    :name \"proto-v0\"\n    :description \"Common Lisp interface to (old V0) GTIRB protobuf files\"\n    :author \"GrammaTech\"\n    :license \"MIT\"\n    :defsystem-depends-on (:protobuf)\n    :components\n    ((:static-file \"README.md\")\n     ;; See the protobuf defsystem extension for how the gtirb.proto\n     ;; file is loaded into Lisp.  https://github.com/brown/protobuf\n     (:module proto\n              :pathname \"../proto/v0/\"\n              :components\n              ((:protobuf-source-file \"AuxDataContainer\")\n               (:protobuf-source-file \"CFG\")\n               (:protobuf-source-file \"Section\")\n               (:protobuf-source-file \"Offset\")\n               (:protobuf-source-file \"IR\")\n               (:protobuf-source-file \"ByteMap\")\n               (:protobuf-source-file \"ProxyBlock\")\n               (:protobuf-source-file \"AuxData\")\n               (:protobuf-source-file \"Module\")\n               (:protobuf-source-file \"DataObject\")\n               (:protobuf-source-file \"ImageByteMap\")\n               (:protobuf-source-file \"SymbolicExpression\")\n               (:protobuf-source-file \"Symbol\")\n               (:protobuf-source-file \"Block\")))))\n\n(defsystem \"proto\"\n    :name \"proto\"\n    :description \"Common Lisp interface to GTIRB protobuf files\"\n    :author \"GrammaTech\"\n    :license \"MIT\"\n    :defsystem-depends-on (:protobuf)\n    :components\n    ((:static-file \"README.md\")\n     ;; See the protobuf defsystem extension for how the gtirb.proto\n     ;; file is loaded into Lisp.  https://github.com/brown/protobuf\n     (:module proto\n              :pathname \"../proto\"\n              :components\n              ((:protobuf-source-file \"AuxData\")\n               (:protobuf-source-file \"ByteInterval\")\n               (:protobuf-source-file \"CFG\")\n               (:protobuf-source-file \"CodeBlock\")\n               (:protobuf-source-file \"Offset\")\n               (:protobuf-source-file \"DataBlock\")\n               (:protobuf-source-file \"IR\")\n               (:protobuf-source-file \"Module\")\n               (:protobuf-source-file \"ProxyBlock\")\n               (:protobuf-source-file \"Section\")\n               (:protobuf-source-file \"Symbol\")\n               (:protobuf-source-file \"SymbolicExpression\")))))\n\n(defsystem \"gtirb/run-validate\"\n    :author \"GrammaTech\"\n    :licence \"MIT\"\n    :description \"Validate a GTIRB instance.\"\n    :depends-on (gtirb/validate)\n    :build-operation \"asdf:program-op\"\n    :build-pathname \"gtirb-validate\"\n    :entry-point \"gtirb/validate::run-validate-file\")\n\n(defsystem \"gtirb/run-update\"\n    :author \"GrammaTech\"\n    :licence \"MIT\"\n    :description \"Convert between GTIRB protobuf versions.\"\n    :depends-on (gtirb/update)\n    :build-operation \"asdf:program-op\"\n    :build-pathname \"gtirb-update\"\n    :entry-point \"gtirb/update::run-update\")\n\n(defsystem \"gtirb/run-dot\"\n    :author \"GrammaTech\"\n    :licence \"MIT\"\n    :description \"Write GTIRB to a dot graph.\"\n    :depends-on (gtirb/dot)\n    :build-operation \"asdf:program-op\"\n    :build-pathname \"gtirb-dot\"\n    :entry-point \"gtirb/dot::run-dot\")\n\n(register-system-packages \"proto\" '(:gtirb.proto))\n(register-system-packages \"cl-interval\" '(:interval))\n"
  },
  {
    "path": "cl/gtirb.lisp",
    "content": "(defpackage :gtirb/gtirb\n  (:nicknames :gtirb)\n  (:use :common-lisp :alexandria :cl-ppcre :graph :trivia\n        :trivial-utf-8\n        :ieee-floats\n        :gtirb/ranged\n        :gtirb/utility\n        :gtirb/version\n        :named-readtables :curry-compose-reader-macros)\n  (:shadow :symbol)\n  (:import-from :gtirb.proto)\n  (:import-from :trivial-package-local-nicknames :add-package-local-nickname)\n  (:import-from :uiop :nest)\n  (:import-from :cl-intbytes\n                :int->octets\n                :octets->int\n                :octets->uint)\n  (:export :read-gtirb\n           :write-gtirb\n           :is-equal-p\n           :*is-equal-p-verbose-p*\n           :gtirb-node\n           :get-uuid\n           :remove-uuid\n           :at-address\n           :on-address\n           :address-range\n           :uuid\n           :update-proto\n;;; Classes and fields.\n           :gtirb\n           :ir\n           :cfg\n           :version\n           ;; Module\n           :module\n           :name\n           :binary-path\n           :isa\n           :file-format\n           :byte-order\n           :preferred-addr\n           :rebase-delta\n           :symbols\n           :proxies\n           :sections\n           :aux-data\n           :entry-point\n           ;; Symbol\n           :symbol\n           :value\n           :payload\n           :at-end\n           ;; Section\n           :section\n           :byte-intervals\n           :flags\n           ;; Byte-Interval\n           :byte-interval\n           :blocks\n           :addressp\n           :address\n           :contents\n           :size\n           :truncate-contents\n           :ignore\n           ;; Symbolic expressions\n           :symbolic-expressions\n           :sym-addr-const\n           :sym-addr-addr\n           :scale\n           :*preserve-symbolic-expressions*\n           ;; Block\n           :gtirb-block\n           :gtirb-byte-block\n           :code-block\n           :data-block\n           :decode-mode\n           :bytes\n           :offset\n           ;; Edge-Label\n           :edge-label\n           :conditional\n           :direct\n           :edge-type\n           ;; Aux-Data\n           :aux-data-type\n           :aux-data-data\n           ;; gtirb\n           :modules))\n(in-package :gtirb/gtirb)\n(in-readtable :curry-compose-reader-macros)\n\n(eval-when (:compile-toplevel :load-toplevel :execute)\n  (add-package-local-nickname :proto :gtirb.proto))\n\n(defgeneric read-gtirb (source)\n  (:documentation \"Read a protobuf serialized GTIRB instance from SOURCE.\")\n  (:method ((path t))\n    (make-instance 'gtirb :proto (read-proto 'proto:ir path))))\n\n(defmethod read-gtirb :around (source)\n  \"Check the protobuf version.\"\n  (let ((gtirb (call-next-method)))\n    (unless (= protobuf-version (proto:version (proto gtirb)))\n      (warn \"Protobuf version mismatch version ~a from ~a isn't expected ~a\"\n            (proto:version (proto gtirb)) source protobuf-version))\n    gtirb))\n\n(defun write-gtirb (gtirb path)\n  \"Write a GTIRB IR object to PATH.\"\n  (update-proto gtirb)\n  (write-proto (proto gtirb) path))\n\n\f\n;;;; Class utilities.\n(defvar *is-equal-p-verbose-p* nil\n  \"Compare equality verbosely in the `is-equal-p' function.\nThis may be useful to print contextual information when an equality\ncomparison fails for a large object with many nested objects.\")\n\n(defvar *is-equal-p-verbose-output-buffer* nil\n  \"Buffer to hold output of is-equal-p verbose failure messages.\")\n\n(defvar *is-equal-p-verbose-output-length* 10\n  \"Maximum length of output to show of `*is-equal-p-verbose-output-buffer*'.\")\n\n(defmacro compare-or-verbose (comparison left right &rest flags)\n  `(or (,comparison ,left ,right ,@flags)\n       (prog1 nil\n         (when *is-equal-p-verbose-p*\n           (push (format nil \"NOT ~S\" (list ',comparison ,left ,right))\n                 *is-equal-p-verbose-output-buffer*)))))\n\n(defun is-equal-p (left right)\n  \"Return t if LEFT and RIGHT are equal.\nRecursively descend into any sub-structure.  Custom recursive equality\npredicates are defined for common Common Lisp data structures as well\nas all GTIRB structures.\"\n  (let ((*is-equal-p-verbose-output-buffer* nil))\n    (let ((equalp (is-equal-p-internal left right)))\n      (prog1 equalp\n        (when (and (not equalp) *is-equal-p-verbose-p*)\n          (format t \"~{~S~%~}\"\n                  (subseq *is-equal-p-verbose-output-buffer*\n                          0 *is-equal-p-verbose-output-length*)))))))\n\n(defmethod is-equal-p-internal :around ((left t) (right t))\n  (let ((equalp (call-next-method)))\n    (when equalp (setf *is-equal-p-verbose-output-buffer* nil))\n    equalp))\n\n(defgeneric is-equal-p-internal (left right)\n  (:documentation \"Internal function called by `is-equal-p'.\")\n  (:method ((left t) (right t))\n    (compare-or-verbose equalp left right))\n  (:method ((left number) (right number))\n    (compare-or-verbose = left right))\n  (:method ((left cl:symbol) (right cl:symbol))\n    (compare-or-verbose eql left right))\n  (:method ((left string) (right string))\n    (compare-or-verbose string= left right))\n  (:method ((left cons) (right cons))\n    (if (and (proper-list-p left) (proper-list-p right))\n        (compare-or-verbose set-equal left right :test #'is-equal-p-internal)\n        (and (compare-or-verbose is-equal-p-internal (car left) (car right))\n             (compare-or-verbose is-equal-p-internal (cdr left) (cdr right)))))\n  (:method ((left hash-table) (right hash-table))\n    (compare-or-verbose set-equal\n                        (hash-table-alist left) (hash-table-alist right)\n                        :test #'is-equal-p-internal))\n  (:method ((left graph:digraph) (right graph:digraph))\n    (and (compare-or-verbose set-equal (graph:nodes left) (graph:nodes right)\n                             :test #'is-equal-p-internal)\n         (compare-or-verbose set-equal (graph:edges-w-values left)\n                             (graph:edges-w-values right)\n                             :test #'is-equal-p-internal))))\n\n(defclass gtirb-node () ()\n  (:documentation \"Objects with a UUID contained in a GTIRB instance.\"))\n\n(defclass proto-backed (gtirb-node) ()\n  (:documentation \"Objects which may be serialized to/from protobuf.\"))\n\n(defgeneric uuid (object)\n  (:documentation \"Return the UUID for OBJECT as an integer.\")\n  (:method ((obj proto-backed)) (uuid-to-integer (proto:uuid (proto obj)))))\n\n(defgeneric get-uuid (uuid object)\n  (:documentation \"Get the referent of UUID in OBJECT.\"))\n\n(defgeneric remove-uuid (uuid object)\n  (:documentation \"Remove the entry for UUID from OBJECT.\"))\n\n(defgeneric (setf get-uuid) (new uuid object)\n  (:documentation \"Register REFERENT behind UUID in OBJECT.\"))\n\n(defgeneric insert-address (object item start-address &optional end-address)\n  (:documentation\n   \"Insert ITEM into OBJECT between START-ADDRESS and END-ADDRESS.\"))\n\n(defgeneric delete-address (object item start-address &optional end-address)\n  (:documentation\n   \"Delete ITEM from OBJECT between START-ADDRESS and END-ADDRESS.\"))\n\n(defgeneric at-address (object address)\n  (:documentation\n   \"Find all objects in OBJECT starting at ADDRESS.\"))\n\n(defgeneric on-address (object start-address &optional end-address)\n  (:documentation\n   \"Find all objects in OBJECT between START-ADDRESS and END-ADDRESS.\"))\n\n(defgeneric set-parent-uuid (new uuid object)\n  (:documentation \"Set UUID to NEW in OBJECT's parent.\"))\n\n(defgeneric update-proto (proto-backed-object)\n  (:documentation\n   \"Update and return the `proto' field of PROTO-BACKED-OBJECT.\nThis will ensure that any changes made to PROTO-BACKED-OBJECT outside\nof its protocol buffer, e.g. any slots initialized using the\n:from-proto option to `define-proto-backed-class', are synchronized\nagainst the object's protocol buffer.\")\n  (:method ((proto-backed-object proto-backed))\n    (proto proto-backed-object)))\n\n(defgeneric address-range (proto-backed-object)\n  (:documentation\n   \"Return any address range of the PROTO-BACKED-OBJECT GTIRB object.\"))\n\n(defmacro define-proto-backed-class ((class proto-class) super-classes\n                                     slot-specifiers proto-fields\n                                     &rest options)\n  \"Define a Common Lisp class backed by a protobuf class.\nSLOT-SPECIFIERS is as in `defclass' with the addition of optional\n:to-proto and :from-proto fields, which may take protobuf\nserialization functions, and :skip-equal-p field which causes\n`is-equal-p' to skip that field.  PROTO-FIELDS may hold a list of\nfields which pass through directly to the backing protobuf class.  The\n:parent option names the field holding the containing protobuf\nelement.  The :address-range option holds the logic to calculate an\naddress range for instances of the object.\"\n  (nest\n   (flet ((plist-get (item list)\n            (second (member item list)))\n          (plist-drop (item list)\n            (if-let ((location (position item list)))\n              (append (subseq list 0 location)\n                      (subseq list (+ 2 location)))\n              list))))\n   (let ((from-proto-slots (remove-if-not {find :from-proto} slot-specifiers))\n         (to-proto-slots (remove-if-not {find :to-proto} slot-specifiers))\n         (parent (second (assoc :parent options)))\n         (address-range (cdr (assoc :address-range options)))))\n   `(progn\n      (defclass ,class (proto-backed ,@super-classes)\n        ;; Accessors for normal lisp classes\n        ((proto :initarg :proto :accessor proto :type ,proto-class\n                :initform ,(if parent\n                               `(let ((it (make-instance ',proto-class)))\n                                  (setf (proto::uuid it) (new-uuid))\n                                  it)\n                               `(make-instance ',proto-class))\n                :documentation \"Backing protobuf object.\nShould not need to be manipulated by client code.\")\n         (ir :accessor ir :type (or null gtirb)\n             :initarg :ir\n             :initform nil\n             :documentation\n             ,(format nil \"Access the top-level IR of this ~a.\" class))\n         ;; TODO: Consider throwing warnings in a `setf :around'\n         ;;       defmethod on the parents of objects with parents if\n         ;;       the objects are set to something that already has a\n         ;;       current parent.  This could avoid surprising\n         ;;       inconsistencies.  Alternately this could throw an\n         ;;       error with the option to copy the object with a new\n         ;;       corrected parent or to set the parent directly.\n         ,@(when parent\n             `((,parent :accessor ,parent :type (or null ,parent)\n                        :initarg ,(make-keyword parent)\n                        :initform nil\n                        :documentation ,(format nil \"Access the ~a of this ~a.\"\n                                                parent class))))\n         ,@(mapcar [{plist-drop :to-proto} {plist-drop :from-proto}\n                    {plist-drop :proto-field} {plist-drop :skip-equal-p}]\n                   slot-specifiers))\n        ,@(remove-if [«or {eql :parent} {eql :address-range}» #'car] options))\n      ,@(when parent\n          `((defmethod get-uuid (uuid (object ,class))\n              (assert (or (ir object) (,parent object)) (object)\n                      ,(format nil\n                               \"`get-uuid' failed on a ~a without a ~a\"\n                               class parent))\n              (get-uuid uuid (or (ir object) (,parent object))))\n            (defmethod set-parent-uuid (new uuid (object ,class))\n              (assert (or (ir object) (,parent object)) (object)\n                      ,(format nil\n                               \"`set-parent-uuid' failed on a ~a without a ~a\"\n                               class parent))\n              (setf (get-uuid uuid (or (ir object) (,parent object))) new))\n            (defmethod (setf get-uuid) (new uuid (object ,class))\n              (assert (or (ir object) (,parent object)) (object)\n                      ,(format nil\n                               \"`get-uuid' failed on ~a without a ~a\"\n                               class parent))\n              (set-parent-uuid new uuid object))\n            (defmethod remove-uuid (uuid (object ,class))\n              (assert (or (ir object) (,parent object)) (object)\n                      ,(format nil\n                               \"`remove-uuid' failed on ~a without a ~a\"\n                               class parent))\n              (remove-uuid uuid (or (ir object) (,parent object))))\n            (defmethod at-address ((object ,class) address)\n              (assert (or (ir object) (,parent object)) (object)\n                      ,(format nil\n                               \"`at-address' failed on ~a without a ~a\"\n                               class parent))\n              (at-address (or (ir object) (,parent object)) address))\n            (defmethod on-address ((object ,class) start &optional end)\n              (assert (or (ir object) (,parent object)) (object)\n                      ,(format nil\n                               \"`on-address' failed on ~a without a ~a\"\n                               class parent))\n              (on-address (or (ir object) (,parent object)) start end))))\n      (defmethod address-range ((self ,class)) ,@address-range)\n      (defmethod\n          initialize-instance :after ((self ,class) &key)\n          ,@(when parent\n              `((when (,parent self)\n                  (setf (get-uuid (uuid-to-integer (proto:uuid (proto self)))\n                                  self)\n                        self))))\n          (with-slots (proto ,@(mapcar #'car from-proto-slots)) self\n            ,@(mapcar\n               (lambda (spec)\n                 (destructuring-bind\n                       (slot &key from-proto &allow-other-keys) spec\n                   `(setf ,slot (funcall ,from-proto proto))))\n               from-proto-slots)))\n      (defmethod update-proto ((self ,class))\n        ,@(mapcar\n           (lambda (spec)\n             (destructuring-bind\n                   (slot &key to-proto (proto-field slot) &allow-other-keys)\n                 spec\n               `(setf (,(intern (symbol-name proto-field) 'proto) (proto self))\n                      (funcall ,to-proto (,slot self)))))\n           to-proto-slots)\n        (proto self))\n      ;; Equality check on class.\n      ;;\n      ;; NOTE: For this to work we might need to add an optional :only\n      ;;       field to both slot-specifiers  and proto-fields.  This\n      ;;       would mean that the equality of this field is only\n      ;;       checked with this form returns true.  E.g., on\n      ;;       byte-intervals we could say:\n      ;;       (address :type unsigned-byte-64 :only #'addressp)\n      (defmethod is-equal-p-internal ((left ,class) (right ,class))\n        (and ,@(mapcar\n                (lambda (accessor)\n                  `(compare-or-verbose is-equal-p-internal\n                                       (,accessor left) (,accessor right)))\n                (append\n                 (mapcar {plist-get :accessor}\n                         (remove-if {plist-get :skip-equal-p}\n                                    slot-specifiers))\n                 (mapcar #'car proto-fields)))))\n      ;; Pass-through accessors for protobuf fields so they operate\n      ;; directly on the backing protobuf object.\n      ,@(apply\n         #'append\n         (mapcar\n          (nest\n           (lambda (pair))\n           (destructuring-bind\n                 (name &key type documentation enumeration (proto-field name)\n                       &allow-other-keys) pair)\n           (let ((base `(,(intern (symbol-name proto-field) 'proto)\n                          (proto obj)))))\n           `((defmethod ,name ((obj ,class))\n               ,@(when documentation (list documentation))\n               ,(ecase type\n                  ((unsigned-byte-64 boolean bytes) base)\n                  (enumeration `(cdr (assoc ,base ,enumeration)))\n                  (uuid `(uuid-to-integer ,base))\n                  (string `(pb:string-value ,base))))\n             (defmethod (setf ,name) (new (obj ,class))\n               ,@(when documentation (list documentation))\n               ,(ecase type\n                  ((unsigned-byte-64 boolean) `(setf ,base new))\n                  (bytes `(setf ,base (force-byte-array new)))\n                  (enumeration `(setf ,base (car (rassoc new ,enumeration))))\n                  (uuid `(setf ,base (integer-to-uuid new)))\n                  (string `(setf ,base (pb:string-field new)))))))\n          proto-fields)))))\n\n(eval-when (:compile-toplevel :load-toplevel :execute)\n  (defvar aux-data-slot-definition\n    \"A-list of auxiliary data objects keyed by string name.\nAux-Data tables may hold structured or unstructured data.  This data\nmay refer to elements of the GTIRB IR through uuids.  Information\nrelevant to a particular module will be stored in Aux-Data tables\naccessible from the specific module.  Aux-Data tables only exist on\nmodules and on GTIRB IR instances.\"))\n\n\f\n;;;; Classes.\n(define-proto-backed-class (gtirb proto:ir) ()\n    ((modules :initarg modules :accessor modules :type list\n              :initform nil\n              :from-proto\n              [{mapcar {make-instance 'module :ir self :gtirb self :proto}}\n               {coerce _ 'list} #'proto:modules]\n              :to-proto {map 'vector #'update-proto}\n              :documentation\n              \"List of the modules on a top-level GTIRB IR instance.\")\n     (cfg :accessor cfg :type digraph\n          :from-proto\n          (lambda (proto)\n            (let ((p-cfg (proto:cfg proto)))\n              (populate\n               (make-instance 'digraph)\n               :edges-w-values\n               (mapcar\n                (lambda (edge)\n                  (cons (list (uuid-to-integer (proto:source-uuid edge))\n                              (uuid-to-integer (proto:target-uuid edge)))\n                        (make-instance 'edge-label :proto (proto:label edge))))\n                (coerce (proto:edges p-cfg) 'list))\n               :nodes (map 'list  #'uuid-to-integer (proto:vertices p-cfg)))))\n          :to-proto\n          (lambda (cfg &aux (p-cfg (make-instance 'proto:cfg)))\n            (setf\n             (proto:vertices p-cfg)\n             (map 'vector #'integer-to-uuid (nodes cfg))\n             (proto:edges p-cfg)\n             (map 'vector\n                  (lambda (edge)\n                    (destructuring-bind ((source target) . label) edge\n                      (let ((p-edge (make-instance 'proto:edge)))\n                        (setf\n                         (proto:source-uuid p-edge) (integer-to-uuid source)\n                         (proto:target-uuid p-edge) (integer-to-uuid target)\n                         (proto:label p-edge) (proto label))\n                        p-edge)))\n                  (edges-w-values cfg)))\n            p-cfg)\n          :documentation\n          \"Control flow graph (CFG) represented as a `graph:digraph'.\nNodes in the graph hold the UUIDs of code blocks which may be looked\nup using `get-uuid'.  Edges on the graph are labeled with `edge-label'\nobjects which provide information on the nature of the control flow of\nthe graph.\")\n     (aux-data :accessor aux-data :type list\n               :from-proto #'aux-data-from-proto\n               :to-proto #'aux-data-to-proto\n               :documentation #.aux-data-slot-definition)\n     (by-uuid :accessor by-uuid :initform (make-hash-table) :type hash-table\n              :skip-equal-p t\n              :documentation \"Internal cache for UUID-based lookup.\")\n     (by-address :accessor by-address :initform (make-ranged) :skip-equal-p t\n                 :documentation \"Internal cache for Address-based lookup.\")\n     (aux-data-w-offsets :accessor aux-data-w-offsets :initform nil\n                         :skip-equal-p t\n                         :documentation \"Cache for fast offset updates.\"))\n    ((version :type unsigned-byte-64 :documentation \"Protobuf version.\"))\n  (:documentation \"Base class of an instance of GTIRB IR.\"))\n\n(defmethod initialize-instance :around ((self gtirb) &key)\n  (call-next-method)\n  ;; Populate the aux-data tables with offsets.\n  (setf (aux-data-w-offsets self) (get-aux-data-w-offsets self)))\n\n(define-condition ir (error)\n  ((message :initarg :message :initform nil :reader message)\n   (object :initarg :object :initform nil :reader object))\n  (:report (lambda (condition stream)\n             (format stream \"GTIRB error ~S on ~S.\"\n                     (message condition) (object condition))))\n  (:documentation \"Condition raised on GTIRB data structure violations.\"))\n\n(defmethod print-object ((obj gtirb) stream)\n  (print-unreadable-object (obj stream :type t :identity t)\n    (format stream \"~a\" (modules obj))))\n\n(defmethod ir ((obj gtirb)) obj)\n\n(defmethod get-uuid (uuid (obj gtirb))\n  (gethash uuid (by-uuid obj)))\n\n(defmethod (setf get-uuid) (new uuid (obj gtirb))\n  (when (zerop uuid)\n    (warn \"Saving object ~a without a UUID into ~a.\" new obj))\n  (when-let ((range (address-range new)))\n    #+debug (format t \"(range ~S) ;; => ~S~%\" new range)\n    (apply #'insert-address obj new range))\n  (setf (gethash uuid (by-uuid obj)) new))\n\n(defmethod remove-uuid (uuid (obj gtirb))\n  (remhash uuid (by-uuid obj)))\n\n(defmethod insert-address ((gtirb gtirb) item start &optional end)\n  (ranged-insert (by-address gtirb) (uuid item) start end))\n\n(defmethod delete-address ((gtirb gtirb) item start &optional end)\n  (ranged-delete (by-address gtirb) (uuid item) start end))\n\n(defmethod at-address ((gtirb gtirb) address)\n  (mapcar {get-uuid _ gtirb} (ranged-find-at (by-address gtirb) address)))\n\n(defmethod on-address ((gtirb gtirb) start &optional (end start))\n  (mapcar {get-uuid _ gtirb} (ranged-find (by-address gtirb) start end)))\n\n(define-constant +module-isa-map+\n    '((#.proto:+isa-isa-undefined+ . :undefined)\n      (#.proto:+isa-ia32+ . :ia32)\n      (#.proto:+isa-ppc32+ . :ppc32)\n      (#.proto:+isa-x64+ . :x64)\n      (#.proto:+isa-arm+ . :arm)\n      (#.proto:+isa-valid-but-unsupported+ . :valid-but-unsupported)\n      (#.proto:+isa-ppc64+ . :ppc64)\n      (#.proto:+isa-arm64+ . :arm64)\n      (#.proto:+isa-mips32+ . :mips32)\n      (#.proto:+isa-mips64+ . :mips64))\n  :test #'equal)\n\n(define-constant +module-file-format-map+\n    '((#.proto:+file-format-coff+ . :coff)\n      (#.proto:+file-format-elf+ . :elf)\n      (#.proto:+file-format-ida-pro-db32+ . :ida-pro-db32)\n      (#.proto:+file-format-ida-pro-db64+ . :ida-pro-db64)\n      (#.proto:+file-format-macho+ . :macho)\n      (#.proto:+file-format-pe+ . :pe)\n      (#.proto:+file-format-raw+ . :raw)\n      (#.proto:+file-format-xcoff+ . :xcoff)\n      (#.proto:+file-format-format-undefined+ . :format-undefined))\n  :test #'equal)\n\n(define-constant +module-byte-order-map+\n    `((#.proto:+byte-order-byte-order-undefined+ . :undefined)\n      (#.proto:+byte-order-big-endian+ . :big-endian)\n      (#.proto:+byte-order-little-endian+ . :little-endian))\n  :test #'equal)\n\n(define-proto-backed-class (module proto:module) ()\n    ((proxies :accessor proxies :type hash-table\n              :initform (make-hash-table)\n              :from-proto\n              (lambda (proto &aux (table (make-hash-table)))\n                (let ((proto-proxies (proto:proxies proto)))\n                  (dotimes (n (length proto-proxies) table)\n                    (let ((it (aref proto-proxies n)))\n                      (setf (gethash (uuid-to-integer (proto:uuid it)) table)\n                            (make-instance 'proxy-block\n                              :ir (ir self) :module self :proto it))))))\n              :to-proto\n              [{map 'vector (lambda (uuid)\n                              (let ((it (make-instance 'proto:proxy-block)))\n                                (setf (proto:uuid it) (integer-to-uuid uuid))\n                                it))}\n               {mapcar #'car} #'hash-table-alist]\n              :documentation\n              \"Hash-table of proxy-blocks keyed by UUID.\nProxy-blocks in GTIRB are used to represent cross-module linkages.\nFor example when code in a module calls to a function defined in an\nexternal library, the CFG for that IR instance may represent this call\nwith a call edge to a proxy block representing the external called\nfunction.\")\n     (symbols :accessor symbols :type list\n              :initform nil\n              :from-proto\n              [{map 'list\n                    {make-instance 'symbol :ir (ir self) :module self :proto}}\n               #'proto:symbols]\n              :to-proto {map 'vector #'update-proto}\n              :documentation \"Hash-table of symbols keyed by UUID.\")\n     (sections :accessor sections :type list\n               :from-proto\n               [{map 'list\n                     {make-instance 'section :ir (ir self) :module self :proto}}\n                #'proto:sections]\n               :to-proto {map 'vector #'update-proto}\n               :documentation \"List of the sections comprising this module.\")\n     (aux-data :accessor aux-data :type list\n               :from-proto #'aux-data-from-proto\n               :to-proto #'aux-data-to-proto\n               :documentation #.aux-data-slot-definition))\n    ((name :type string :documentation\n           \"An optional human-readable name for this module.\")\n     (binary-path :type string :documentation\n                  \"The path or filename for this module.\nE.g, the name of a dynamically loaded library or of the main\nexecutable.\")\n     (preferred-addr :type unsigned-byte-64 :documentation\n                     \"Some systems specify a preferred address in memory.\nOn those systems this field may be used to capture this address.\")\n     (rebase-delta :type unsigned-byte-64 :documentation\n                   \"The difference between this module's and\n`preferred-addr' and the address at which it was actually loaded.\")\n     (isa :type enumeration :enumeration +module-isa-map+ :documentation\n          \"The instruction set architecture (ISA) of the code in this module.\")\n     (file-format :type enumeration :enumeration +module-file-format-map+\n                  :documentation\n                  \"The binary file format of the original file this\nmodule represents.\")\n     (byte-order :type enumeration :enumeration +module-byte-order-map+ :documentation\n                 \"The byte-order of the bytes in this module.\"))\n  (:documentation \"Module of a GTIRB IR instance.\") (:parent gtirb))\n\n(defmethod make-instance :around\n    ((class (eql 'module)) &rest initargs &key &allow-other-keys)\n  (let ((proto (or (getf initargs :proto)\n                   (let ((new-proto (make-instance 'proto:module)))\n                     (if-let ((name (getf initargs :name)))\n                       (setf (proto:name new-proto) (pb:string-field name))\n                       (warn \"Modules created without a name\"))\n                     new-proto))))\n    (apply #'call-next-method class :proto proto initargs)))\n\n(defmethod print-object ((obj module) stream)\n  (print-unreadable-object (obj stream :type t :identity t)\n    (format stream \"~a ~a ~s\" (file-format obj) (isa obj) (name obj))))\n\n(defgeneric get-aux-data-w-offsets (object)\n  (:documentation \"Collect all Aux-Data tables with offsets in their types.\")\n  (:method ((list list))\n    (remove-if-not [{find :offset} #'flatten #'aux-data-type #'cdr] list))\n  (:method ((self module)) (get-aux-data-w-offsets (aux-data self)))\n  (:method ((self gtirb))\n    (apply #'append\n           (get-aux-data-w-offsets (aux-data self))\n           (mapcar #'get-aux-data-w-offsets (modules self)))))\n\n(defmethod (setf aux-data) :after (new-value (self gtirb))\n  (declare (ignorable new-value))\n  (setf (aux-data-w-offsets self) (get-aux-data-w-offsets self)))\n\n(defmethod (setf aux-data) :after (new-value (self module))\n  (declare (ignorable new-value))\n  (setf (aux-data-w-offsets (ir self)) (get-aux-data-w-offsets (ir self))))\n\n(define-constant +edge-label-type-map+\n    '((#.proto:+edge-type-type-branch+ . :branch)\n      (#.proto:+edge-type-type-call+ . :call)\n      (#.proto:+edge-type-type-fallthrough+ . :fallthrough)\n      (#.proto:+edge-type-type-return+ . :return)\n      (#.proto:+edge-type-type-syscall+ . :syscall)\n      (#.proto:+edge-type-type-sysret+ . :sysret))\n  :test #'equal)\n\n(define-proto-backed-class (edge-label proto:edge-label) () ()\n    ((conditional :type boolean :documentation\n                  \"This is true if this edge is due to a conditional\ninstruction.\")\n     (direct :type boolean :documentation\n             \"Is this a direct (as opposed to indirect) control flow edge.\")\n     (edge-type :type enumeration :enumeration +edge-label-type-map+\n                :proto-field type :documentation\n                \"The type of an edge indicates the nature of the\ncontrol flow along it.  E.g., \\\"branch,\\\" \\\"call,\\\" \\\"fallthrough,\\\"\nand \\\"return\\\" are examples.\"))\n  (:documentation \"Label on a CFG edge.\nThis indicates the type of control flow along this edge.\"))\n\n(defmethod print-object ((obj edge-label) stream)\n  (print-unreadable-object (obj stream :type t :identity t)\n    (format stream \"~a ~:[unconditional~;conditional~] ~:[undirect~;direct~]\"\n            (edge-type obj) (conditional obj) (direct obj))))\n\n(define-proto-backed-class (symbol proto:symbol) () ()\n    ((name :type string)\n     (value :type unsigned-byte-64)\n     (referent-uuid :type uuid)\n     (at-end :type boolean))\n  (:documentation\n   \"Symbol with it's NAME and an optional VALUE or REFERENT.\")\n  (:parent module))\n\n(defgeneric payload (symbol)\n  (:documentation \"Provide access to the referent or value of SYMBOL.\")\n  (:method ((symbol symbol))\n    (cond\n      ((proto:has-value (proto symbol))\n       (value symbol))\n      ((proto:has-referent-uuid (proto symbol))\n       (get-uuid (referent-uuid symbol) symbol)))))\n\n(defmethod (setf payload) ((new proto-backed) (symbol symbol))\n  \"Save GTIRB object NEW into the `referent-uuid' of SYMBOL.\"\n  (proto:clear-value (proto symbol))\n  (setf (referent-uuid symbol) (uuid new)))\n\n(defmethod (setf payload) ((new integer) (symbol symbol))\n  \"Save INTEGER value NEW into the `value' of SYMBOL.\"\n  (proto:clear-referent-uuid (proto symbol))\n  (setf (value symbol) new))\n\n(defmethod (setf payload) ((new t) (symbol symbol))\n  (error \"Symbol payload ~S must be either a GTIRB element or an integer.\" new))\n\n(defmethod print-object ((obj symbol) stream)\n  (print-unreadable-object (obj stream :type t :identity t)\n    (format stream \"~a ~a~:[~;|~]\" (name obj)\n            (or (value obj) (referent-uuid obj))\n            (at-end obj))))\n\n(define-constant +section-flags-map+\n    '((#.proto:+section-flag-section-undefined+ . :flag-undefined)\n      (#.proto:+section-flag-readable+ . :readable)\n      (#.proto:+section-flag-writable+ . :writable)\n      (#.proto:+section-flag-executable+ . :executable)\n      (#.proto:+section-flag-loaded+ . :loaded)\n      (#.proto:+section-flag-initialized+ . :initialized)\n      (#.proto:+section-flag-thread-local+ . :thread-local))\n  :test #'equal)\n\n(define-proto-backed-class (section proto:section) ()\n    ((byte-intervals\n      :accessor byte-intervals :type list\n      :from-proto\n      [{map 'list\n            {make-instance 'byte-interval :ir (ir self) :section self :proto}}\n       #'proto:byte-intervals]\n      :to-proto {map 'vector #'update-proto}\n      :documentation \"Byte-intervals holding all of the section's bytes.\"))\n    ((name :type string :documentation \"Name of this section.\")\n     (flags :type enumeration :enumeration +section-flags-map+\n            :proto-field section-flags :documentation\n            \"Flags holding common properties of this section.\nThese flags only hold those section properties which are relatively\nuniversal including read, write, execute permissions, whether the\nsection is loaded into memory at run-time or not, whether the section\nis zero initialized, and whether the section is thread-local.\"))\n  (:documentation \"Section in a GTIRB IR instance.\") (:parent module))\n\n(defmethod print-object ((obj section) stream)\n  (print-unreadable-object (obj stream :type t :identity t)\n    (format stream \"~a ~a\" (name obj) (length (byte-intervals obj)))))\n\n(defmethod address ((obj section))\n  (extremum (mapcar #'address (byte-intervals obj)) #'<))\n\n(defmethod size ((it section))\n  (- (extremum (mapcar «+ #'address #'size» (byte-intervals it)) #'> :key #'car)\n     (address it)))\n\n(defgeneric blocks (obj)\n  (:documentation \"List of gtirb-byte-block objects in this object.\nPrimitive accessor for byte-interval.\")\n  (:method ((obj gtirb)) (mappend #'blocks (modules obj)))\n  (:method ((obj module)) (mappend #'blocks (sections obj)))\n  (:method ((obj section)) (mappend #'blocks (byte-intervals obj))))\n\n(define-proto-backed-class (offset proto:offset) () ()\n    ((element-id :type uuid)\n     (displacement :type unsigned-byte-64))\n  (:documentation \"Offset into a GTIRB object.\"))\n\n(define-constant +se-attribute-flag-map+\n    '(\n      (#.proto:+se-attribute-flag-got+ . :got)\n      (#.proto:+se-attribute-flag-gotpc+ . :gotpc)\n      (#.proto:+se-attribute-flag-gotoff+ . :gotoff)\n      (#.proto:+se-attribute-flag-gotrel+ . :gotrel)\n      (#.proto:+se-attribute-flag-plt+ . :plt)\n      (#.proto:+se-attribute-flag-pltoff+ . :pltoff)\n      (#.proto:+se-attribute-flag-pcrel+ . :pcrel)\n      (#.proto:+se-attribute-flag-secrel+ . :secrel)\n      (#.proto:+se-attribute-flag-tls+ . :tls)\n      (#.proto:+se-attribute-flag-tlsgd+ . :tlsgd)\n      (#.proto:+se-attribute-flag-tlsld+ . :tlsld)\n      (#.proto:+se-attribute-flag-tlsldm+ . :tlsldm)\n      (#.proto:+se-attribute-flag-tlscall+ . :tlscall)\n      (#.proto:+se-attribute-flag-tlsdesc+ . :tlsdesc)\n      (#.proto:+se-attribute-flag-tprel+ . :tprel)\n      (#.proto:+se-attribute-flag-tpoff+ . :tpoff)\n      (#.proto:+se-attribute-flag-dtprel+ . :dtprel)\n      (#.proto:+se-attribute-flag-dtpoff+ . :dtpoff)\n      (#.proto:+se-attribute-flag-dtpmod+ . :dtpmod)\n      (#.proto:+se-attribute-flag-ntpoff+ . :ntpoff)\n      (#.proto:+se-attribute-flag-page+ . :page)\n      (#.proto:+se-attribute-flag-pageoff+ . :pageoff)\n      (#.proto:+se-attribute-flag-call+ . :call)\n      (#.proto:+se-attribute-flag-lo+ . :lo)\n      (#.proto:+se-attribute-flag-hi+ . :hi)\n      (#.proto:+se-attribute-flag-higher+ . :higher)\n      (#.proto:+se-attribute-flag-highest+ . :highest)\n      (#.proto:+se-attribute-flag-gotntpoff+ . :gotntpoff)\n      (#.proto:+se-attribute-flag-indntpoff+ . :indntpoff)\n      (#.proto:+se-attribute-flag-g0+ . :g0)\n      (#.proto:+se-attribute-flag-g1+ . :g1)\n      (#.proto:+se-attribute-flag-g2+ . :g2)\n      (#.proto:+se-attribute-flag-g3+ . :g3)\n      (#.proto:+se-attribute-flag-upper16+ . :upper16)\n      (#.proto:+se-attribute-flag-lower16+ . :lower16)\n      (#.proto:+se-attribute-flag-lo12+ . :lo12)\n      (#.proto:+se-attribute-flag-lo15+ . :lo15)\n      (#.proto:+se-attribute-flag-lo14+ . :lo14)\n      (#.proto:+se-attribute-flag-hi12+ . :hi12)\n      (#.proto:+se-attribute-flag-hi21+ . :hi21)\n      (#.proto:+se-attribute-flag-s+ . :s)\n      (#.proto:+se-attribute-flag-pg+ . :pg)\n      (#.proto:+se-attribute-flag-nc+ . :nc)\n      (#.proto:+se-attribute-flag-abs+ . :abs)\n      (#.proto:+se-attribute-flag-prel+ . :prel)\n      (#.proto:+se-attribute-flag-prel31+ . :prel31)\n      (#.proto:+se-attribute-flag-target1+ . :target1)\n      (#.proto:+se-attribute-flag-target2+ . :target2)\n      (#.proto:+se-attribute-flag-sbrel+ . :sbrel)\n      (#.proto:+se-attribute-flag-tlsldo+ . :tlsldo)\n      (#.proto:+se-attribute-flag-hi16+ . :hi16)\n      (#.proto:+se-attribute-flag-lo16+ . :lo16)\n      (#.proto:+se-attribute-flag-gprel+ . :gprel)\n      (#.proto:+se-attribute-flag-disp+ . :disp)\n      (#.proto:+se-attribute-flag-ofst+ . :ofst)\n      (#.proto:+se-attribute-flag-h+ . :h)\n      (#.proto:+se-attribute-flag-l+ . :l)\n      (#.proto:+se-attribute-flag-ha+ . :ha)\n      (#.proto:+se-attribute-flag-high+ . :high)\n      (#.proto:+se-attribute-flag-higha+ . :higha)\n      (#.proto:+se-attribute-flag-highera+ . :highera)\n      (#.proto:+se-attribute-flag-highesta+ . :highesta)\n      (#.proto:+se-attribute-flag-tocbase+ . :tocbase)\n      (#.proto:+se-attribute-flag-toc+ . :toc)\n      (#.proto:+se-attribute-flag-notoc+ . :notoc))\n  :test #'equal\n  :documentation \"See doc/general/SymbolicExpression.md for more details.\")\n\n(define-proto-backed-class (byte-interval proto:byte-interval) ()\n    ((blocks :initarg :blocks :accessor blocks :type list\n             :from-proto\n             [{map 'list\n                   (lambda (proto-block)\n                     (let ((it (cond\n                                 ((not (emptyp\n                                        (proto:uuid (proto:data proto-block))))\n                                  (make-instance 'data-block\n                                    :ir (ir self)\n                                    :byte-interval self\n                                    :offset (proto:offset proto-block)\n                                    :proto (proto:data proto-block)))\n                                 ((not (emptyp\n                                        (proto:uuid (proto:code proto-block))))\n                                  (make-instance 'code-block\n                                    :ir (ir self)\n                                    :byte-interval self\n                                    :offset (proto:offset proto-block)\n                                    :proto (proto:code proto-block))))))\n                       #+debug\n                       (when (emptyp (proto:uuid (proto it)))\n                         (warn \"BAD BLOCK ~a with empty uuid from ~a.~%~A~%\"\n                               it (name (section self)) proto-block))\n                       it))}\n              #'proto:blocks]\n             :to-proto\n             {map 'vector\n                  (lambda (gtirb-block)\n                    (let ((it (make-instance 'proto:block)))\n                      (setf (proto:offset it) (offset gtirb-block))\n                      (etypecase gtirb-block\n                        (code-block\n                         (setf (proto:code it) (update-proto gtirb-block)))\n                        (data-block\n                         (setf (proto:data it) (update-proto gtirb-block))))\n                      it))}\n             :documentation\n             \"Blocks in this byte-interval.\nThis list could include `code-block' or `data-block' elements (which\nboth subclass the `gtirb-byte-block' class) but not `proxy-block'\nelements as proxy blocks do not hold bytes.\")\n     (symbolic-expressions\n      :accessor symbolic-expressions :type hash-table\n      :initarg :symbolic-expressions\n      :from-proto\n      (lambda (proto &aux (table (make-hash-table)))\n        (flet ((process-symbols (&rest symbols)\n                 (mappend (lambda (uuid)\n                            (if-let ((sym (get-uuid (uuid-to-integer uuid)\n                                                    (ir self))))\n                              (list sym)\n                              (unless (emptyp uuid)\n                                (warn \"Symbol UUID ~S not found\" uuid))))\n                          symbols)))\n          (dotimes (n (length (proto:symbolic-expressions proto)) table)\n            (let* ((proto (aref (proto:symbolic-expressions proto) n))\n                   (offset (proto:key proto))\n                   (attribute-flags\n                    (map 'list [#'cdr {assoc _ +se-attribute-flag-map+}]\n                         (proto:attribute-flags (proto:value proto))))\n                   (symbolic-expression (proto:value proto)))\n              (setf (gethash offset table)\n                    (cond\n                      ((proto:has-addr-const symbolic-expression)\n                       (make-instance 'sym-addr-const\n                         :ir (ir self)\n                         :attribute-flags attribute-flags\n                         :symbols (process-symbols\n                                   (proto:symbol-uuid\n                                    (proto:addr-const symbolic-expression)))\n                         :proto (proto:addr-const symbolic-expression)))\n                      ((proto:has-addr-addr symbolic-expression)\n                       (make-instance 'sym-addr-addr\n                         :ir (ir self)\n                         :attribute-flags attribute-flags\n                         :symbols (process-symbols\n                                   (proto:symbol1-uuid\n                                    (proto:addr-addr symbolic-expression))\n                                   (proto:symbol2-uuid\n                                    (proto:addr-addr symbolic-expression)))\n                         :proto (proto:addr-addr symbolic-expression)))\n                      (t (assert \"Symbolic expression of unknown kind.\"))))))))\n      :to-proto\n      [{map 'vector\n            (lambda (pair)\n              (destructuring-bind (offset . symbolic-expression) pair\n                (flet ((force-attribute-flags-array (array)\n                         (declare (type (simple-array) array))\n                         (make-array (length array)\n                                     :element-type `(mod ,(length +se-attribute-flag-map+))\n                                     :initial-contents array)))\n                  (let ((it (make-instance\n                                'proto:byte-interval-symbolic-expressions-entry)))\n                    (setf (proto:key it) offset\n                          (proto:value it)\n                          (let ((it (make-instance 'proto:symbolic-expression)))\n                            (when (attribute-flags symbolic-expression)\n                              (setf (proto:attribute-flags it)\n                                    (force-attribute-flags-array\n                                     (map 'vector\n                                          [#'car {rassoc _ +se-attribute-flag-map+}]\n                                          (attribute-flags symbolic-expression)))))\n                            (etypecase symbolic-expression\n                              (sym-addr-const\n                               (setf (proto:addr-const it)\n                                     (update-proto symbolic-expression)))\n                              (sym-addr-addr\n                               (setf (proto:addr-addr it)\n                                     (update-proto symbolic-expression))))\n                            it))\n                    it))))}\n       #'hash-table-alist]\n      :documentation \"Hash of symbolic-expressions keyed by offset.\"))\n    ((addressp :type boolean :proto-field has-address\n               :documentation\n               \"Does this byte-interval have an address.\")\n     (address :type unsigned-byte-64\n              :documentation\n              \"Optionally specify the address in memory at which this\n~ byte-interval should start.  Byte-intervals without address could\nexist anywhere in memory.\")\n     (size :type unsigned-byte-64 :documentation\n           \"The size of this byte-interval.\nIt is possible for the size of a byte-interval to be larger than the\nnumber of bytes in the byte interval's `contents' if portions of the\nbyte-interval are not represented statically but are zero-initialized\nat runtime.\")\n     (contents :type bytes :documentation\n               \"A vector holding the actual bytes of this byte interval.\"))\n  (:documentation \"Byte-interval in a GTIRB instance.\") (:parent section)\n  (:address-range (when (addressp self)\n                    (list (address self) (+ (address self) (size self))))))\n\n(defmethod (setf size) :before (new (obj byte-interval))\n  (restart-case\n      (when (> (length (contents obj)) new)\n        (error (make-condition 'ir\n                               :message \"size smaller than contents\"\n                               :object obj)))\n    (truncate-contents ()\n      :report \"Truncate the contents of the byte-interval to the new size.\"\n      (setf (contents obj) (subseq (contents obj) 0 new)))\n    (ignore ()\n      :report \"Ignore and leave the byte-interval in an inconsistent state.\")))\n\n(defmethod print-object ((obj byte-interval) stream)\n  (print-unreadable-object (obj stream :type t :identity t)\n    (format stream \"~a ~a\"\n            (if (addressp obj) (address obj) \"?\")\n            (size obj))))\n\n(defmethod address ((obj byte-interval))\n  (when (addressp obj) (proto:address (proto obj))))\n\n(defclass symbolic-expression ()\n  ((symbols :accessor symbols :initarg :symbols :initform nil :type list\n            :documentation \"Symbol(s) appearing in this symbolic expression.\")\n   (attribute-flags :accessor attribute-flags :initarg :attribute-flags\n                    :initform nil :type list\n                    :documentation \"Attributes holding the relocation type.\")))\n\n(defmethod print-object ((obj symbolic-expression) stream)\n  (print-unreadable-object (obj stream :type t :identity t)\n    (format stream \"~a ~{~a~^, ~}\" (offset obj) (symbols obj))))\n\n;;; TODO: If we get symbolic expressions for these, then add the\n;;; following to each `symbolic-expression' class:\n;;;\n;;;     (:parent byte-interval)\n;;;     (:address-range (when-let ((range (addressp (byte-interval self))))\n;;;                       (+ (offset self) (first range))))\n;;;\n;;; and then go back up and add \":byte-interval self\" to their\n;;; `make-instance' calls in byte-interval.\n(define-proto-backed-class\n    (sym-addr-const proto:sym-addr-const) (symbolic-expression) ()\n    ((offset :type unsigned-byte-64))\n  (:address-range (when (addressp (byte-interval self))\n                    (let ((address (+ (address (byte-interval self))\n                                      (offset self))))\n                      (list address address)))))\n\n(define-proto-backed-class\n    (sym-addr-addr proto:sym-addr-addr) (symbolic-expression) ()\n    ((offset :type unsigned-byte-64)\n     (scale :type unsigned-byte-64))\n  (:address-range (when (addressp (byte-interval self))\n                    (let ((address (+ (address (byte-interval self))\n                                      (offset self))))\n                      (list address address)))))\n\n(defmethod update-proto :before ((sym sym-addr-const))\n  (setf (proto:symbol-uuid (proto sym))\n        (integer-to-uuid (uuid (first (symbols sym))))))\n\n(defmethod update-proto :before ((sym sym-addr-addr))\n  (setf (proto:symbol1-uuid (proto sym))\n        (integer-to-uuid (uuid (first (symbols sym))))\n        (proto:symbol2-uuid (proto sym))\n        (integer-to-uuid (uuid (second (symbols sym))))))\n\n(defmethod update-proto :before ((sym sym-addr-const))\n  (setf (proto:symbol-uuid (proto sym))\n        (integer-to-uuid (uuid (first (symbols sym))))))\n\n(defmethod update-proto :before ((sym sym-addr-addr))\n  (setf (proto:symbol1-uuid (proto sym))\n        (integer-to-uuid (uuid (first (symbols sym))))\n        (proto:symbol2-uuid (proto sym))\n        (integer-to-uuid (uuid (second (symbols sym))))))\n\n(defclass gtirb-block () ())\n\n(defclass gtirb-byte-block (gtirb-block) ()\n  (:documentation \"Super-class of the `code-block' and `data-block' classes.\nThis class abstracts over all GTIRB blocks which are able to hold bytes.\"))\n\n(defmethod symbolic-expressions ((bb gtirb-byte-block))\n  (nest\n   (alist-hash-table)\n   (remove-if-not [«and {< (offset bb)} {>= (+ (offset bb) (size bb))}» #'car])\n   (hash-table-alist)\n   (symbolic-expressions)\n   (byte-interval bb)))\n\n(defmethod address ((obj gtirb-byte-block))\n  (when-let ((base-address (address (byte-interval obj))))\n    (+ base-address (offset obj))))\n\n(defgeneric bytes (object &optional start end)\n  (:documentation \"Return the bytes held by OBJECT.\")\n  (:method ((obj byte-interval) &optional (start 0) end)\n    (if end\n        (subseq (contents obj) start end)\n        (subseq (contents obj) start)))\n  (:method ((obj gtirb-byte-block) &optional (start 0) (end (size obj)))\n    #+debug (format t \"[~S] ~S:[~S:~S]<-[~S:~S]~%\"\n                    (proto:uuid (proto obj))\n                    (name (section (byte-interval obj)))\n                    (or (and (addressp (byte-interval obj))\n                             (address (byte-interval obj)))\n                        \"?\")\n                    (size (byte-interval obj))\n                    (offset obj) (size obj))\n    (let* ((start (+ (offset obj) start))\n           (end (+ (offset obj) end)))\n      (assert (<= end (size (byte-interval obj))) (obj)\n              \"Block's end ~d exceeds size of containing byte-interval ~d.\"\n              end (size (byte-interval obj)))\n      (let ((real-end (length (contents (byte-interval obj)))))\n        (cond\n          ((<= end real-end)            ; Allocated bytes.\n           (subseq (contents (byte-interval obj)) start end))\n          ((<= start real-end) ; Both allocated and un-allocated bytes.\n           (concatenate 'vector (subseq (contents (byte-interval obj)) start)\n                        (make-array (- end real-end) :initial-element 0)))\n          (t                          ; Un-allocated bytes, zero-fill.\n           (make-array (size obj) :initial-element 0)))))))\n\n(defun shift-subseq (sequence start end)\n  \"Return a copy of SEQUENCE bounded by START and END.\"\n  (subseq sequence start end))\n\n(defparameter *preserve-symbolic-expressions* nil\n  \"When true, (setf bytes) preserves symbolic expressions\nintersecting the assigned part of the object.\")\n\n(define-setf-expander shift-subseq (sequence start end &environment env)\n  \"Update the subseq of SEQUENCE bounded by START and END.\"\n  (multiple-value-bind (dummies vals newval setter getter)\n      (get-setf-expansion sequence env)\n    (declare (ignorable newval setter))\n    (let ((store (gensym)))\n      (values\n       dummies                          ; Temporary variables\n       vals                             ; Value forms.\n       (list store)                     ; Store variables.\n       `(progn\n          (cond\n            ((zerop ,start)\n             (setf ,getter\n                   (concatenate 'vector ,store (subseq ,getter ,end))))\n            ((= (length ,store) (- ,end ,start))\n             (setf (subseq ,getter ,start ,end) ,store))\n            ((>= ,end (length ,getter))\n             (setf ,getter\n                   (concatenate 'vector (subseq ,getter 0 ,start) ,store)))\n            (t (setf ,getter (concatenate 'vector\n                                          (subseq ,getter 0 ,start)\n                                          ,store\n                                          (subseq ,getter ,end)))))\n          ,store)                       ; Storing form.\n       `(shift-subseq ,getter)))))      ; Accessing form.\n\n(define-setf-expander bytes (sequence &optional (start 0) (end nil end-p)\n                             &environment env)\n  (multiple-value-bind (dummies vals newval setter getter)\n      (get-setf-expansion sequence env)\n    (declare (ignorable newval setter))\n    (let ((store (gensym))\n          (end (if end-p end `(length (bytes ,getter)))))\n      (values\n       dummies                          ; Temporary variables\n       vals                             ; Value forms.\n       (list store)                     ; Store variables.\n       `(progn\n          (etypecase ,getter\n            (gtirb::byte-interval\n             (setf (shift-subseq (contents ,getter) ,start ,end) ,store))\n            (gtirb::gtirb-byte-block\n             (with-slots (offset) ,getter\n               (let ((original-offset offset))\n                 (setf (shift-subseq (contents (byte-interval ,getter))\n                                     (+ offset ,start) (+ offset ,end))\n                       ,store)\n                 (setf-bytes-after ,store (byte-interval ,getter)\n                                   (+ offset ,start) (+ offset ,end))\n                 ;; Ensure the offset for THIS block isn't pushed back change.\n                 (setf offset original-offset)))))\n\n          (setf-bytes-after ,store ,getter ,start ,end)\n          ,store)                       ; Storing form.\n       `(bytes ,getter)))))             ; Accessing form.\n\n(defvar *update-aux-data-offsets* nil\n  \"Are offsets in AuxData tables updated as bytes are modified.\")\n\n(defgeneric setf-bytes-after (new object &optional start end)\n  (:documentation\n   \"Update the offsets into BYTE-INTERVAL due to saving NEW into START END.\")\n  (:method (new (byte-interval byte-interval)\n            &optional (start 0) (end (size byte-interval)))\n    (setf (size byte-interval)\n          (+ start (length new) (- (size byte-interval) end)))\n    (let ((difference (- (length new) (- end start))))\n      ;; Symbolic expressions.\n      (nest (setf (symbolic-expressions byte-interval))\n            (alist-hash-table)\n            (mappend (lambda (pair)\n                       (destructuring-bind (offset . sym-expr) pair\n                         (cond\n                           ((< offset start) (list (cons offset sym-expr)))\n                           ((>= offset end)\n                            (list (cons (+ offset difference) sym-expr)))\n                           ;; Clear symbolic expressions in the modified range,\n                           ;; unless *preserve-symbolic-expressions* is true.\n                           (t (if *preserve-symbolic-expressions* (list pair) nil))))))\n            (hash-table-alist (symbolic-expressions byte-interval)))\n      (when *update-aux-data-offsets*\n        ;; Update offsets in AuxData tables.\n        (labels ((update-offset (data type)\n                   (cond\n                     ((and (listp type) (eql :mapping (car type)))\n                      (nest (alist-hash-table)\n                            (mapcar «cons\n                                     [{update-offset _ (second type)} #'car]\n                                     [{update-offset _ (third type)} #'cdr]»)\n                            (hash-table-alist data)))\n                     ((and (listp type) (eql :sequence (car type)))\n                      (mapcar {update-offset _ (cdr type)} data))\n                     ((eql :offset type)\n                      ;; NOTE: Since we are already adjusting all\n                      ;;       other code blocks and offsets are\n                      ;;       currently stored by code block we only\n                      ;;       need to update offsets in the current\n                      ;;       code block.\n                      ;; NOTE: Offsets are relative to the base of the\n                      ;;       code block but START is relative to the\n                      ;;       base of the byte-interval.\n                      ;; NOTE: Only update offsets in the current\n                      ;;       block.\n                      (let* ((obj (get-uuid (first data) byte-interval))\n                             (obj-start (if (typep obj 'gtirb-byte-block)\n                                            (offset obj)\n                                            most-positive-fixnum))\n                             (obj-end (+ obj-start (size obj)))\n                             (off (second data)))\n                        (when (and\n                               ;; Changes bytes intersect this block\n                               (or (and (>= obj-start start)\n                                        (<= obj-start end))\n                                   (and (>= obj-end start)\n                                        (<= obj-end end)))\n                               ;; This offset is after the start\n                               ;; of the changed bytes\n                               (>= (+ (offset obj) off) start))\n                          (incf (second data) difference)))\n                      data)\n                     (t data))))\n          (mapcar\n           (lambda (pair)\n             (let ((table (cdr pair)))\n               (setf (aux-data-data table)\n                     (update-offset (aux-data-data table)\n                                    (aux-data-type table)))))\n           (aux-data-w-offsets (ir byte-interval)))))\n      ;; Byte-Blocks.\n      (mapc (lambda (bb)\n              (with-slots (offset) bb\n                (when (>= offset end)\n                  (incf offset difference))))\n            (blocks byte-interval)))\n    new)\n  (:method (new (bb gtirb-byte-block) &optional (start 0) (end (size bb)))\n    ;; Update the size of the byte-block\n    (setf (size bb) (+ start (length new) (- (size bb) end)))\n    new))\n\n(define-proto-backed-class (code-block proto:code-block) (gtirb-byte-block)\n    ((offset :initarg :offset :accessor offset :type number\n             :documentation\n             \"Offset into this block's bytes in the block's byte-interval.\"))\n    ((size :type unsigned-byte-64\n           :documentation \"The length of the bytes held by this code block.\")\n     (decode-mode :type unsigned-byte-64 :documentation\n                  \"Only present on architecture with multiple decode-modes.\"))\n  (:documentation \"Code-block in a GTIRB IR instance.\") (:parent byte-interval)\n  (:address-range (when-let ((range (address-range (byte-interval self))))\n                    (list (+ (offset self) (first range))\n                          (+ (offset self) (size self) (first range))))))\n\n(defmethod print-object ((obj code-block) stream)\n  (print-unreadable-object (obj stream :type t :identity t)\n    (format stream \"~a ~a\" (size obj) (decode-mode obj))))\n\n(defgeneric entry-point (module)\n  (:documentation \"The code-block which is the entry point of MODULE.\")\n  (:method ((obj module))\n    (get-uuid (uuid-to-integer (proto:entry-point (proto obj))) obj)))\n\n(defmethod (setf entry-point) ((new code-block) (obj module))\n  (proto:clear-entry-point (proto obj))\n  (setf (proto:entry-point (proto obj)) (integer-to-uuid (uuid new))))\n\n(define-proto-backed-class (data-block proto:data-block) (gtirb-byte-block)\n    ((offset :initarg :offset :accessor offset :type number\n             :documentation\n             \"Offset into this block's bytes in the block's byte-interval.\"))\n    ((size :type unsigned-byte-64 :documentation\n           \"The length of the bytes held by this data block.\"))\n  (:documentation \"Data-block in a GTIRB IR instance.\")\n  (:parent byte-interval)\n  (:address-range (when-let ((range (address-range (byte-interval self))))\n                    (list (+ (offset self) (first range))\n                          (+ (offset self) (size self) (first range))))))\n\n(defmethod print-object ((obj data-block) stream)\n  (print-unreadable-object (obj stream :type t :identity t)\n    (format stream \"~a\" (size obj))))\n\n(define-proto-backed-class (proxy-block proto:proxy-block) (gtirb-block) () ()\n  (:documentation \"Proxy-block in a GTIRB IR instance.\")\n  (:parent module))\n\n(defmethod print-object ((obj proxy-block) stream)\n  (print-unreadable-object (obj stream :type t :identity t)))\n\n\f\n;;;; AuxData type and data handling.\n(define-proto-backed-class (aux-data proto:aux-data) () () ())\n\n(defmethod print-object ((obj aux-data) stream)\n  (print-unreadable-object (obj stream :type t :identity t)\n    (format stream \"~a\" (aux-data-type obj))))\n\n(defun aux-data-from-proto (proto)\n  (let ((p-aux-data (proto:aux-data proto))\n        (aux-data '()))\n    (dotimes (n (length p-aux-data))\n      (push (cons (pb:string-value (proto:key (aref p-aux-data n)))\n                  (make-instance 'aux-data\n                    :proto (proto:value (aref p-aux-data n))))\n            aux-data))\n    aux-data))\n\n(defun aux-data-to-proto (aux-data)\n  (map 'vector (lambda (pair)\n                 (destructuring-bind (name . aux-data) pair\n                   (let ((entry\n                          (make-instance 'proto:module-aux-data-entry)))\n                     (setf (proto:key entry) (pb:string-field name)\n                           (proto:value entry) (proto aux-data))\n                     entry)))\n       aux-data))\n\n(defmacro start-case (string &body body)\n  `(progn\n     ;; (declare (type string ,string))\n     (assert (stringp ,string) (,string) \"Argument ~s is not a string.\" ,string)\n     (cond\n       ,@(mapcar (lambda (form)\n                   (destructuring-bind (prefix . body) form\n                     (if (stringp prefix)\n                         `((eql (search ,prefix ,string) 0)\n                           (let ((,string (subseq ,string ,(length prefix))))\n                             ,@body))\n                         (cons prefix body))))\n                 body))))\n\n(defparameter +integer-typename-regex+ (create-scanner \"(U?INT)([0-9]+)-T\")\n  \"Regex for deconstructing an integer typename.\")\n\n(defun matching (open-char close-char string)\n  \"Return the first balanced offset of CLOSE-CHAR in STRING.\nSTRING is assumed to already have one extant OPEN-CHAR which needs to\nbe matched.  New instances of OPEN-CHAR must be closed by balanced\nCLOSE-CHARs before the CLOSE-CHAR matching the implicit extant\nOPEN-CHAR.\"\n  (let ((offset 1))\n    (dotimes (n (length string))\n      (cond\n        ((eql (aref string n) open-char) (incf offset))\n        ((eql (aref string n) close-char) (decf offset)))\n      (when (zerop offset)\n        (return-from matching n))))\n  (error \"Can't close (~a ~a) in ~s.\" open-char close-char string))\n\n(defun aux-data-type-read (type-string)\n  (when (and type-string (not (emptyp type-string)))\n    (start-case type-string\n      (\"mapping<\"\n       (let ((close (matching #\\< #\\> type-string)))\n         (cons (cons :mapping (aux-data-type-read (subseq type-string 0 close)))\n               (aux-data-type-read (subseq type-string close)))))\n      (\"set<\"\n       (let ((close (matching #\\< #\\> type-string)))\n         (cons (cons :set (aux-data-type-read (subseq type-string 0 close)))\n               (aux-data-type-read (subseq type-string close)))))\n      (\"sequence<\"\n       (let ((close (matching #\\< #\\> type-string)))\n         (cons (cons :sequence (aux-data-type-read (subseq type-string 0 close)))\n               (aux-data-type-read (subseq type-string close)))))\n      (\"tuple<\"\n       (let ((close (matching #\\< #\\> type-string)))\n         (cons (cons :tuple (aux-data-type-read (subseq type-string 0 close)))\n               (aux-data-type-read (subseq type-string close)))))\n      (\"variant<\"\n       (let ((close (matching #\\< #\\> type-string)))\n         (cons (cons :variant (aux-data-type-read (subseq type-string 0 close)))\n               (aux-data-type-read (subseq type-string close)))))\n      (\",\" (aux-data-type-read type-string))\n      (\">\" (aux-data-type-read type-string))\n      (\"UUID\" (cons :uuid (aux-data-type-read type-string)))\n      (\"Addr\" (cons :addr (aux-data-type-read type-string)))\n      (\"Offset\" (cons :offset (aux-data-type-read type-string)))\n      (\"string\" (cons :string (aux-data-type-read type-string)))\n      (\"bool\" (cons :bool (aux-data-type-read type-string)))\n      (\"uint8_t\" (cons :uint8-t (aux-data-type-read type-string)))\n      (\"uint16_t\" (cons :uint16-t (aux-data-type-read type-string)))\n      (\"uint32_t\" (cons :uint32-t (aux-data-type-read type-string)))\n      (\"uint64_t\" (cons :uint64-t (aux-data-type-read type-string)))\n      (\"int8_t\" (cons :int8-t (aux-data-type-read type-string)))\n      (\"int16_t\" (cons :int16-t (aux-data-type-read type-string)))\n      (\"int32_t\" (cons :int32-t (aux-data-type-read type-string)))\n      (\"int64_t\" (cons :int64-t (aux-data-type-read type-string)))\n      (\"float\" (cons :float (aux-data-type-read type-string)))\n      (\"double\" (cons :double (aux-data-type-read type-string)))\n      (t (error \"Junk in type string ~a\" type-string)))))\n\n(defgeneric aux-data-type (aux-data)\n  (:documentation \"Access the structured type of AUX-DATA.\")\n  (:method ((obj aux-data))\n    (first (aux-data-type-read\n            (pb:string-value (proto:type-name (proto obj)))))))\n\n(defun aux-data-type-print (stream\n                            type\n                            &optional\n                              colon-modifier-supplied-p\n                              at-sign-modifier-supplied-p\n                              (repetitions 1))\n  (declare (type (or null (eql t) stream string) stream))\n  (declare (ignorable colon-modifier-supplied-p at-sign-modifier-supplied-p repetitions))\n  (when type\n    (if (listp type)\n        (case (first type)\n          (:mapping\n           (format stream \"mapping<~/gtirb:aux-data-type-print/,~/gtirb:aux-data-type-print/>\"\n                   (second type)\n                   (third type)))\n          (:set (format stream \"set<~/gtirb:aux-data-type-print/>\" (second type)))\n          (:sequence (format stream \"sequence<~/gtirb:aux-data-type-print/>\" (second type)))\n          (:tuple (format stream \"tuple<~{~/gtirb:aux-data-type-print/~^,~}>\" (cdr type)))\n          (:variant (format stream \"variant<~{~/gtirb:aux-data-type-print/~^,~}>\" (cdr type))))\n        (format stream (ecase type\n                         (:uuid \"UUID\")\n                         (:addr \"Addr\")\n                         (:offset \"Offset\")\n                         (:string \"string\")\n                         (:bool \"bool\")\n                         (:uint8-t \"uint8_t\")\n                         (:uint16-t \"uint16_t\")\n                         (:uint32-t \"uint32_t\")\n                         (:uint64-t \"uint64_t\")\n                         (:int8-t \"int8_t\")\n                         (:int16-t \"int16_t\")\n                         (:int32-t \"int32_t\")\n                         (:int64-t \"int64_t\")\n                         (:float \"float\")\n                         (:double \"double\"))))))\n\n(defmethod (setf aux-data-type) (new (obj aux-data))\n  (setf (proto:type-name (proto obj))\n        (pb:string-field (format nil \"~/gtirb::aux-data-type-print/\" new))))\n\n(defgeneric aux-data-data (aux-data)\n  (:documentation \"Access the structured representation of AUX-DATAs data.\")\n  (:method ((obj aux-data))\n    (aux-data-decode (aux-data-type obj) (proto:data (proto obj)))))\n\n(defmethod (setf aux-data-data) (new (obj aux-data))\n  (setf (proto:data (proto obj))\n        (force-byte-array (aux-data-encode (aux-data-type obj) new))))\n\n(defun parse-num-bytes (num-bits-string)\n  (/ (parse-integer num-bits-string) 8))\n\n(declaim (special *decode-data*))\n(defun decode (type)\n  (labels ((advance (n) (setf *decode-data* (subseq *decode-data* n)))\n           (decode-int (type)\n             (register-groups-bind (type-signage (#'parse-num-bytes num-bytes))\n                 (+integer-typename-regex+ (symbol-name type))\n               (prog1\n                   (if (string= type-signage \"UINT\")\n                       (octets->uint (subseq *decode-data* 0 num-bytes)\n                                     num-bytes)\n                       (octets->int (subseq *decode-data* 0 num-bytes)\n                                    num-bytes))\n                 (advance num-bytes)))))\n    (declare (inline advance))\n    (match type\n      ((or :uint8-t :int8-t :uint16-t :int16-t\n           :uint32-t :int32-t :uint64-t :int64-t)\n       (decode-int type))\n      (:float\n       (decode-float32 (decode-int :uint32-t)))\n      (:double\n       (decode-float64 (decode-int :uint64-t)))\n      (:addr\n       (prog1\n           (octets->uint (subseq *decode-data* 0 8) 8)\n         (advance 8)))\n      (:bool\n       (prog1\n           (not (zerop (octets->uint (subseq *decode-data* 0 1) 1)))\n         (advance 1)))\n      (:uuid\n       (prog1 (uuid-to-integer (subseq *decode-data* 0 16)) (advance 16)))\n      (:offset\n       (handler-bind\n           ((error\n             (lambda (e)\n               (declare (ignorable e))\n               (let* ((offset (make-instance 'proto:offset))\n                      (size (pb:octet-size offset)))\n                 (pb:merge-from-array offset *decode-data* 0 size)\n                 (prog1 offset (advance size))))))\n         (list (decode :uuid) (decode :uint64-t))))\n      (:string\n       (let ((size (decode :uint64-t)))\n         (prog1 (utf-8-bytes-to-string (subseq *decode-data* 0 size))\n           (advance size))))\n      ((list :mapping key-t value-t)\n       (let ((result (make-hash-table :test #'equal)))\n         (dotimes (n (decode :uint64-t) result)\n           (declare (ignorable n))\n           (let* ((key (decode key-t))\n                  (value (decode value-t)))\n             (setf (gethash key result) value)))))\n      ((list (or :sequence :set) type)\n       (let (result)\n         (reverse\n          (dotimes (n (decode :uint64-t) result)\n            (declare (ignorable n))\n            (push (decode type) result)))))\n      ((list* :tuple types)\n       (mapcar #'decode types))\n      ((list* :variant types)\n       (let ((index (decode :uint64-t)))\n         (cons index (decode (nth index types))))))))\n(defun aux-data-decode (type data)\n  (let ((*decode-data* data))\n    (decode type)))\n\n(defun encode (type data)\n  (labels ((extend (it) (push it *decode-data*))\n           (encode-int (type data)\n             (register-groups-bind (_ (#'parse-num-bytes num-bytes))\n                 (+integer-typename-regex+ (symbol-name type))\n               (declare (ignorable _))\n               (extend (int->octets data num-bytes)))))\n    (declare (inline extend))\n    (match type\n      ((or :uint8-t :int8-t :uint16-t :int16-t\n           :uint32-t :int32-t :uint64-t :int64-t)\n       (encode-int type data))\n      (:float\n       (encode-int :uint32-t (encode-float32 data)))\n      (:double\n       (encode-int :uint64-t (encode-float64 data)))\n      (:addr\n       (extend (int->octets data 8)))\n      (:bool\n       (extend (int->octets (if data 1 0) 1)))\n      (:uuid\n       (extend (integer-to-uuid data)))\n      (:offset\n       (etypecase data\n         (proto:offset\n          (let* ((size (pb:octet-size data))\n                 (buffer (make-array size :element-type '(unsigned-byte 8))))\n            (pb:serialize data buffer 0 size)\n            (extend buffer)))\n         (list\n          (progn (encode :uuid (first data))\n                 (encode :uint64-t (second data))))))\n      (:string\n       (let ((string-bytes (string-to-utf-8-bytes data)))\n         (encode :uint64-t (length string-bytes))\n         (extend string-bytes)))\n      ((list :mapping key-t value-t)\n       (encode :uint64-t (hash-table-count data))\n       (maphash (lambda (key value)\n                  (encode key-t key)\n                  (encode value-t value))\n                data))\n      ((list (or :sequence :set) type)\n       (let ((size (length data)))\n         (encode :uint64-t size)\n         (dotimes (n size)\n           (encode type (elt data n)))))\n      ((list* :tuple types)\n       (mapc (lambda (type datum)\n               (encode type datum))\n             types data))\n      ((list* :variant types)\n       (encode :uint64-t (car data))\n       (encode (nth (car data) types) (cdr data))))))\n(defun aux-data-encode (type data)\n  (let ((*decode-data* nil))\n    (encode type data)\n    (reduce {concatenate 'vector} (reverse *decode-data*))))\n"
  },
  {
    "path": "cl/package.lisp",
    "content": "(defpackage :gtirb\n  (use-package :common-lisp))\n"
  },
  {
    "path": "cl/ranged.lisp",
    "content": "(defpackage :gtirb/ranged\n  (:use :common-lisp)\n  (:import-from :interval)\n  (:export :make-ranged\n           :ranged-insert\n           :ranged-delete\n           :ranged-find\n           :ranged-find-at))\n(in-package :gtirb/ranged)\n#-debug (declaim (optimize (speed 3) (safety 0) (debug 0)))\n#+debug (declaim (optimize (speed 0) (safety 3) (debug 3)))\n\n(defun make-ranged ()\n  (interval:make-tree))\n\n(defstruct (uuid-interval (:include interval:interval))\n  (uuid 0 :type integer))\n\n(defun uuid-interval= (i1 i2)\n  (= (uuid-interval-uuid i1) (uuid-interval-uuid i2)))\n\n(defun ranged-insert (tree uuid start end)\n  (interval:insert tree (make-uuid-interval :uuid uuid\n                                            :start start\n                                            :end end)))\n\n(defun ranged-delete (tree uuid start end)\n  (interval:delete tree (make-uuid-interval :uuid uuid\n                                            :start start\n                                            :end end)))\n\n(defun ranged-find-at (tree address)\n  (mapcar #'uuid-interval-uuid\n          (remove-if-not (lambda (i)\n                           (= address (interval:interval-start i)))\n                         (interval:find-all tree address))))\n\n(defun ranged-find (tree start &optional (end start))\n  (mapcar #'uuid-interval-uuid (interval:find-all tree (cons start end))))\n"
  },
  {
    "path": "cl/test.lisp",
    "content": "(defpackage :gtirb/test\n  (:use :common-lisp\n        :alexandria\n        :flexi-streams\n        :stefil\n        :gtirb\n        :gtirb/dot\n        :gtirb/utility\n        :gtirb/ranged\n        :gtirb/version\n        :graph\n        :named-readtables :curry-compose-reader-macros)\n  (:import-from :trivial-package-local-nicknames :add-package-local-nickname)\n  (:import-from :gtirb.proto)\n  (:import-from :gtirb/utility :check-magic-header :write-magic-header)\n  (:import-from :md5 :md5sum-file :md5sum-sequence)\n  (:import-from :uiop :nest :run-program :with-temporary-file :quit)\n  (:import-from :asdf/system :system-relative-pathname)\n  (:shadowing-import-from :gtirb :symbol)\n  (:export :test :batch-test))\n(in-package :gtirb/test)\n(in-readtable :curry-compose-reader-macros)\n\n(eval-when (:compile-toplevel :load-toplevel :execute)\n  (add-package-local-nickname :proto :gtirb.proto))\n\n(defvar *proto-path* nil \"Path to protobuf.\")\n\n(defun batch-test (&optional args)\n  \"Run tests in 'batch' mode printing results to STDERR then quit.\nThe ERRNO used when exiting lisp indicates success or failure.\"\n  (declare (ignorable args))\n  (let* ((stefil::*test-progress-print-right-margin* (expt 2 20))\n         (failures (coerce (stefil::failure-descriptions-of\n                            (without-debugging (test)))\n                           'list)))\n    (if failures\n        (format *error-output* \"FAILURES~%~{  ~a~~%~}\"\n                (mapc [#'stefil::name-of\n                       #'stefil::test-of\n                       #'car #'stefil::test-context-backtrace-of]\n                      failures))\n        (format *error-output* \"SUCCESS~%\"))\n    (quit (if failures 2 0))))\n\n(defvar *gtirb-dir* (system-relative-pathname \"gtirb\" \"../\"))\n\n\f\n;;;; Fixtures.\n(defixture hello\n  (:setup\n   (progn\n     #+live-w-ddisasm\n     (with-temporary-file (:pathname bin-path)\n       (setf *proto-path* (with-temporary-file (:pathname p :keep t) p))\n       (run-program (format nil \"echo 'main(){puts(\\\"hello world\\\");}'~\n                                     |gcc -x c - -o ~a\"\n                            bin-path) :force-shell t)\n       (run-program\n        (format nil \"ddisasm --ir ~a ~a\" *proto-path* bin-path)))\n     #-live-w-ddisasm\n     (setf *proto-path*\n           (merge-pathnames \"python/tests/hello.gtirb\" *gtirb-dir*))))\n  (:teardown\n   (progn\n     #+live-w-ddisasm (delete-file *proto-path*)\n     (setf *proto-path* nil))))\n\n\f\n;;;; Main test suite.\n(defsuite test)\n(in-suite test)\n\n(deftest we-have-versions ()\n  (is (stringp gtirb-version))\n  (is (integerp protobuf-version)))\n\n(deftest simple-read ()\n  (with-fixture hello\n    (is (eql 'proto:ir\n             (class-name (class-of (read-proto 'proto:ir *proto-path*)))))))\n\n(deftest simple-write ()\n  (with-fixture hello\n    (with-temporary-file (:pathname path)\n      (gtirb::write-proto (read-proto 'proto:ir *proto-path*) path)\n      (is (probe-file path)))))\n\n(deftest idempotent-read-write ()\n  (with-fixture hello\n    (with-temporary-file (:pathname path)\n      (gtirb::write-proto (read-proto 'proto:ir *proto-path*) path)\n      ;; Protobuf provides multiple options for serializing repeated\n      ;; enums, so this check can fail even with valid serialization.\n      #+inhibited\n      (is (equalp (md5sum-file *proto-path*)\n                  (md5sum-file path))))))\n\n(deftest read-gtirb-from-streams-and-files ()\n  (with-fixture hello\n    (is (typep (read-gtirb *proto-path*) 'gtirb))\n    (is (typep (read-gtirb (namestring *proto-path*)) 'gtirb))\n    (is (typep (with-open-file (input *proto-path*) (read-gtirb input))\n               'gtirb))))\n\n(deftest idempotent-read-write-w-class ()\n  (nest\n   (with-fixture hello)\n   (with-temporary-file (:pathname path))\n   (let ((hello1 (read-gtirb *proto-path*)))\n     (write-gtirb hello1 path)\n     (is (is-equal-p hello1 (read-gtirb path))))))\n\n(deftest idempotent-aux-data-type ()\n  (with-fixture hello\n    (let ((it (read-gtirb *proto-path*)))\n      (is (tree-equal\n           (mapcar [#'pb:string-value #'proto:type-name #'gtirb::proto #'cdr]\n                   (aux-data (first (modules it))))\n           (mapcar [{format nil \"~/gtirb::aux-data-type-print/\"} #'aux-data-type #'cdr]\n                   (aux-data (first (modules it))))\n           :test #'string=)))))\n\n(deftest idempotent-aux-data-decode-encode ()\n  (let ((type1 '(:tuple :uuid :uint64-t :int64-t :uint64-t))\n        (type2 '(:sequence :uuid))\n        (type3 '(:sequence (:variant :uuid :string)))\n        (data '(1 2 3 4))\n        (data2 '((0 . 1) (1 . \"foo\") (0 . 3) (1 . \"bar\"))))\n    (is (equalp\n         (gtirb::aux-data-decode type1 (gtirb::aux-data-encode type1 data))\n         data))\n    (is (equalp\n         (gtirb::aux-data-decode type2 (gtirb::aux-data-encode type2 data))\n         data))\n    (is (equalp\n         (gtirb::aux-data-decode type3 (gtirb::aux-data-encode type3 data2))\n         data2)))\n  (with-fixture hello\n    (let ((hello (read-gtirb *proto-path*)))\n      (mapc (lambda (pair)\n              (destructuring-bind (name . aux-data) pair\n                (let* ((orig (proto:data (gtirb::proto aux-data)))\n                       (type (aux-data-type aux-data))\n                       (new (gtirb::aux-data-encode\n                             type (aux-data-data aux-data))))\n                  (is (equalp (gtirb::aux-data-decode type new)\n                              (gtirb::aux-data-decode type orig))\n                      \"~s with type ~a encodes/decodes is not idempotent~%~s\"\n                      name (aux-data-type aux-data)\n                      (list (gtirb::aux-data-decode type orig)\n                            (gtirb::aux-data-decode type new))))))\n            (aux-data (first (modules hello)))))))\n\n(deftest test-check-magic-header ()\n  (is (signals gtirb-magic-error\n        (check-magic-header #())))\n  (is (signals gtirb-magic-error\n        (check-magic-header #(0 0 0 0 0 0 0 0))))\n  (is (signals gtirb-magic-error\n        (check-magic-header #(71 84 73 82 66 0 0 0))))\n  (is (null (check-magic-header (vector 71 84 73 82 66 0 0 protobuf-version)))))\n\n(deftest test-write-magic-header ()\n  (with-output-to-sequence (out)\n    (write-magic-header out)\n    (is (equalp (get-output-stream-sequence out)\n                (vector 71 84 73 82 66 0 0 protobuf-version)))))\n\n(deftest update-proto-to-disk-and-back ()\n  (nest\n   (with-fixture hello)\n   (with-temporary-file (:pathname path))\n   (let ((test-string \"this is a test\")\n         (hello (read-gtirb *proto-path*))\n         (aux (make-instance 'aux-data)))\n     (setf (aux-data-type aux) :string)\n     (setf (aux-data-data aux) test-string)\n     (push (cons \"test\" aux) (aux-data (first (modules hello))))\n     (write-gtirb hello path)\n     (let* ((next (read-gtirb path))\n            (proto (gtirb::proto (first (modules next)))))\n       ;; Test for non-empty protobuf elements.\n       (is (not (zerop (length (proto:byte-intervals (aref (proto:sections proto) 0))))))\n       ;; Test for the aux-data table created earlier in the test.\n       (is (string= (aux-data-data\n                     (cdr (assoc \"test\" (aux-data (first (modules next)))\n                                 :test #'string=)))\n                    test-string))))))\n\n(deftest create-module-with-a-name ()\n  (is (string= \"foo\"\n               (nest\n                (pb:string-value)\n                (proto:name)\n                (gtirb::proto)\n                (make-instance 'module :name \"foo\" :allow-other-keys t)))))\n\n;; FIXME: create-module-without-a-name should verify that the appropriate\n;; warning is emitted, but for some reason the warning doesn't percolate up\n;; to the point where the signals testing macro is able to catch it.\n(deftest create-module-without-a-name ()\n  (is (emptyp (nest\n               (pb:string-value)\n               (proto:name)\n               (gtirb::proto)\n               (make-instance 'module)))))\n\n(deftest entry-points-on-modules ()\n  (with-fixture hello\n    (let* ((hello (read-gtirb *proto-path*))\n           (module (first (modules hello)))\n           (code-block (nest (first)\n                             (remove-if-not {typep _ 'code-block})\n                             (blocks hello))))\n      ;; Entry-point is read as a code block.\n      (is (typep (entry-point module) 'code-block))\n      ;; Newly saved entry-point has the UUID of the code block.\n      (setf (entry-point module) code-block)\n      (is (= (uuid code-block)\n             (uuid-to-integer (proto:entry-point (gtirb::proto module))))))))\n\n(deftest back-pointers-work ()\n  (with-fixture hello\n    (let ((hello (read-gtirb *proto-path*)))\n      ;; Modules point to IR.\n      (is (every [{eql hello} #'gtirb] (modules hello)))\n      ;; Sections point to modules.\n      (mapc (lambda (module)\n              (is (every [{eql module} #'module] (sections module)))\n              ;; Byte-intervals point to sections.\n              (mapc (lambda (section)\n                      (is (every [{eql section} #'section]\n                                 (byte-intervals section)))\n                      ;; Blocks point to byte-intervals.\n                      (mapc (lambda (byte-interval)\n                              (is (every [{eql byte-interval} #'byte-interval]\n                                         (blocks byte-interval))))\n                            (byte-intervals section)))\n                    (sections module)))\n            (modules hello)))))\n\n(deftest access-block-bytes ()\n  (with-fixture hello\n    (is (every [#'not #'null #'bytes]\n               (blocks (read-gtirb *proto-path*))))))\n\n(deftest find-every-block-in-the-module ()\n  (nest (with-fixture hello)\n        (let ((it (read-gtirb *proto-path*))))\n        (is)\n        (every {get-uuid _ it})\n        (mapcar #'uuid)\n        (blocks it)))\n\n(deftest get-blocks-and-bytes-from-cfg-nodes ()\n  (nest (with-fixture hello)\n        (let ((it (read-gtirb *proto-path*))))\n        (is)\n        (every {get-uuid _ it})\n        (nodes)\n        (cfg it)))\n\n(deftest shift-subseq-adds-and-removes-as-expected ()\n  (let ((it #(1 2 3 4 5)))\n    (setf (gtirb::shift-subseq it 2 3) #(9 9 9 9))\n    (is (equalp it #(1 2 9 9 9 9 4 5))))\n  (let ((it #(1 2 3 4 5)))\n    (setf (gtirb::shift-subseq it 2 3) #())\n    (is (equalp it #(1 2 4 5)))))\n\n(deftest set-block-bytes-to-the-same-size ()\n  (with-fixture hello\n    (let* ((it (read-gtirb *proto-path*))\n           (original-byte-intervals (nest (mappend #'byte-intervals)\n                                          (mappend #'sections)\n                                          (modules it)))\n           (original-byte-interval-md5sum\n            (nest (md5sum-sequence)\n                  (force-byte-array)\n                  (apply #'concatenate 'vector)\n                  (mapcar #'contents original-byte-intervals))))\n      (let ((target (first (mappend #'blocks original-byte-intervals))))\n        (setf (bytes target)\n              (make-array (length (bytes target)) :initial-element 9))\n        (is (= (length original-byte-intervals) ; No new byte intervals.\n               (length (nest (mappend #'byte-intervals)\n                             (mappend #'sections)\n                             (modules it)))))\n        (is (not (equalp original-byte-interval-md5sum ; New contents.\n                         (nest (md5sum-sequence)\n                               (force-byte-array)\n                               (apply #'concatenate 'vector)\n                               (mapcar #'contents)\n                               (mappend #'byte-intervals)\n                               (mappend #'sections)\n                               (modules it)))))))))\n\n(deftest set-block-bytes-to-the-different-size ()\n  (with-fixture hello\n    (let* ((it (read-gtirb *proto-path*))\n           (original-byte-intervals (nest (mappend #'byte-intervals)\n                                          (mappend #'sections)\n                                          (modules it)))\n           (target (first (mappend #'blocks original-byte-intervals)))\n           (original-bi-size (size (byte-interval target)))\n           (original-bi-bytes (bytes (byte-interval target)))\n           (original-size (length (bytes target)))\n           (rest-block-bytes\n            (cdr (mapcar #'bytes (blocks (byte-interval target))))))\n      (setf (bytes target) (make-array (* 2 original-size) :initial-element 9))\n      ;; First block bytes are updated.\n      (is (equalp (bytes (first (mappend #'blocks original-byte-intervals)))\n                  (make-array (* 2 original-size) :initial-element 9)))\n      ;; Block size is updated.\n      (is (equalp (size target) (* 2 original-size)))\n      ;; Byte-interval size is updated.\n      (is (equalp (size (byte-interval target))\n                  (+ original-bi-size original-size)))\n      ;; Remainder of the byte-interval's bytes are the same.\n      (is (equalp (subseq (bytes (byte-interval target)) (* 2 original-size))\n                  (subseq original-bi-bytes original-size)))\n      ;; Remaining blocks bytes are the same.\n      (is (every #'equalp\n                 rest-block-bytes\n                 (cdr (mapcar #'bytes (blocks (byte-interval target)))))))))\n\n(deftest address-range-block-lookup ()\n  (with-fixture hello\n    (let* ((it (read-gtirb *proto-path*))\n           (a-block (first (blocks it))))\n      (is (= 2 (length (address-range a-block))))\n      (is (member a-block (nest (mappend #'blocks)\n                                (on-address it)\n                                (first)\n                                (address-range a-block))))\n      (is (member a-block (nest (mappend #'blocks)\n                                (at-address it)\n                                (first)\n                                (address-range a-block))))\n      (is (not (member a-block (nest (mappend #'blocks)\n                                     (at-address it)\n                                     (second)\n                                     (address-range a-block))))))))\n\n(deftest symbolic-expressions-pushed-back ()\n  (with-fixture hello\n    ;; Collect a byte-interval with offset symbolic expressions.\n    (let* ((bi (nest (find-if [{some [#'not #'zerop #'car]}\n                               #'hash-table-alist #'symbolic-expressions])\n                     (cdr) (mappend #'byte-intervals)\n                     (sections) (first) (modules)\n                     (read-gtirb *proto-path*)))\n           (original-length (length (bytes bi)))\n           (original-offsets (hash-table-keys (symbolic-expressions bi)))\n           (largest-offset (extremum original-offsets #'>))\n           (smallest-offset (extremum original-offsets #'<)))\n      ;; Add bytes after the last symbol.\n      (setf (bytes bi largest-offset largest-offset)\n            (make-array 2 :initial-element 9))\n      ;; Ensure bytes have been altered.\n      (is (> (length (bytes bi)) original-length))\n      ;; Ensure symbolic expressions before last have not moved.\n      (is (set-equal (remove (+ largest-offset 2)\n                             (hash-table-keys (symbolic-expressions bi)))\n                     (remove largest-offset original-offsets)))\n      ;; Remove those added bytes\n      (setf (bytes bi largest-offset (+ largest-offset 2)) #())\n      ;; Add bytes at the beginning.\n      (setf (bytes bi 0 0) (make-array 1 :initial-element 9))\n      ;; Ensure symbolic expressions have actually been pushed back.\n      (is (set-equal (mapcar #'1+ original-offsets)\n                     (hash-table-keys (symbolic-expressions bi))))\n      ;; Drop bytes at the beginning.\n      (setf (bytes bi 0 (1+ smallest-offset)) #())\n      ;; Ensure this symbolic expression now starts at the beginning.\n      (is (zerop (extremum (hash-table-keys (symbolic-expressions bi))\n                           #'<))))))\n\n(defvar *listing-comments*)\n(defun get-listing-comments (it)\n  (when-let ((table (assoc \"comments\" (gtirb::aux-data-w-offsets (ir it))\n                           :test #'equalp)))\n    (hash-table-alist (aux-data-data (cdr table)))))\n(defmethod listing :around (object &key stream comments)\n  (declare (ignorable stream comments))\n  (let ((*listing-comments* (if (boundp '*listing-comments*)\n                                *listing-comments*\n                                (get-listing-comments object))))\n    (call-next-method)))\n(defgeneric listing (OBJECT &key stream comments)\n  (:documentation \"Print a listing of OBJECT.\")\n  (:method ((self gtirb) &key (stream t) comments)\n    (format stream \"~&IR~%\")\n    (mapc {listing _ :stream stream :comments comments} (modules self)))\n  (:method ((self module) &key (stream t) comments)\n    (format stream \"~&Module: ~S~%\" (name self))\n    (mapc {listing _ :stream stream :comments comments} (sections self)))\n  (:method ((self section) &key (stream t) comments)\n    (format stream \"~&Section: ~S\" (name self))\n    (mapc {listing _ :stream stream :comments comments} (byte-intervals self)))\n  (:method ((self byte-interval) &key (stream t) comments)\n    (format stream \"~:[ (no address)~; at ~a~]~%\" (addressp self) (address self))\n    (mapc {listing _ :stream stream :comments comments} (blocks self)))\n  (:method ((self gtirb-byte-block) &key (stream t) comments)\n    (let ((bytes (bytes self))\n          (comments (when comments\n                      (remove-if-not [{= (uuid self)} #'caar] *listing-comments*))))\n      (dotimes (step (size self))\n        (format stream (if (zerop step) \"~&>\" \" \"))\n        (if-let ((comment (and comments (find-if [{= step} #'cadar] comments))))\n          (format stream \"~4X ; ~A~%\" (aref bytes step) (cdr comment))\n          (format stream \"~4X\" (aref bytes step)))\n        (when (= 7 (mod step 8)) (format stream \"~&\"))))))\n\n(defun block-comments (data-block it)\n  (sort (nest (remove-if-not [{= (uuid data-block)} #'caar])\n              (hash-table-alist)\n              (aux-data-data) (cdr)\n              (assoc \"comments\" (gtirb::aux-data-w-offsets (ir it))\n                     :test #'equalp))\n        #'< :key [#'second #'car]))\n\n(deftest offsets-pushed-back ()\n  (nest (let ((gtirb::*update-aux-data-offsets* t)))\n        (with-fixture hello)\n        (let* ((it (read-gtirb *proto-path*))\n               (text (find-if [{string= \".text\"} #'name]\n                              (sections (first (modules it)))))\n               (commented-block (find-if {block-comments _ it} (blocks text)))\n               (comment (first (block-comments commented-block it)))\n               (starting-offset (cadar comment)))\n          (is (gtirb::get-aux-data-w-offsets it)\n              \"We're finding aux-data tables with offsets. ~\n             Should be at least comments and cfiDirectives.\")\n          (is (gtirb::aux-data-w-offsets it)\n              \"The `aux-data-w-offsets' was populated.\")\n          #+nil (listing commented-block :comments t)\n          (setf (bytes commented-block 0 0) #(0 0 0 0))\n          #+nil (listing commented-block :comments t)\n          (is (= (+ 4 starting-offset)\n                 (cadar (first (block-comments commented-block it))))))))\n\n(deftest block-symbolic-expressions ()\n  (with-fixture hello\n    (is (nest (mappend [#'hash-table-values #'symbolic-expressions])\n              (mappend #'blocks) (mappend #'byte-intervals)\n              (sections) (first) (modules)\n              (read-gtirb *proto-path*)))))\n\n(deftest symbolic-expressions-maintained ()\n  (nest\n   (with-fixture hello)\n   (mapc (lambda (db)\n           (let ((o-offset (offset db))\n                 (o-bi-size (size (byte-interval db)))\n                 (o-db-size (size db))\n                 (o-bi-se-size (hash-table-size\n                                (symbolic-expressions (byte-interval db))))\n                 (o-se-size (hash-table-size\n                             (symbolic-expressions db))))\n             (setf (bytes db 0 0) #(#x90 #x90 #x90 #x90))\n             (is (= o-offset (offset db)))\n             (is (= (+ 4 o-bi-size) (size (byte-interval db))))\n             (is (= (+ 4 o-db-size) (size db)))\n             (is (= o-bi-se-size\n                    (hash-table-size\n                     (symbolic-expressions (byte-interval db)))))\n             (is (= o-se-size\n                    (hash-table-size\n                     (symbolic-expressions db)))))))\n   (blocks (read-gtirb *proto-path*))))\n\n(deftest payload-can-be-read-and-set ()\n  (with-fixture hello\n    (let* ((it (read-gtirb *proto-path*))\n           (symbols (mappend #'symbols (modules it)))\n           (referent-symbol\n            (find-if [#'proto:has-referent-uuid #'gtirb::proto] symbols)))\n      ;; Reading gives the right type of payload.\n      (is (subtypep (type-of (payload referent-symbol)) 'gtirb::proto-backed))\n      ;; Setting a payload has the right effect.\n      (setf (payload referent-symbol) 42) ; Referent to value.\n      (is (subtypep (type-of (payload referent-symbol)) 'number))\n      (is (not (proto:has-referent-uuid (gtirb::proto referent-symbol)))))))\n\n(deftest can-create-without-parents ()\n  (is (typep (make-instance 'module) 'module))\n  (is (typep (make-instance 'section) 'section))\n  (is (typep (make-instance 'byte-interval) 'byte-interval)))\n\n(deftest direct-ir-access ()\n  (with-fixture hello\n    (let* ((it (read-gtirb *proto-path*)))\n      (is (typep (ir (setf it (first (modules it)))) 'gtirb))\n      (is (typep (ir (setf it (first (sections it)))) 'gtirb))\n      (is (typep (ir (setf it (first (byte-intervals it)))) 'gtirb))\n      (is (typep (ir (setf it (first (blocks it)))) 'gtirb)))))\n\n(deftest every-symbolic-expression-has-symbols ()\n  (flet ((every-symbolic-expression-has-symbols-proto (path)\n           (every (lambda (se)\n                    (cond\n                      ((proto:has-addr-const se)\n                       (proto:symbol-uuid (proto:addr-const se)))\n                      ((proto:has-addr-addr se)\n                       (proto:symbol1-uuid (proto:addr-addr se)))))\n                  (nest\n                   (mapcar #'proto:value)\n                   (mappend [{coerce _ 'list} #'proto:symbolic-expressions])\n                   (mappend [{coerce _ 'list} #'proto:byte-intervals])\n                   (coerce (proto:sections\n                            (aref (proto:modules\n                                   (read-proto 'proto:ir path)) 0))\n                           'list))))\n         (every-symbolic-expression-has-symbols-gtirb (path)\n           (nest (every #'symbols)\n                 (mappend [#'hash-table-values #'symbolic-expressions])\n                 (mappend #'byte-intervals)\n                 (mappend #'sections)\n                 (modules (read-gtirb path)))))\n    (with-fixture hello\n      ;; First confirm for the protobuf\n      (is (every-symbolic-expression-has-symbols-proto *proto-path*))\n      ;; Second confirm for the GTIRB representation.\n      (is (every-symbolic-expression-has-symbols-gtirb *proto-path*))\n      ;; Then re-confirm both for a rewritten protobuf file.\n      (uiop:with-temporary-file (:pathname temporary-file)\n        (write-gtirb (read-gtirb *proto-path*) temporary-file)\n        (is (every-symbolic-expression-has-symbols-proto temporary-file))\n        (is (every-symbolic-expression-has-symbols-gtirb temporary-file))))))\n\n#+ignore-expected-failure\n(deftest every-block-is-found-at-its-address ()\n  (with-fixture hello\n    (let ((it (read-gtirb *proto-path*)))\n      (nest (is)\n            (every «member #'identity [{at-address it} #'address]»)\n            (mappend #'blocks)\n            (mappend #'byte-intervals)\n            (mappend #'sections)\n            (modules it)))))\n\n(deftest truncating-size-on-byte-interval-errors-and-truncates ()\n  (with-fixture hello\n    (let ((byte-intervals (nest (mappend #'byte-intervals)\n                                (mappend #'sections)\n                                (modules)\n                                (read-gtirb *proto-path*))))\n      ;; Truncation signals an error.\n      (signals ir\n        (setf (size (first byte-intervals))\n              (1- (length (contents (first byte-intervals))))))\n      ;; Truncate restart works.\n      (let* ((bi (second byte-intervals))\n             (original-length (length (contents bi))))\n        (handler-bind\n            ((ir\n              (lambda (e)\n                (if (find-restart 'truncate-contents)\n                    (invoke-restart 'truncate-contents)\n                    (error e)))))\n          (setf (size bi) (1- original-length)))\n        (is (= original-length\n               (+ 1 (size bi))\n               (+ 1 (length (contents bi))))))\n      ;; Ignore restart works.\n      (let* ((bi (third byte-intervals))\n             (original-length (length (contents bi))))\n        (handler-bind\n            ((ir\n              (lambda (e)\n                (if (find-restart 'ignore)\n                    (invoke-restart 'ignore)\n                    (error e)))))\n          (setf (size bi) (1- original-length)))\n        (is (= original-length (length (contents bi))))\n        (is (> original-length (size bi)))))))\n\n\f\n;;;; Dot test suite\n(deftest write-dot-to-file ()\n  (with-fixture hello\n    (with-temporary-file (:pathname path)\n      (to-dot-file (read-gtirb *proto-path*) path))))\n"
  },
  {
    "path": "cl/update.lisp",
    "content": "(defpackage :gtirb/update\n  (:use :common-lisp\n        :alexandria\n        :gtirb/utility\n        :named-readtables\n        :curry-compose-reader-macros\n        :command-line-arguments)\n  (:import-from :serapeum :take-while)\n  (:import-from :gtirb.proto)\n  (:import-from :trivial-package-local-nicknames :add-package-local-nickname)\n  (:import-from :proto-v0)\n  (:import-from :uiop :nest)\n  (:import-from :uiop/image :quit)\n  (:import-from :gtirb\n                :aux-data :aux-data-type :aux-data-data\n                :+module-file-format-map+)\n  (:export :update :upgrade :read-proto :write-proto))\n(in-package :gtirb/update)\n(in-readtable :curry-compose-reader-macros)\n\n(eval-when (:compile-toplevel :load-toplevel :execute)\n  (add-package-local-nickname :proto :gtirb.proto)\n  (defparameter +udpate-args+\n    '(((\"help\" #\\h #\\?) :type boolean :optional t\n       :documentation \"display help output\"))))\n\n(defun module-bytes-subseq (module start end &aux (results #()))\n  (let ((regions (proto-v0:regions (proto-v0:byte-map\n                                    (proto-v0:image-byte-map module)))))\n    (force-byte-array\n     (dotimes (n (length regions) results)\n       (let* ((region (aref regions n))\n              (address (proto-v0:address region))\n              (size (length (proto-v0:data region))))\n         (cond\n           ((and (<= address start) (< start (+ address size)))\n            (setf results (concatenate 'vector\n                                       results\n                                       (subseq (proto-v0:data region)\n                                               (- start address)\n                                               (min size (- end address)))))\n            (setf start (min end (+ address size))))\n           ((= start end) (return results))))))))\n\n(defun byte-interval (module section\n                      &aux (new (make-instance 'proto:byte-interval)))\n  (let ((address (proto-v0:address section))\n        (size (proto-v0:size section)))\n    (setf (proto:uuid new) (new-uuid)\n          (proto:address new) address\n          (proto:has-address new) (proto-v0:has-address section)\n          (proto:size new) size\n          (proto:contents new)\n          (module-bytes-subseq module address (+ address size))\n          (proto:symbolic-expressions new)\n          (map 'vector {upgrade _ :base address}\n               (remove-if-not [«and {<= address} {>= (+ address size)}» #'proto-v0:key]\n                              (proto-v0:symbolic-operands module)))\n          (proto:blocks new)\n          (map 'vector (lambda (block)\n                         (etypecase block\n                           (proto-v0:block\n                               (let ((it (make-instance 'proto:block)))\n                                 (setf (proto:code it)\n                                       (upgrade block)\n                                       (proto:offset it)\n                                       (- (proto-v0:address block) address))\n                                 it))\n                           (proto-v0:data-object\n                            (let ((it (make-instance 'proto:block)))\n                              (setf (proto:data it)\n                                    (upgrade block :base address)\n                                    (proto:offset it)\n                                    (- (proto-v0:address block) address))\n                              it))))\n               (remove-if-not\n                (lambda (block)\n                  (let ((addr (proto-v0:address block)))\n                    (and (<= address addr)\n                         (< addr (+ address size)))))\n                (concatenate 'vector\n                             (proto-v0:blocks module)\n                             (proto-v0:data module))))))\n  (coerce (list new) 'vector))\n\n(defun entry-point (module)\n  (when-let ((address (proto-v0:entry-point-address\n                       (proto-v0:image-byte-map module))))\n    (if-let ((gtirb-block\n              (find-if\n               «and [{< address} «+ #'proto-v0:address #'proto-v0:size»]\n                    [{>= address} #'proto-v0:address]»\n               (proto-v0:blocks module))))\n      (proto-v0:uuid gtirb-block)\n      (if (zerop address)\n          (warn \"Zero address found in module ~S, assuming not an entry point.\"\n                (pb:string-value (proto-v0:name module)))\n          (error \"No block found holding module ~S entry point ~a.\"\n                 (pb:string-value (proto-v0:name module))\n                 address)))))\n\n(defmacro transfer-fields (new old &rest fields)\n  `(progn\n     ,@(mapcar (lambda (field)\n                 `(setf (,(intern (symbol-name field) 'proto) ,new)\n                        (upgrade (,(intern (symbol-name field) 'proto-v0) ,old))))\n               fields)))\n\n#+debug\n(defun serial (it)\n  \"Useful to ensure yourself of what protobuf serialization is producing.\"\n  (let* ((size (pb:octet-size it))\n         (buffer (make-array size :element-type '(unsigned-byte 8))))\n    (pb:serialize it buffer 0 size)\n    buffer))\n\n#+debug\n(defun deserial (class bytes &aux (it (make-instance class)))\n  \"Useful to ensure yourself of what protobuf deserialization is producing.\"\n  (pb:merge-from-array it bytes 0 (length bytes))\n  it)\n\n(defun combine-cfgs (cfgs)\n  (let ((it (make-instance 'proto:cfg)))\n    (setf (proto:edges it)\n          (coerce (mappend [{coerce _ 'list} #'proto:edges] cfgs) 'vector))\n    (setf (proto:vertices it)\n          (coerce (mappend [{coerce _ 'list} #'proto:vertices] cfgs) 'vector))\n    it))\n\n(define-constant +symbol-storage-kind+\n    '((#.proto-v0:+storage-kind-storage-undefined+ . :undefined)\n      (#.proto-v0:+storage-kind-storage-normal+ . :normal)\n      (#.proto-v0:+storage-kind-storage-static+ . :static)\n      (#.proto-v0:+storage-kind-storage-extern+ . :extern)\n      (#.proto-v0:+storage-kind-storage-local+ . :local))\n  :test #'equal)\n\n(defvar *code-block-uuids* (make-hash-table))\n(defvar *data-block-uuids* (make-hash-table))\n\n(defun storage-kind (symbol)\n  (cdr (assoc (proto-v0:storage-kind symbol) +symbol-storage-kind+)))\n\n(defun elf-symbol-info (symbol)\n  \"Return an elfSymbolInfo entry for SYMBOL using its `proto-v0:storage-kind'.\"\n  (list\n   0\n   ;; Point to data \"OBJ,\" if it points to a code \"FUNC,\" else \"NOTYPE.\"\n   (cond\n     ((gethash (proto-v0:uuid symbol) *data-block-uuids*) \"OBJ\")\n     ((gethash (proto-v0:uuid symbol) *code-block-uuids*) \"FUNC\")\n     (t \"NOTYPE\"))\n   (ecase (storage-kind symbol)\n     ((:normal :static) \"GLOBAL\")\n     (:local \"LOCAL\"))\n   (ecase (storage-kind symbol)\n     (:normal \"DEFAULT\")\n     ((:local :static) \"HIDDEN\"))\n   0))\n\n(defun update-padding-table (data offset-bases)\n  \"Convert DATA which is keyed by addresses to be keyed by offset.\nUse OFFSET-BASES, an alist of base address and byte-interval, to do\nthis conversion.\"\n  (let* ((it (make-instance 'aux-data :proto data))\n         (data (aux-data-data it)))\n    (nest (setf (aux-data-type it) '(:mapping :offset :uint64-t)\n                (aux-data-data it))\n          (alist-hash-table)\n          (mapcar (lambda (pair)\n                    (destructuring-bind (addr . value) pair\n                      (let ((base (nest (lastcar)\n                                        (take-while [{> addr} #'car])\n                                        offset-bases)))\n                        (destructuring-bind (base . id) base\n                          (cons\n                           (let ((it (make-instance 'proto:offset)))\n                             (setf (proto:element-id it) id)\n                             (setf (proto:displacement it) (- addr base))\n                             it)\n                           value))))))\n          (hash-table-alist)\n          data)\n    (gtirb::proto it)))\n\n(defun offset-bases (new-sections)\n  (nest (apply #'append)\n        (map 'list (lambda (section)\n                     (map 'list (lambda (bi)\n                                  (assert (proto:has-address bi))\n                                  (cons (proto:address bi)\n                                        (proto:uuid bi)))\n                          (proto:byte-intervals section))))\n        new-sections))\n\n(defgeneric upgrade (object &key &allow-other-keys)\n  (:documentation \"Upgrade OBJECT to the next protobuf version.\")\n  (:method ((old t) &key &allow-other-keys) old)\n  (:method ((old array) &key  &allow-other-keys)\n    (if (every #'numberp old)\n        (force-byte-array old)\n        (map 'vector #'upgrade old)))\n  (:method ((old proto-v0:ir) &key &allow-other-keys\n            &aux (new (make-instance 'proto:ir)))\n    (setf (proto:uuid new) (proto-v0:uuid old)\n          (proto:version new) 1\n          (proto:aux-data new) (upgrade (proto-v0:aux-data-container old)\n                                        :new-class 'proto:ir-aux-data-entry)\n          (proto:modules new) (upgrade (proto-v0:modules old))\n          (proto:cfg new) (combine-cfgs (map 'list [#'upgrade #'proto-v0:cfg]\n                                             (proto-v0:modules old))))\n    new)\n  (:method ((old proto-v0:module) &key &allow-other-keys\n            &aux (new (make-instance 'proto:module)))\n    (transfer-fields new old\n                     uuid binary-path preferred-addr rebase-delta file-format\n                     name symbols proxies name)\n    (let ((new-sections (map 'vector {upgrade _ :module old}\n                             (proto-v0:sections old))))\n      (setf (proto:isa new) (proto-v0:isa-id old)\n            (proto:aux-data new)\n            (upgrade (proto-v0:aux-data-container old)\n                     :new-class 'proto:module-aux-data-entry\n                     :offset-bases (offset-bases new-sections))\n            (proto:sections new) new-sections))\n    (if-let ((entry-point (entry-point old)))\n      (setf (proto:entry-point new) entry-point))\n    ;; Add a symbolType AuxData table of type mapping<UUID, string> to\n    ;; track the storage kinds of all symbols.\n    (ecase (cdr (assoc (proto-v0:file-format old) +module-file-format-map+))\n      (:elf\n       (let ((ad (make-instance 'aux-data))\n             (ade (make-instance 'proto:module-aux-data-entry)))\n         (setf (aux-data-type ad)\n               '(:mapping :uuid\n                 (:tuple :uint64-t :string :string :string :uint64-t))\n               (aux-data-data ad)\n               (alist-hash-table\n                (map 'list «cons [#'uuid-to-integer #'proto-v0:uuid]\n                                 #'elf-symbol-info»\n                     (remove-if [{eql :extern} #'storage-kind]\n                                (proto-v0:symbols old)))))\n         (setf (proto:key ade) (pb:string-field \"elfSymbolInfo\")\n               (proto:value ade) (gtirb::proto ad))\n         (setf (proto:aux-data new)\n               (coerce (append (list ade) (coerce (proto:aux-data new) 'list))\n                       'vector))))\n      (:pe (flet ((symbols-to-aux-data (name symbols)\n                    (let ((ad (make-instance 'aux-data))\n                          (ade (make-instance 'proto:module-aux-data-entry)))\n                      (setf (aux-data-type ad) '(:set :uuid)\n                            (aux-data-data ad) symbols\n                            (proto:key ade) (pb:string-field name)\n                            (proto:value ade) (gtirb::proto ad))\n                      ade)))\n             (let ((in (symbols-to-aux-data\n                        \"peImportedSymbols\"\n                        (nest\n                         (mapcar [#'uuid-to-integer #'proto-v0:uuid])\n                         (remove-if-not [{member _ '(:local :static)}\n                                         #'storage-kind])\n                         (proto-v0:symbols old))))\n                   (out (symbols-to-aux-data\n                         \"peExportedSymbols\"\n                         (nest\n                          (mapcar [#'uuid-to-integer #'proto-v0:uuid])\n                          (remove-if-not [{member _ '(:normal :extern)}\n                                          #'storage-kind])\n                          (proto-v0:symbols old)))))\n               (setf (proto:aux-data new)\n                     (coerce (append (list in out)\n                                     (coerce (proto:aux-data new) 'list))\n                             'vector))))))\n    new)\n  (:method ((old proto-v0:aux-data-container) &key new-class offset-bases\n                                                &allow-other-keys)\n    (map 'vector (lambda (entry)\n                   (let ((it (make-instance new-class)))\n                     (let ((new-value (upgrade (proto-v0:value entry))))\n                       (when (string= \"padding\"\n                                      (pb:string-value (proto-v0:key entry)))\n                         (setf new-value (update-padding-table\n                                          new-value offset-bases)))\n                       (setf (proto:key it) (proto-v0:key entry)\n                             (proto:value it) new-value))\n                     it))\n         (proto-v0:aux-data old)))\n  (:method ((old proto-v0:aux-data) &key &allow-other-keys\n            &aux (new (make-instance 'proto:aux-data)))\n    (transfer-fields new old type-name data)\n    new)\n  (:method ((old proto-v0:section) &key module &allow-other-keys\n            &aux (new (make-instance 'proto:section)))\n    (transfer-fields new old uuid name)\n    (setf (proto:byte-intervals new) (byte-interval module old))\n    new)\n  (:method ((old proto-v0:edge-label) &key &allow-other-keys\n            &aux (new (make-instance 'proto:edge-label)))\n    (transfer-fields new old conditional direct type)\n    new)\n  (:method ((old proto-v0:edge) &key &allow-other-keys\n            &aux (new (make-instance 'proto:edge)))\n    (transfer-fields new old source-uuid target-uuid label)\n    new)\n  (:method ((old proto-v0:cfg) &key &allow-other-keys\n            &aux (new (make-instance 'proto:cfg)))\n    (transfer-fields new old vertices edges)\n    new)\n  (:method ((old proto-v0:module-symbolic-operands-entry)\n            &key base &allow-other-keys\n            &aux (new (make-instance\n                          'proto:byte-interval-symbolic-expressions-entry)))\n    (setf (proto:key new) (- (proto-v0:key old) base)\n          (proto:value new) (upgrade (proto-v0:value old)))\n    new)\n  (:method ((old proto-v0:symbol) &key &allow-other-keys\n            &aux (new (make-instance 'proto:symbol)))\n    (transfer-fields new old uuid name)\n    (cond                ; Variant \"oneof\" 'value' or 'referent_uuid'.\n      ((proto-v0:has-value old)\n       (setf (proto:value new) (proto-v0:value old)))\n      ((proto-v0:has-referent-uuid old)\n       (setf (proto:referent-uuid new) (upgrade (proto-v0:referent-uuid old))\n             ;; This field was added after GTIRB-V.0.\n             (proto:at-end new) nil)))\n    new)\n  (:method ((old proto-v0:symbolic-expression) &key &allow-other-keys\n            &aux (new (make-instance 'proto:symbolic-expression)))\n    (cond                               ; Variant \"oneof\" field.\n      ((proto-v0:has-addr-const old)\n       (setf (proto:addr-const new) (upgrade (proto-v0:addr-const old))))\n      ((proto-v0:has-addr-addr old)\n       (setf (proto:addr-addr new) (upgrade (proto-v0:addr-addr old))))\n      (t (warn \"Symbolic expressions ~s has no value.\" old)))\n    #+debug\n    (progn     ; Potentially useful debug pattern to inspect protobuf.\n      (format t \"~%~%~%OLD:~S~%\" (serial old))\n      (describe old)\n      (format t \"~%NEW:~S~%\" (serial new))\n      (describe new))\n    new)\n  (:method ((old proto-v0:sym-addr-const) &key &allow-other-keys\n            &aux (new (make-instance 'proto:sym-addr-const)))\n    (transfer-fields new old symbol-uuid)\n    new)\n  (:method ((old proto-v0:sym-addr-addr) &key &allow-other-keys\n            &aux (new (make-instance 'proto:sym-addr-addr)))\n    (transfer-fields new old scale offset symbol1-uuid symbol2-uuid)\n    new)\n  (:method ((old proto-v0:block) &key &allow-other-keys\n            &aux (new (make-instance 'proto:code-block)))\n    (setf (gethash (proto-v0:uuid old) *code-block-uuids*) t)\n    (transfer-fields new old uuid size decode-mode)\n    new)\n  (:method ((old proto-v0:data-object) &key &allow-other-keys\n            &aux (new (make-instance 'proto:data-block)))\n    (setf (gethash (proto-v0:uuid old) *data-block-uuids*) t)\n    (transfer-fields new old uuid size)\n    new))\n\n(define-command update (input-file output-file &spec +udpate-args+)\n  \"Update GTIRB protobuf from INPUT-FILE to OUTPUT-FILE.\" \"\"\n  (when help (show-help-for-update) (quit))\n  (setf *random-state* (make-random-state t))\n  (write-proto (upgrade (read-proto 'proto-v0:ir input-file)) output-file))\n"
  },
  {
    "path": "cl/utility.lisp",
    "content": "(defpackage :gtirb/utility\n  (:use :common-lisp\n        :gtirb/version)\n  (:import-from :cl-intbytes\n                :int->octets\n                :octets->int)\n  (:import-from :alexandria\n                :define-constant\n                :read-stream-content-into-byte-vector\n                :read-file-into-byte-vector\n                :starts-with-subseq)\n  (:import-from :uiop :nest)\n  (:import-from :uiop/stream :file-stream-p)\n  (:export :read-proto\n           :write-proto\n           :gtirb-magic-error\n           :new-uuid\n           :force-byte-array\n           :uuid-to-integer\n           :integer-to-uuid))\n(in-package :gtirb/utility)\n(declaim (optimize (speed 3) (safety 0) (debug 0)))\n\n(define-constant gtirb-magic-octets #(71 84 73 82 66) ;; \"GTIRB\"\n  :test #'equalp\n  :documentation \"GTIRB file magic bytes at beginning of magic header.\")\n\n(define-constant gtirb-magic-length 8\n  :test #'equal\n  :documentation \"Number of bytes in the GTIRB file magic header.\")\n\n(define-condition gtirb-magic-error (error)\n  ((message :initarg :message :initform nil :reader message))\n  (:report (lambda (condition stream)\n             (format stream \"~S\" (message condition))))\n  (:documentation \"Condition raised if GTIRB header is invalid.\"))\n\n(defgeneric read-proto (class source)\n  (:documentation \"Read protobuf object of class CLASS from SOURCE.\")\n  (:method :before\n    (class (path pathname))\n    (declare (ignorable class))\n    (assert (probe-file path) (path)\n            \"Can't read Protobuf from ~s, because the file doesn't exist.\"\n            path))\n  (:method (class (path string)) (read-proto class (pathname path)))\n  (:method (class (path pathname))\n    (with-open-file (input path :direction :input :element-type 'unsigned-byte)\n      (read-proto class input)))\n  (:method (class (input stream))\n    (read-proto class (if (file-stream-p input)\n                          (read-file-into-byte-vector input)\n                          (read-stream-content-into-byte-vector input))))\n  (:method (class (buffer array) &aux (gtirb (make-instance class)))\n    (check-magic-header buffer)\n    (pb:merge-from-array gtirb buffer gtirb-magic-length (length buffer))\n    gtirb))\n\n(defun write-proto (object path)\n  \"Write OBJECT to PATH.\"\n  (let* ((size (pb:octet-size object))\n         (buffer (make-array size :element-type '(unsigned-byte 8))))\n    (pb:serialize object buffer 0 size)\n    (with-open-file (output path\n                            :direction :output :if-exists :supersede\n                            :element-type 'unsigned-byte)\n      (write-magic-header output)\n      (write-sequence buffer output)))\n  (values))\n\n(defun new-uuid (&aux (it (make-array 16 :element-type '(unsigned-byte 8))))\n  \"Return a new random UUID.\"\n  (dotimes (n 16 it) (setf (aref it n) (random 256))))\n\n(defun force-byte-array (array)\n  \"Force ARRAY into a byte array.\"\n  (declare (type (simple-array) array))\n  (make-array (length array) :element-type '(unsigned-byte 8)\n              :initial-contents array))\n\n(defun uuid-to-integer (uuid)\n  (declare (type (simple-array) uuid))\n  (if (zerop (length uuid))\n      (prog1 0 #+debug (warn \"Bad null UUID.\"))\n      (octets->int (force-byte-array uuid) 16)))\n\n(defun integer-to-uuid (number)\n  (int->octets number 16))\n\n(defun check-magic-header (bytes)\n  \"Check if the GTIRB magic header bytes are present in at the start of BYTES,\nthrowing a GTIRB-MAGIC-ERROR if the header is not present.\"\n  (when (or (< (length bytes) gtirb-magic-length)\n            (not (starts-with-subseq gtirb-magic-octets bytes)))\n    (error (make-condition 'gtirb-magic-error\n                           :message \"File missing GTIRB magic - not a GTIRB file?\")))\n  (when (not (equal protobuf-version (aref bytes (1- gtirb-magic-length))))\n    (error (nest (make-condition 'gtirb-magic-error :message)\n                 (format nil \"Attempt to decode IR of version ~d (expected version ~d)\"\n                         (aref bytes (1- gtirb-magic-length))\n                         protobuf-version)))))\n\n(defun write-magic-header (stream)\n  \"Write the GTIRB magic header bytes to STREAM.\"\n  (write-sequence gtirb-magic-octets stream)\n  (write-byte 0 stream)\n  (write-byte 0 stream)\n  (write-byte protobuf-version stream))\n"
  },
  {
    "path": "cl/validate.lisp",
    "content": "(defpackage :gtirb/validate\n  (:use :gt/full :gtirb :graph :command-line-arguments)\n  (:import-from :gtirb.proto)\n  (:shadowing-import-from :gt/full :size :copy)\n  (:shadowing-import-from :gtirb :symbol)\n  (:export :validate))\n(in-package :gtirb/validate)\n(in-readtable :curry-compose-reader-macros)\n(defmethod size ((gtirb-node gtirb-node)) (gtirb:size gtirb-node))\n(defmethod copy ((graph graph) &key &allow-other-keys) (graph:copy graph))\n\n\f\n;;;; Interface\n(defvar *requirements* nil\n  \"A-list of default requirements keyed by object type.\")\n\n(defvar *failed-checks*)\n\n(defgeneric validate (object &key requirements)\n  (:documentation \"Validate that OBJECT satisfies the requirements in .\")\n  (:method\n      ((object t) &key (requirements *requirements*) &aux (*failed-checks* nil))\n    (values (every {check object} (cdr (assoc (type-of object) requirements)))\n            *failed-checks*)))\n\n(defclass check ()\n  ((action :reader action :initarg :action\n           :type (or symbol function) :documentation \"Action to run the check.\")\n   (object :reader object :initarg :object\n           :type symbol :documentation \"Type of object the check applies to.\")\n   (name :reader name :initarg :name\n         :type string :documentation \"Name of the check.\"))\n  (:documentation \"Check objects hold validation checks for gtirb instances.\"))\n\n(defmethod initialize-instance :after\n    ((check check) &key (requirements *requirements*) &allow-other-keys)\n  (unless (assoc (object check) requirements)\n    (push (list (object check)) requirements))\n  (pushnew check (cdr (assoc (object check) requirements)) :key #'name))\n\n(defgeneric check (object requirement)\n  (:documentation \"Check that OBJECT satisfies REQUIREMENT.\")\n  (:method ((obj t) (requirement symbol)) (funcall requirement obj))\n  (:method ((obj t) (requirement function)) (funcall requirement obj))\n  (:method ((obj t) (requirement check)) (funcall (action requirement) obj)))\n\n(defmethod check :around ((object t) (requirement function))\n  (or (call-next-method) (push requirement *failed-checks*)))\n(defmethod check :around ((object t) (requirement check))\n  (or (call-next-method) (push (name requirement) *failed-checks*)))\n\n\f\n;;;; GTIRB Checks\n(defmacro define-check-generic (name (object) &body methods)\n  `(progn (defgeneric ,name (,object) ,@methods)\n          (make-instance 'check\n            :name ',name\n            :action ',name\n            :object ',(second (first (second (first methods)))))))\n\n(define-check-generic size-matches-contents (object)\n  (:method ((obj gtirb)) (every #'size-matches-contents (modules obj)))\n  (:method ((obj module)) (every #'size-matches-contents (sections obj)))\n  (:method ((obj section)) (every #'size-matches-contents (byte-intervals obj)))\n  (:method ((obj byte-interval)) (= (size obj) (length (contents obj)))))\n\n(flet ((nothing-overlaps- (things &aux (min 0))\n         (and (every (lambda (pair)\n                       (destructuring-bind (address . size) pair\n                         (prog1 (>= address min)\n                           (setf min (max min (+ address size))))))\n                     (sort (mapcar «cons #'address #'size» things) #'<\n                           :key #'car))\n              (every #'nothing-overlaps things))))\n  (define-check-generic nothing-overlaps (object)\n    (:method ((obj gtirb)) (every #'nothing-overlaps (modules obj)))\n    (:method ((obj module)) (nothing-overlaps- (sections obj)))\n    (:method ((obj section)) (nothing-overlaps- (byte-intervals obj)))\n    (:method ((obj byte-interval))\n      (nothing-overlaps- (remove-if-not {typep _ 'code-block} (blocks obj))))\n    (:method ((obj code-block)) t)))\n\n(define-check-generic all-referents-exist (object)\n  (:method ((obj gtirb))\n    (and (every #'all-referents-exist (modules obj))\n         (every {get-uuid _ obj} (nodes (cfg obj)))))\n  (:method ((obj module)) (every #'all-referents-exist (symbols obj)))\n  (:method ((obj symbol))\n    (if (gtirb.proto:has-referent-uuid (gtirb::proto obj))\n        (payload obj)\n        t)))\n\n(define-check-generic symbolic-expression-size-well-formed (object)\n  (:method ((obj gtirb))\n    (every [{every «member #'second\n                           [#'hash-table-keys #'symbolic-expressions\n                                              {get-uuid _ obj} #'car]»}\n            #'hash-table-keys #'aux-data-data #'cdr\n            (lambda (el) (assoc \"symbolicExpressionSizes\" el :test #'string=))\n            #'aux-data]\n           (modules obj))))\n\n\f\n;;;; Command-line interface\n(eval-when (:compile-toplevel :load-toplevel :execute)\n  (defparameter +validate-args+\n    '(((\"help\" #\\h #\\?) :type boolean :optional t\n       :documentation \"display help output\"))))\n\n(define-command validate-file (gtirb-file &spec +validate-args+)\n  \"Validate GTIRB-FILE.\" \"\"\n  (flet ((exit (code)\n           (if *lisp-interaction*\n               (return-from validate-file (zerop code))\n               (quit code))))\n    (when help (show-help-for-validate-file) (quit))\n    (if (validate (read-gtirb gtirb-file))\n        (exit 0)\n        (exit 2))))\n"
  },
  {
    "path": "cl/version.lisp",
    "content": "(defpackage :gtirb/version\n  (:use :common-lisp)\n  (:import-from :alexandria\n                :define-constant)\n  (:import-from :asdf/system :system-relative-pathname)\n  (:import-from :uiop :nest)\n  (:export :gtirb-version\n           :protobuf-version))\n(in-package :gtirb/version)\n\n(eval-when (:compile-toplevel :load-toplevel :execute)\n  (defvar version.txt\n    `#.(nest (let ((version-path\n                    (system-relative-pathname \"gtirb\" \"../version.txt\"))))\n             (with-open-file (in version-path))\n             (loop for line = (read-line in nil :eof)\n                until (eql line :eof)\n                collect (let ((delim (position #\\Space line)))\n                          (cons (intern (subseq line 0 delim))\n                                (parse-integer (subseq line (1+ delim)))))))))\n\n(define-constant gtirb-version\n    (format nil \"~d.~d.~d\"\n            (cdr (assoc 'VERSION_MAJOR version.txt))\n            (cdr (assoc 'VERSION_MINOR version.txt))\n            (cdr (assoc 'VERSION_PATCH version.txt)))\n  :test #'string=\n  :documentation \"GTIRB Version as a string of \\\"MAJOR.MINOR.PATCH\\\".\")\n\n(define-constant protobuf-version\n    (cdr (assoc 'VERSION_PROTOBUF version.txt))\n  :test #'=\n  :documentation \"GTIRB Protobuf Version as a non-negative integer.\")\n"
  },
  {
    "path": "conanfile.py",
    "content": "import os\nimport re\n\nfrom conans import CMake, ConanFile, tools\nfrom conans.errors import ConanInvalidConfiguration\nfrom conans.model.version import Version\n\n\ndef get_gtirb_version():\n    if \"CI_COMMIT_REF_NAME\" in os.environ:\n        branch = os.environ[\"CI_COMMIT_REF_NAME\"]\n        if branch == \"master\":\n            return \"dev\"\n    try:\n        with open(\"version.txt\") as f:\n            s = f.read()\n            match = re.search(\n                r\"VERSION_MAJOR(\\s+)(\\S+)(\\s+)\"\n                r\"VERSION_MINOR(\\s+)(\\S+)(\\s+)\"\n                r\"VERSION_PATCH(\\s+)(\\S+)(\\s+)\",\n                s,\n            )\n            if match:\n                major = match.group(2)\n                minor = match.group(5)\n                patch = match.group(8)\n                return major + \".\" + minor + \".\" + patch\n            else:\n                return \"<ERROR: no version found in version.txt>\"\n    except Exception:\n        return \"<ERROR: version.txt not found>\"\n\n\ndef branch_to_channel(branch):\n    if re.match(r\"^release-.*\", branch):\n        return \"stable\"\n    else:\n        return branch.replace(\"/\", \"+\")\n\n\nclass Properties:\n    name = \"gtirb\"\n    rel_url = \"rewriting/gtirb\"\n    exports_sources = \"*\", \"!*_CPack_Packages*\", \"!*java*.class\"\n\n    @property\n    def version(self):\n        if not hasattr(self, \"_version\"):\n            self._version = get_gtirb_version()\n        return self._version\n\n    @version.setter\n    def version(self, ver):\n        self._version = ver\n\n    @property\n    def description(self):\n        return \"%s library\" % self.name\n\n    @property\n    def url(self):\n        return \"https://git.grammatech.com/%s\" % self.rel_url\n\n    @property\n    def conan_channel(self):\n        channel = \"local\"\n        if \"CI_COMMIT_REF_NAME\" in os.environ:\n            branch = os.environ[\"CI_COMMIT_REF_NAME\"]\n            channel = branch_to_channel(branch)\n        return channel\n\n    @property\n    def archived_channels(self):\n        # Add to this list branch names to have conan packages for\n        # branches archived in gitlab.\n        archived_branches = [\"master\"]\n        # Also, archive the 'stable' channel, where all stable versions\n        # will be uploaded\n        archived_channels = [\"stable\"]\n        return archived_channels + list(\n            map(branch_to_channel, archived_branches)\n        )\n\n    @property\n    def conan_ref(self):\n        channel = self.conan_channel\n        return \"%s/%s\" % (self.rel_url.replace(\"/\", \"+\"), channel)\n\n    @property\n    def conan_recipe(self):\n        return \"%s/%s@%s\" % (self.name, self.version, self.conan_ref)\n\n\nclass GtirbConan(Properties, ConanFile):\n    boost_version = \"1.69.0\"\n    protobuf_version = \"3.15.5\"\n    requires = (\n        \"boost/{0}\".format(boost_version),\n        \"protobuf/{0}\".format(protobuf_version),\n    )\n    settings = \"os\", \"build_type\", \"compiler\", \"arch\"\n    generators = \"cmake\"\n\n    def configure(self):\n        if (\n            self.settings.compiler == \"gcc\"\n            and self.settings.compiler.libcxx != \"libstdc++11\"\n        ):\n            raise ConanInvalidConfiguration(\n                \"gtirb requires libstdc++11 ABI, update your conan profile\"\n            )\n\n    def build_requirements(self):\n        if self.settings.os == \"Windows\":\n            self.build_requires(\"ninja/1.10.2\")\n\n    def build(self):\n        if self.settings.os == \"Windows\":\n            with tools.vcvars(\n                self.settings, force=True, filter_known_paths=False\n            ):\n                self.build_cmake()\n        else:\n            self.build_cmake()\n\n    def build_cmake(self):\n        # Note: Only build the C++ API\n        defs = {\n            \"CMAKE_VERBOSE_MAKEFILE:BOOL\": \"ON\",\n            \"ENABLE_CONAN:BOOL\": \"ON\",\n            \"GTIRB_CXX_API:BOOL\": \"ON\",\n            \"GTIRB_PY_API:BOOL\": \"OFF\",\n            \"GTIRB_CL_API:BOOL\": \"OFF\",\n            \"GTIRB_JAVA_API:BOOL\": \"OFF\",\n        }\n        disable_parallel_build = (\n            int(os.environ.get(\"GTIRB_DISABLE_PARALLEL_BUILD\", \"0\")) != 0\n        )\n        if self.settings.os == \"Windows\":\n            cmake = CMake(self, generator=\"Ninja\")\n            defs.update(\n                {\n                    k: os.environ.get(k)\n                    for k in [\"BOOST_ROOT\", \"CMAKE_PREFIX_PATH\", \"PYTHON\"]\n                }\n            )\n            defs.update({\"Protobuf_USE_STATIC_LIBS\": \"ON\"})\n            if disable_parallel_build:\n                defs[\"GTIRB_MSVC_PARALLEL_COMPILE_JOBS\"] = \"1\"\n        else:\n            cmake = CMake(self, generator=None)\n            defs.update({\"GTIRB_STRIP_DEBUG_SYMBOLS:BOOL\": \"ON\"})\n        cmake.configure(\n            source_folder=\".\",\n            defs=defs,\n        )\n        if disable_parallel_build:\n            cmake.parallel = False\n        cmake.build()\n        cmake.test(output_on_failure=True)\n        cmake.install()\n        # The patch_config_paths() function will change absolute paths in the\n        # exported cmake config files to use the appropriate conan variables\n        # instead.\n        # It is an experimental feature of conan, however, so if you're having\n        # trouble with paths in the cmake of the conan package, it could that\n        # this function is no longer doing what we want.\n        cmake.patch_config_paths()\n\n    def package(self):\n        pass\n\n    def package_info(self):\n        self.cpp_info.libs = [\"gtirb\"]\n\n    def package_id(self):\n        v = Version(str(self.settings.compiler.version))\n        if self.settings.compiler == \"Visual Studio\" and v in [\"15\", \"16\"]:\n            self.info.settings.compiler.version = \"Visual Studio 15 and 16\"\n"
  },
  {
    "path": "cpack-config.cmake",
    "content": "# Global properties\nset(CMAKE_PROJECT_HOMEPAGE_URL https://github.com/GrammaTech/gtirb)\nset(CPACK_COMPONENTS_GROUPING ALL_COMPONENTS_IN_ONE)\n\nset(CPACK_DEB_COMPONENT_INSTALL ON)\n\n# Reusable lists of components\nset(LIB_COMPONENTS library license)\nset(DEV_COMPONENTS headers proto_library cmake_config cmake_target)\n\n# Debian packages\nif(\"${CPACK_GTIRB_PACKAGE}\" STREQUAL \"debian-lib\")\n  set(CPACK_DEBIAN_PACKAGE_NAME \"libgtirb\")\n  set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)\n  set(CPACK_COMPONENTS_ALL ${LIB_COMPONENTS})\n  if(\"${CPACK_DEBIAN_PACKAGE_RELEASE}\" STREQUAL \"focal\")\n    set(CPACK_DEBIAN_PACKAGE_DEPENDS\n        \"libstdc++6, libc6, libgcc1, libprotobuf17\"\n    )\n  elseif(\"${CPACK_DEBIAN_PACKAGE_RELEASE}\" STREQUAL \"jammy\")\n    set(CPACK_DEBIAN_PACKAGE_DEPENDS\n        \"libstdc++6, libc6, libgcc-s1, libprotobuf23\"\n    )\n  elseif(\"${CPACK_DEBIAN_PACKAGE_RELEASE}\" STREQUAL \"noble\")\n    set(CPACK_DEBIAN_PACKAGE_DEPENDS\n        \"libstdc++6, libc6, libgcc-s1, libprotobuf32t64\"\n    )\n  else()\n    message(\n      SEND_ERROR \"Unknown / missing value for CPACK_DEBIAN_PACKAGE_RELEASE.\"\n    )\n  endif()\nelseif(\"${CPACK_GTIRB_PACKAGE}\" STREQUAL \"debian-dev\")\n  set(CPACK_DEBIAN_PACKAGE_NAME \"libgtirb-dev\")\n  set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)\n  set(CPACK_COMPONENTS_ALL ${DEV_COMPONENTS})\n  set(CPACK_DEBIAN_PACKAGE_DEPENDS\n      \"libgtirb (=${CPACK_GTIRB_VERSION}-${CPACK_DEBIAN_PACKAGE_RELEASE}), libboost-dev (>=1.68) | libboost1.68-dev, libprotobuf-dev (>=${CPACK_PROTOBUF_VERSION_LOWER_BOUND}~), libprotobuf-dev (<<${CPACK_PROTOBUF_VERSION_UPPER_BOUND})\"\n  )\nelseif(\"${CPACK_GTIRB_PACKAGE}\" STREQUAL \"debian-debug\")\n  set(CPACK_DEBIAN_PACKAGE_NAME \"libgtirb-dbg\")\n  set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)\n  set(CPACK_COMPONENTS_ALL debug-file)\n  set(CPACK_DEBIAN_PACKAGE_DEPENDS\n      \"libgtirb (=${CPACK_GTIRB_VERSION}-${CPACK_DEBIAN_PACKAGE_RELEASE})\"\n  )\nendif()\n"
  },
  {
    "path": "doc/CFG-Edges.md",
    "content": "Advice on when to Place ICFG Edges\n==================================\n\nIt is not always straightforward when to construct ICFG edges.  For\nexample, should there be an edge from a function's return to every\ncaller of that function?  While GTIRB does not preclude or enforce any\nparticular ICFG connection strategy, we do propose the following\nsuggestions for how to handle many common situations.\n\n## Undefined/extern functions.\n\nHow to handle edges leaving call instructions to undefined or extern\nfunctions?  In this case the function is not included in the module\nand thus is not a possible edge target in the ICFG.\n\n> ????\n\n## Fall through edges from call sites.\n\nSince we're working with an interprocedural CFG, we have edges from\ncall instructions to their targets. Do we also have edges from a call\ninstruction to the instruction immediately after it in memory?\n\n> Yes unless we know the callee does not return (e.g., exit).\n\n### Non-return functions.\n\nWhen generating code around non-return functions (like exit):\nsometimes compilers omit any following code if they know a call will\nnot return.  For example in a situation like this (except in machine\ncode):\n\n```C\nvoid foo()\n{\n    if (something) {\n        bar_that_always_calls_exit();\n        // stack cleanup\n        return;\n    }\n}\n```\n\nIn some cases, the compiler will know that\n`bar_that_always_calls_exit()` will never return. In some cases, the\ncompiler doesn't figure that out. In the former case, the compiler may\nomit the \"stack cleanup\" and \"return\" code. In the latter case, it\nwill not.\n\nIn some cases, your disassembly engine will know that\n`bar_that_always_calls_exit()` will never return.  In some cases, your\ndisassembly engine doesn't figure that out.  In the former case, you\ncan choose to omit the \"fall-through\" edge in your IR. In the latter\ncase, you won't, because you think the execution flow is possible.\n\nSo, if you get the combination: the compiler figured it out and you\ndid *not*.  Then you will add the CFG edge from\n`bar_that_always_calls_exit()` to whatever follows.  But whatever\nfollows will not necessarily be code in the function `foo()` or code\nat all really.  It will be whatever random chunk of bytes the compiler\nhappened to plop down next.\n\nWe bring this up because it has bearing on your stance for adding\nedges from callsites to their follows.  If you don't do that, you'll\nnever make this mistake.\n\nHowever, we suggest that in the balance, having the edges when your\ndisassembly is correct outweighs the presence of this error.\n\n\n## Edges from returns back to call sites.\n\nWhat about from a return instruction to corresponding call sites\n(plural) (or rather the instructions that follow them)?\n\n> Yes.\n\n## Edges from indirect calls to targets.\n\nIndirect calls: we won't know who the targets are always. And we won't\nknow to add edges from corresponding return instructions.\n\n> We put in edges (to and from) as we're able to identify them.  We\n> don't conservatively put edges between every indirect call and every\n> function.\n\n## Tail calls.\n\nTail calls don't have return instructions or a place for a callee to\nreturn to.\n\n> Hook up the eventual return of a tail called function to the places\n> it could lead (i.e., non tail-call callers and callers of tail-call\n> callers).\n"
  },
  {
    "path": "doc/CMakeLists.txt",
    "content": "add_custom_target(doc)\nfile(MAKE_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}/html\")\n\nif(CXX_API)\n  set(CPP_TAGFILE \"${CMAKE_CURRENT_BINARY_DIR}/CPP_DOXY.tag\")\n  set(CPP_TAGFILE_RULE \"${CPP_TAGFILE}=cpp\")\n  set(CPP_DOX_ENABLED \"CPP_ONLY\")\n  set(CPP_API_VISIBLE \"yes\")\n  add_subdirectory(cpp)\nelse()\n  set(CPP_TAGFILE_RULE \"\")\n  set(CPP_DOX_ENABLED \"\")\n  set(CPP_API_VISIBLE \"no\")\nendif()\n\nif(PY_API)\n  add_subdirectory(python)\n  set(PY_DOX_ENABLED \"PY_ONLY\")\n  set(PY_API_VISIBLE \"yes\")\nelse()\n  set(PY_DOX_ENABLED \"\")\n  set(PY_API_VISIBLE \"no\")\nendif()\n\nif(CL_API)\n  add_subdirectory(cl)\n  set(CL_DOX_ENABLED \"CL_ONLY\")\n  set(CL_API_VISIBLE \"yes\")\nelse()\n  set(CL_DOX_ENABLED \"\")\n  set(CL_API_VISIBLE \"no\")\nendif()\n\nif(JAVA_API)\n  add_subdirectory(java)\n  set(JAVA_DOX_ENABLED \"JAVA_ONLY\")\n  set(JAVA_API_VISIBLE \"yes\")\nelse()\n  set(JAVA_DOX_ENABLED \"\")\n  set(JAVA_API_VISIBLE \"no\")\nendif()\n\nadd_subdirectory(examples)\nadd_subdirectory(general)\n"
  },
  {
    "path": "doc/binary-representation.md",
    "content": "Binary Representation with GTIRB\n================================\n\n- [Representing Binaries](#representing-binaries)\n    - [Sections](#sections)\n    - [Symbols](#symbols)\n    - [Byte Intervals](#byte-intervals)\n    - [Symbolic Expressions](#symbolic-expressions)\n\nGTIRB portably encodes binaries from a range of standard executable\nand linkable formats, such as\n[ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format),\n[PE](https://en.wikipedia.org/wiki/Portable_Executable), and\n[Mach-O](https://en.wikipedia.org/wiki/Mach-O), allowing conversion to\nand from these formats to GTIRB.  In ensure all information from the\noriginal binary is retained despite standard GTIRB data\nstructures--which are intended to be general across all binary\nrepresentations--being lossy for many aspects of particular\nrepresentation, encoders are encouraged to include all raw bytes of\nthe original file in the GTIRB encoding.  In addition, GTIRB encodes\ninformation above and beyond what these formats store; it stores\ncontrol flow, symbolization (reference) information, and other\nanalysis results, with the goal of providing all essential information\nto support subsequent binary analysis and rewriting. Finally, GTIRB\nallows user-extensible data to be included in the form of AuxData\ntables which can easily reference other GTIRB elements--letting tools\ncommunicate with each other in a single standard in-file format.\n\n## Representing Binaries\n\nAlthough executable file formats differ in many ways, they typically\ntend to have a similar structure.  The bytes of the image are divided\ninto sections, which contain the bytes consisting of the code and data\nalong with information about how to load and adjust them at run-time.\nTo facilitate linking with shared libraries, they have a symbol table,\nwhich specifies a list of names of entities this file provides or\nrequires.  To facilitate relocation in memory these files often\ncontains a relocation table.\n\nGTIRB contains all this information in standard forms.  In GTIRB, a\nsingle executable or library is encoded as a *module*.  A GTIRB file\nmay have multiple modules, enclosed in a single *IR*.  GTIRB encodes\nthe standard features of all binary formats in the following\nstructures:\n\n### Sections\n\nModules in GTIRB contain multiple *sections*.  A section has a name\nreflecting any name given in the original file (e.g., `.text`), a set\nof properties, and a set of contents stored in\n[byte intervals](#byte-intervals).\n\n### Symbols\n\nRather than storing a symbol table as a section, GTIRB stores a set of\n*symbols* associated with every module.  These symbols have a name, a\nset of properties, and a *referent*.  A referent may be an integer,\nindicating that the symbol is a numeric constant or fixed address, or\na reference to a *block*. A block may be one of:\n\n| Block Kind    | Description                                             |\n|---------------|---------------------------------------------------------|\n| *code block*  | a series of executable instructions                     |\n| *data block*  | a series of data bytes                                  |\n| *proxy block* | indicating that the symbol is defined in another module |\n\n### Byte Intervals\n\nThe bytes of a section are subdivided into chunks of bytes called\n*byte intervals*. This indirection layer serves two purposes:\n\n- Indicate what blocks can be moved independently of each other. It is\n  guaranteed that you can shuffle around two byte intervals in a\n  section, and doing so will preserve the program's semantics.\n- Support the generation of blocks with no original address. Byte\n  intervals may have a fixed address, but they may also be unfixed,\n  likely indicating that the byte interval was generated by a binary\n  rewriting tool or is freely movable to any address.\n\nTwo byte intervals in the same section may not overlap in addresses\n(although sections can overlap with each other in some cases, such as\nin object code).  Byte intervals contain code blocks or data blocks.\nThe blocks within a byte interval *can* overlap.  Examples of\noverlapping blocks include:\n\n- Overlapping data blocks are common.\n  - One data block may representing an array may overlap many data\n    blocks representing elements of the array.\n  - Compilers often overlap strings with shared suffixes.  The data\n    blocks representing these strings will similarly overlap.\n* Overlapping code blocks are rare, however particularly clever or\n  malicious code blocks in variable-width ISAs may overlap when two\n  different sequences of instructions serialize to machine-code bytes\n  which share common subsequences.\n\nByte intervals also hold [symbolic expressions](#symbolic-expressions)\nwhich indicate symbolic contents of code or data blocks.\n\n### Symbolic Expressions\n\nTo encode relocations, GTIRB associates *symbolic expressions* with\nbyte-intervals.  These specify that certain bytes in the binary refer\nto the address.  This allows these bytes to be recalculated when the\nreferent is moved in the binary image.\n\nGTIRB does not specify exactly how symbolic expressions are\ntransformed into bytes. This depends on where the symbolic expression\nis located; inside a code block, it depends on what part of an\ninstruction it is of, while inside a data block, it depends on the\nsize of the data block.\n\nThere are currently three kinds of symbolic expressions:\n\n| Kind            | Description       |\n|-----------------|-------------------|\n| *SymAddrConst*  | the address of the referent of a symbol, plus or minus a fixed offset     |\n| *SymAddrAddr*   | the difference between two symbols, divided by a scale and plus an offset |\n"
  },
  {
    "path": "doc/cl/CMakeLists.txt",
    "content": "set(SDT_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/write-documentation.lisp)\nset(README ${CMAKE_SOURCE_DIR}/cl/README.md)\nset(HTML_INDEX ${CMAKE_BINARY_DIR}/doc/html/cl/index.html)\n\nfile(MAKE_DIRECTORY \"${CMAKE_BINARY_DIR}/doc/html/cl\")\nfile(GLOB CL_SOURCES ${CMAKE_SOURCE_DIR}/cl/*.lisp ${CMAKE_SOURCE_DIR}/cl/*.asd)\n\nadd_custom_command(\n  OUTPUT ${HTML_INDEX}\n  DEPENDS ${SDT_SCRIPT} ${README} ${CL_SOURCES}\n  COMMAND\n    ${LISP} --noinform --dynamic-space-size 16384 --no-userinit --no-sysinit\n    --disable-debugger --load ${QUICKLISP}/setup.lisp --eval\n    \"(asdf:initialize-source-registry `(:source-registry (:tree \\\"${CMAKE_SOURCE_DIR}/cl\\\") :inherit-configuration))\"\n    --script ${SDT_SCRIPT} gtirb ${README} ${HTML_INDEX}\n  VERBATIM\n  COMMENT \"Generating API documentation with SDT\"\n)\nadd_custom_target(sdt ALL DEPENDS ${HTML_INDEX})\nadd_dependencies(doc sdt)\n"
  },
  {
    "path": "doc/cl/write-documentation.lisp",
    "content": ";; -*- lisp -*-\n;;\n;; Usage: write-documentation PKG ABSTRACT OUTPUT-HTML\n;;   Write the automatically generated documentation for PKG to\n;;   OUTPUT-HTML.  The ABSTRACT should be a file in Markdown format to\n;;   place at the top of the generated documentation.\n;;\n(load \"~/.sbclrc\" :if-does-not-exist nil)\n(ql:quickload :alexandria)\n(ql:quickload :simpler-documentation-template)\n(ql:quickload :markdown.cl)\n(unless (= (length sb-ext:*posix-argv*) 5)\n  (format t \"Usage: write-documentation PKG ABSTRACT OUTPUT-HTML\"))\n(let ((package (alexandria:make-keyword\n                (string-upcase (second sb-ext:*posix-argv*))))\n      (abstract-path (third sb-ext:*posix-argv*))\n      (output-path (fourth sb-ext:*posix-argv*)))\n  (ql:quickload package)\n  #+debug (format t \"Writing: ~S~%\" (list package abstract-path output-path))\n  (simpler-documentation-template:create-template\n   package\n   :maybe-skip-methods-p t\n   :target output-path\n   :abstract-html (markdown.cl:parse\n                   (with-open-file (in abstract-path)\n                     (let* ((file-bytes (file-length in))\n                            (seq (make-string file-bytes))\n                            (file-chars (read-sequence seq in)))\n                       (subseq seq 0 file-chars))))))\n"
  },
  {
    "path": "doc/cpp/CMakeLists.txt",
    "content": "# based on sample in https://majewsky.wordpress.com/2010/08/14/tip-of-the-day-\n# cmake-and-doxygen/ add a target to generate API documentation with Doxygen\n\ncmake_minimum_required(VERSION 3.3)\n\nfind_package(Doxygen)\nif(DOXYGEN_FOUND)\n\n  set(ROOTDIR \"${CMAKE_CURRENT_SOURCE_DIR}/../..\")\n  set(DOTDIR \"${CMAKE_CURRENT_SOURCE_DIR}/../dot\")\n\n  set(BUILDFILES_IN ../preprocmd.py DoxygenLayout.xml)\n  foreach(_inf ${BUILDFILES_IN})\n    configure_file(\n      ${CMAKE_CURRENT_SOURCE_DIR}/${_inf} ${CMAKE_CURRENT_BINARY_DIR}/${_inf}\n      @ONLY\n    )\n  endforeach()\n\n  # Handle version initialization\n  file(READ \"${ROOTDIR}/version.txt\" ver)\n\n  string(REGEX MATCH \"VERSION_MAJOR ([0-9]*)\" _ ${ver})\n  set(GTIRB_MAJOR_VERSION ${CMAKE_MATCH_1})\n\n  string(REGEX MATCH \"VERSION_MINOR ([0-9]*)\" _ ${ver})\n  set(GTIRB_MINOR_VERSION ${CMAKE_MATCH_1})\n\n  string(REGEX MATCH \"VERSION_PATCH ([0-9]*)\" _ ${ver})\n  set(GTIRB_PATCH_VERSION ${CMAKE_MATCH_1})\n\n  configure_file(\n    \"${ROOTDIR}/include/gtirb/version.h.in\"\n    \"${ROOTDIR}/include/gtirb/version.h\" @ONLY\n  )\n\n  configure_file(\n    \"${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in\"\n    \"${CMAKE_CURRENT_BINARY_DIR}/Doxyfile\" @ONLY\n  )\n\n  # adapted from https://gist.github.com/abravalheri/11214134\n\n  macro(move_filename file_list newdir)\n    foreach(src_file ${${file_list}})\n      get_filename_component(src_file_name \"${src_file}\" NAME)\n      list(REMOVE_ITEM ${file_list} \"${src_file}\")\n      list(APPEND ${file_list} \"${newdir}/${src_file_name}\")\n    endforeach()\n  endmacro()\n\n  # ----------------------------------------------------------------------\n  # copy dot files into a subdir of the working directory\n  # ----------------------------------------------------------------------\n  file(GLOB DOTFILES_IN \"${DOTDIR}/*\")\n\n  set(DOTFILES ${DOTFILES_IN})\n  move_filename(DOTFILES ${CMAKE_CURRENT_BINARY_DIR})\n\n  # message(\"DOTFILES = ${DOTFILES}\")\n\n  add_custom_command(\n    OUTPUT ${DOTFILES}\n    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}\n    DEPENDS ${DOTFILES_IN}\n    COMMAND mkdir -p dot\n    COMMAND ${CMAKE_COMMAND} -E copy_directory ${DOTDIR} dot\n    COMMENT \"copying dot dir\"\n    VERBATIM\n  )\n\n  # ----------------------------------------------------------------------\n  # copy md files into the working directory\n  # ----------------------------------------------------------------------\n\n  set(MDFILES_IN \"${CMAKE_CURRENT_SOURCE_DIR}/README.md\")\n\n  set(MDFILES ${MDFILES_IN})\n  move_filename(MDFILES ${CMAKE_CURRENT_BINARY_DIR})\n  # message(\"MDFILES = ${MDFILES}\")\n\n  gtirb_find_python()\n\n  foreach(_inmd ${MDFILES_IN})\n    get_filename_component(_outmd \"${_inmd}\" NAME)\n    add_custom_command(\n      OUTPUT ${_outmd}\n      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}\n      DEPENDS ${_inmd}\n      COMMAND ${CMAKE_COMMAND} -E copy ${_inmd} \"${_outmd}.in\"\n      COMMAND ${PYTHON} ../preprocmd.py \"${_outmd}.in\" ${_outmd}\n      COMMENT \"processing ${_outmd}\"\n      VERBATIM\n    )\n  endforeach()\n\n  # ----------------------------------------------------------------------\n  # Main target\n  # ----------------------------------------------------------------------\n\n  add_custom_target(\n    cpp_doxyout\n    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}\n    DEPENDS ${DOTFILES}\n    DEPENDS ${MDFILES}\n    COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile\n    COMMENT \"Generating C++ API documentation with Doxygen\"\n    VERBATIM\n  )\n\n  add_dependencies(doc cpp_doxyout)\nendif(DOXYGEN_FOUND)\n"
  },
  {
    "path": "doc/cpp/Doxyfile.in",
    "content": "# Doxyfile 1.8.11\n\n# This file describes the settings to be used by the documentation system\n# doxygen (www.doxygen.org) for a project.\n#\n# All text after a double hash (##) is considered a comment and is placed in\n# front of the TAG it is preceding.\n#\n# All text after a single hash (#) is considered a comment and will be ignored.\n# The format is:\n# TAG = value [value, ...]\n# For lists, items can also be appended using:\n# TAG += value [value, ...]\n# Values that contain spaces should be placed between quotes (\\\" \\\").\n\n#---------------------------------------------------------------------------\n# Project related configuration options\n#---------------------------------------------------------------------------\n\n# This tag specifies the encoding used for all characters in the config file\n# that follow. The default is UTF-8 which is also the encoding used for all text\n# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv\n# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv\n# for the list of possible encodings.\n# The default value is: UTF-8.\n\nDOXYFILE_ENCODING      = UTF-8\n\n# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by\n# double-quotes, unless you are using Doxywizard) that should identify the\n# project for which the documentation is generated. This name is used in the\n# title of most generated pages and in a few other places.\n# The default value is: My Project.\n\nPROJECT_NAME           = GTIRB\n\n# The PROJECT_NUMBER tag can be used to enter a project or revision number. This\n# could be handy for archiving the generated documentation or if some version\n# control system is used.\n\nPROJECT_NUMBER         = v@GTIRB_MAJOR_VERSION@.@GTIRB_MINOR_VERSION@.@GTIRB_PATCH_VERSION@\n\n# Using the PROJECT_BRIEF tag one can provide an optional one line description\n# for a project that appears at the top of each page and should give viewer a\n# quick idea about the purpose of the project. Keep the description short.\n\nPROJECT_BRIEF          = \"GrammaTech Intermediate Representation for Binaries: C++ API\"\n\n# With the PROJECT_LOGO tag one can specify a logo or an icon that is included\n# in the documentation. The maximum height of the logo should not exceed 55\n# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy\n# the logo to the output directory.\n\nPROJECT_LOGO           =\n\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path\n# into which the generated documentation will be written. If a relative path is\n# entered, it will be relative to the location where doxygen was started. If\n# left blank the current directory will be used.\n\nOUTPUT_DIRECTORY       = @CMAKE_BINARY_DIR@/doc\n\n# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-\n# directories (in 2 levels) under the output directory of each output format and\n# will distribute the generated files over these directories. Enabling this\n# option can be useful when feeding doxygen a huge amount of source files, where\n# putting all generated files in the same directory would otherwise causes\n# performance problems for the file system.\n# The default value is: NO.\n\nCREATE_SUBDIRS         = NO\n\n# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII\n# characters to appear in the names of generated files. If set to NO, non-ASCII\n# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode\n# U+3044.\n# The default value is: NO.\n\nALLOW_UNICODE_NAMES    = NO\n\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all\n# documentation generated by doxygen is written. Doxygen will use this\n# information to generate all constant output in the proper language.\n# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,\n# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),\n# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,\n# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),\n# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,\n# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,\n# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,\n# Ukrainian and Vietnamese.\n# The default value is: English.\n\nOUTPUT_LANGUAGE        = English\n\n# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member\n# descriptions after the members that are listed in the file and class\n# documentation (similar to Javadoc). Set to NO to disable this.\n# The default value is: YES.\n\nBRIEF_MEMBER_DESC      = YES\n\n# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief\n# description of a member or function before the detailed description\n#\n# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the\n# brief descriptions will be completely suppressed.\n# The default value is: YES.\n\nREPEAT_BRIEF           = YES\n\n# This tag implements a quasi-intelligent brief description abbreviator that is\n# used to form the text in various listings. Each string in this list, if found\n# as the leading text of the brief description, will be stripped from the text\n# and the result, after processing the whole list, is used as the annotated\n# text. Otherwise, the brief description is used as-is. If left blank, the\n# following values are used ($name is automatically replaced with the name of\n# the entity):The $name class, The $name widget, The $name file, is, provides,\n# specifies, contains, represents, a, an and the.\n\nABBREVIATE_BRIEF       = \"The $name class\" \\\n                         \"The $name widget\" \\\n                         \"The $name file\" \\\n                         is \\\n                         provides \\\n                         specifies \\\n                         contains \\\n                         represents \\\n                         a \\\n                         an \\\n                         the\n\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then\n# doxygen will generate a detailed section even if there is only a brief\n# description.\n# The default value is: NO.\n\nALWAYS_DETAILED_SEC    = NO\n\n# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all\n# inherited members of a class in the documentation of that class as if those\n# members were ordinary class members. Constructors, destructors and assignment\n# operators of the base classes will not be shown.\n# The default value is: NO.\n\nINLINE_INHERITED_MEMB  = NO\n\n# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path\n# before files name in the file list and in the header files. If set to NO the\n# shortest path that makes the file name unique will be used\n# The default value is: YES.\n\nFULL_PATH_NAMES        = NO\n\n# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.\n# Stripping is only done if one of the specified strings matches the left-hand\n# part of the path. The tag can be used to show relative paths in the file list.\n# If left blank the directory from which doxygen is run is used as the path to\n# strip.\n#\n# Note that you can specify absolute paths here, but also relative paths, which\n# will be relative from the directory where doxygen is started.\n# This tag requires that the tag FULL_PATH_NAMES is set to YES.\n\nSTRIP_FROM_PATH        = .\n\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the\n# path mentioned in the documentation of a class, which tells the reader which\n# header file to include in order to use a class. If left blank only the name of\n# the header file containing the class definition is used. Otherwise one should\n# specify the list of include paths that are normally passed to the compiler\n# using the -I flag.\n\nSTRIP_FROM_INC_PATH    =\n\n# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but\n# less readable) file names. This can be useful is your file systems doesn't\n# support long names like on DOS, Mac, or CD-ROM.\n# The default value is: NO.\n\nSHORT_NAMES            = NO\n\n# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the\n# first line (until the first dot) of a Javadoc-style comment as the brief\n# description. If set to NO, the Javadoc-style will behave just like regular Qt-\n# style comments (thus requiring an explicit @brief command for a brief\n# description.)\n# The default value is: NO.\n\nJAVADOC_AUTOBRIEF      = NO\n\n# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first\n# line (until the first dot) of a Qt-style comment as the brief description. If\n# set to NO, the Qt-style will behave just like regular Qt-style comments (thus\n# requiring an explicit \\brief command for a brief description.)\n# The default value is: NO.\n\nQT_AUTOBRIEF           = NO\n\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a\n# multi-line C++ special comment block (i.e. a block of //! or /// comments) as\n# a brief description. This used to be the default behavior. The new default is\n# to treat a multi-line C++ comment block as a detailed description. Set this\n# tag to YES if you prefer the old behavior instead.\n#\n# Note that setting this tag to YES also means that rational rose comments are\n# not recognized any more.\n# The default value is: NO.\n\nMULTILINE_CPP_IS_BRIEF = NO\n\n# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the\n# documentation from any documented member that it re-implements.\n# The default value is: YES.\n\nINHERIT_DOCS           = YES\n\n# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new\n# page for each member. If set to NO, the documentation of a member will be part\n# of the file/class/namespace that contains it.\n# The default value is: NO.\n\nSEPARATE_MEMBER_PAGES  = NO\n\n# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen\n# uses this value to replace tabs by spaces in code fragments.\n# Minimum value: 1, maximum value: 16, default value: 4.\n\nTAB_SIZE               = 4\n\n# This tag can be used to specify a number of aliases that act as commands in\n# the documentation. An alias has the form:\n# name=value\n# For example adding\n# \"sideeffect=@par Side Effects:\\n\"\n# will allow you to put the command \\sideeffect (or @sideeffect) in the\n# documentation, which will result in a user-defined paragraph with heading\n# \"Side Effects:\". You can put \\n's in the value part of an alias to insert\n# newlines.\n\nALIASES                =\n\n# This tag can be used to specify a number of word-keyword mappings (TCL only).\n# A mapping has the form \"name=value\". For example adding \"class=itcl::class\"\n# will allow you to use the command class in the itcl::class meaning.\n\nTCL_SUBST              =\n\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources\n# only. Doxygen will then generate output that is more tailored for C. For\n# instance, some of the names that are used will be different. The list of all\n# members will be omitted, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_FOR_C  = NO\n\n# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or\n# Python sources only. Doxygen will then generate output that is more tailored\n# for that language. For instance, namespaces will be presented as packages,\n# qualified scopes will look different, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_JAVA   = NO\n\n# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran\n# sources. Doxygen will then generate output that is tailored for Fortran.\n# The default value is: NO.\n\nOPTIMIZE_FOR_FORTRAN   = NO\n\n# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL\n# sources. Doxygen will then generate output that is tailored for VHDL.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_VHDL   = NO\n\n# Doxygen selects the parser to use depending on the extension of the files it\n# parses. With this tag you can assign which parser to use for a given\n# extension. Doxygen has a built-in mapping, but you can override or extend it\n# using this tag. The format is ext=language, where ext is a file extension, and\n# language is one of the parsers supported by doxygen: IDL, Java, Javascript,\n# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:\n# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:\n# Fortran. In the later case the parser tries to guess whether the code is fixed\n# or free formatted code, this is the default for Fortran type files), VHDL. For\n# instance to make doxygen treat .inc files as Fortran files (default is PHP),\n# and .f files as C (default is Fortran), use: inc=Fortran f=C.\n#\n# Note: For files without extension you can use no_extension as a placeholder.\n#\n# Note that for custom extensions you also need to set FILE_PATTERNS otherwise\n# the files are not read by doxygen.\n\nEXTENSION_MAPPING      =\n\n# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments\n# according to the Markdown format, which allows for more readable\n# documentation. See http://daringfireball.net/projects/markdown/ for details.\n# The output of markdown processing is further processed by doxygen, so you can\n# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in\n# case of backward compatibilities issues.\n# The default value is: YES.\n\nMARKDOWN_SUPPORT       = YES\n\n# When enabled doxygen tries to link words that correspond to documented\n# classes, or namespaces to their corresponding documentation. Such a link can\n# be prevented in individual cases by putting a % sign in front of the word or\n# globally by setting AUTOLINK_SUPPORT to NO.\n# The default value is: YES.\n\nAUTOLINK_SUPPORT       = YES\n\n# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want\n# to include (a tag file for) the STL sources as input, then you should set this\n# tag to YES in order to let doxygen match functions declarations and\n# definitions whose arguments contain STL classes (e.g. func(std::string);\n# versus func(std::string) {}). This also make the inheritance and collaboration\n# diagrams that involve STL classes more complete and accurate.\n# The default value is: NO.\n\nBUILTIN_STL_SUPPORT    = NO\n\n# If you use Microsoft's C++/CLI language, you should set this option to YES to\n# enable parsing support.\n# The default value is: NO.\n\nCPP_CLI_SUPPORT        = NO\n\n# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:\n# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen\n# will parse them like normal C++ but will assume all classes use public instead\n# of private inheritance when no explicit protection keyword is present.\n# The default value is: NO.\n\nSIP_SUPPORT            = NO\n\n# For Microsoft's IDL there are propget and propput attributes to indicate\n# getter and setter methods for a property. Setting this option to YES will make\n# doxygen to replace the get and set methods by a property in the documentation.\n# This will only work if the methods are indeed getting or setting a simple\n# type. If this is not the case, or you want to show the methods anyway, you\n# should set this option to NO.\n# The default value is: YES.\n\nIDL_PROPERTY_SUPPORT   = YES\n\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC\n# tag is set to YES then doxygen will reuse the documentation of the first\n# member in the group (if any) for the other members of the group. By default\n# all members of a group must be documented explicitly.\n# The default value is: NO.\n\nDISTRIBUTE_GROUP_DOC   = NO\n\n# If one adds a struct or class to a group and this option is enabled, then also\n# any nested class or struct is added to the same group. By default this option\n# is disabled and one has to add nested compounds explicitly via \\ingroup.\n# The default value is: NO.\n\nGROUP_NESTED_COMPOUNDS = NO\n\n# Set the SUBGROUPING tag to YES to allow class member groups of the same type\n# (for instance a group of public functions) to be put as a subgroup of that\n# type (e.g. under the Public Functions section). Set it to NO to prevent\n# subgrouping. Alternatively, this can be done per class using the\n# \\nosubgrouping command.\n# The default value is: YES.\n\nSUBGROUPING            = YES\n\n# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions\n# are shown inside the group in which they are included (e.g. using \\ingroup)\n# instead of on a separate page (for HTML and Man pages) or section (for LaTeX\n# and RTF).\n#\n# Note that this feature does not work in combination with\n# SEPARATE_MEMBER_PAGES.\n# The default value is: NO.\n\nINLINE_GROUPED_CLASSES = NO\n\n# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions\n# with only public data fields or simple typedef fields will be shown inline in\n# the documentation of the scope in which they are defined (i.e. file,\n# namespace, or group documentation), provided this scope is documented. If set\n# to NO, structs, classes, and unions are shown on a separate page (for HTML and\n# Man pages) or section (for LaTeX and RTF).\n# The default value is: NO.\n\nINLINE_SIMPLE_STRUCTS  = NO\n\n# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or\n# enum is documented as struct, union, or enum with the name of the typedef. So\n# typedef struct TypeS {} TypeT, will appear in the documentation as a struct\n# with name TypeT. When disabled the typedef will appear as a member of a file,\n# namespace, or class. And the struct will be named TypeS. This can typically be\n# useful for C code in case the coding convention dictates that all compound\n# types are typedef'ed and only the typedef is referenced, never the tag name.\n# The default value is: NO.\n\nTYPEDEF_HIDES_STRUCT   = YES\n\n# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This\n# cache is used to resolve symbols given their name and scope. Since this can be\n# an expensive process and often the same symbol appears multiple times in the\n# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small\n# doxygen will become slower. If the cache is too large, memory is wasted. The\n# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range\n# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536\n# symbols. At the end of a run doxygen will report the cache usage and suggest\n# the optimal cache size from a speed point of view.\n# Minimum value: 0, maximum value: 9, default value: 0.\n\nLOOKUP_CACHE_SIZE      = 0\n\n#---------------------------------------------------------------------------\n# Build related configuration options\n#---------------------------------------------------------------------------\n\n# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in\n# documentation are documented, even if no documentation was available. Private\n# class members and static file members will be hidden unless the\n# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.\n# Note: This will also disable the warnings about undocumented members that are\n# normally produced when WARNINGS is set to YES.\n# The default value is: NO.\n\nEXTRACT_ALL            = YES\n\n# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will\n# be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PRIVATE        = NO\n\n# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal\n# scope will be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PACKAGE        = NO\n\n# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be\n# included in the documentation.\n# The default value is: NO.\n\nEXTRACT_STATIC         = NO\n\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined\n# locally in source files will be included in the documentation. If set to NO,\n# only classes defined in header files are included. Does not have any effect\n# for Java sources.\n# The default value is: YES.\n\nEXTRACT_LOCAL_CLASSES  = YES\n\n# This flag is only useful for Objective-C code. If set to YES, local methods,\n# which are defined in the implementation section but not in the interface are\n# included in the documentation. If set to NO, only methods in the interface are\n# included.\n# The default value is: NO.\n\nEXTRACT_LOCAL_METHODS  = NO\n\n# If this flag is set to YES, the members of anonymous namespaces will be\n# extracted and appear in the documentation as a namespace called\n# 'anonymous_namespace{file}', where file will be replaced with the base name of\n# the file that contains the anonymous namespace. By default anonymous namespace\n# are hidden.\n# The default value is: NO.\n\nEXTRACT_ANON_NSPACES   = YES\n\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all\n# undocumented members inside documented classes or files. If set to NO these\n# members will be included in the various overviews, but no documentation\n# section is generated. This option has no effect if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_MEMBERS     = NO\n\n# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all\n# undocumented classes that are normally visible in the class hierarchy. If set\n# to NO, these classes will be included in the various overviews. This option\n# has no effect if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_CLASSES     = NO\n\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend\n# (class|struct|union) declarations. If set to NO, these declarations will be\n# included in the documentation.\n# The default value is: NO.\n\nHIDE_FRIEND_COMPOUNDS  = NO\n\n# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any\n# documentation blocks found inside the body of a function. If set to NO, these\n# blocks will be appended to the function's detailed documentation block.\n# The default value is: NO.\n\nHIDE_IN_BODY_DOCS      = NO\n\n# The INTERNAL_DOCS tag determines if documentation that is typed after a\n# \\internal command is included. If the tag is set to NO then the documentation\n# will be excluded. Set it to YES to include the internal documentation.\n# The default value is: NO.\n\nINTERNAL_DOCS          = NO\n\n# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file\n# names in lower-case letters. If set to YES, upper-case letters are also\n# allowed. This is useful if you have classes or files whose names only differ\n# in case and if your file system supports case sensitive file names. Windows\n# and Mac users are advised to set this option to NO.\n# The default value is: system dependent.\n\nCASE_SENSE_NAMES       = NO\n\n# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with\n# their full class and namespace scopes in the documentation. If set to YES, the\n# scope will be hidden.\n# The default value is: NO.\n\nHIDE_SCOPE_NAMES       = NO\n\n# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will\n# append additional text to a page's title, such as Class Reference. If set to\n# YES the compound reference will be hidden.\n# The default value is: NO.\n\nHIDE_COMPOUND_REFERENCE= NO\n\n# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of\n# the files that are included by a file in the documentation of that file.\n# The default value is: YES.\n\nSHOW_INCLUDE_FILES     = YES\n\n# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each\n# grouped member an include statement to the documentation, telling the reader\n# which file to include in order to use the member.\n# The default value is: NO.\n\nSHOW_GROUPED_MEMB_INC  = YES\n\n# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include\n# files with double quotes in the documentation rather than with sharp brackets.\n# The default value is: NO.\n\nFORCE_LOCAL_INCLUDES   = NO\n\n# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the\n# documentation for inline members.\n# The default value is: YES.\n\nINLINE_INFO            = YES\n\n# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the\n# (detailed) documentation of file and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order.\n# The default value is: YES.\n\nSORT_MEMBER_DOCS       = YES\n\n# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief\n# descriptions of file, namespace and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order. Note that\n# this will also influence the order of the classes in the class list.\n# The default value is: NO.\n\nSORT_BRIEF_DOCS        = YES\n\n# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the\n# (brief and detailed) documentation of class members so that constructors and\n# destructors are listed first. If set to NO the constructors will appear in the\n# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.\n# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief\n# member documentation.\n# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting\n# detailed member documentation.\n# The default value is: NO.\n\nSORT_MEMBERS_CTORS_1ST = YES\n\n# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy\n# of group names into alphabetical order. If set to NO the group names will\n# appear in their defined order.\n# The default value is: NO.\n\nSORT_GROUP_NAMES       = YES\n\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by\n# fully-qualified names, including namespaces. If set to NO, the class list will\n# be sorted only by class name, not including the namespace part.\n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n# Note: This option applies only to the class list, not to the alphabetical\n# list.\n# The default value is: NO.\n\nSORT_BY_SCOPE_NAME     = NO\n\n# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper\n# type resolution of all parameters of a function it will reject a match between\n# the prototype and the implementation of a member function even if there is\n# only one candidate or it is obvious which candidate to choose by doing a\n# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still\n# accept a match between prototype and implementation in such cases.\n# The default value is: NO.\n\nSTRICT_PROTO_MATCHING  = NO\n\n# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo\n# list. This list is created by putting \\todo commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TODOLIST      = YES\n\n# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test\n# list. This list is created by putting \\test commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TESTLIST      = YES\n\n# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug\n# list. This list is created by putting \\bug commands in the documentation.\n# The default value is: YES.\n\nGENERATE_BUGLIST       = YES\n\n# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)\n# the deprecated list. This list is created by putting \\deprecated commands in\n# the documentation.\n# The default value is: YES.\n\nGENERATE_DEPRECATEDLIST= YES\n\n# The ENABLED_SECTIONS tag can be used to enable conditional documentation\n# sections, marked by \\if <section_label> ... \\endif and \\cond <section_label>\n# ... \\endcond blocks.\n\nENABLED_SECTIONS       =\n\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the\n# initial value of a variable or macro / define can have for it to appear in the\n# documentation. If the initializer consists of more lines than specified here\n# it will be hidden. Use a value of 0 to hide initializers completely. The\n# appearance of the value of individual variables and macros / defines can be\n# controlled using \\showinitializer or \\hideinitializer command in the\n# documentation regardless of this setting.\n# Minimum value: 0, maximum value: 10000, default value: 30.\n\nMAX_INITIALIZER_LINES  = 30\n\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at\n# the bottom of the documentation of classes and structs. If set to YES, the\n# list will mention the files that were used to generate the documentation.\n# The default value is: YES.\n\nSHOW_USED_FILES        = YES\n\n# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This\n# will remove the Files entry from the Quick Index and from the Folder Tree View\n# (if specified).\n# The default value is: YES.\n\nSHOW_FILES             = YES\n\n# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces\n# page. This will remove the Namespaces entry from the Quick Index and from the\n# Folder Tree View (if specified).\n# The default value is: YES.\n\nSHOW_NAMESPACES        = YES\n\n# The FILE_VERSION_FILTER tag can be used to specify a program or script that\n# doxygen should invoke to get the current version for each file (typically from\n# the version control system). Doxygen will invoke the program by executing (via\n# popen()) the command command input-file, where command is the value of the\n# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided\n# by doxygen. Whatever the program writes to standard output is used as the file\n# version. For an example see the documentation.\n\nFILE_VERSION_FILTER    =\n\n# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed\n# by doxygen. The layout file controls the global structure of the generated\n# output files in an output format independent way. To create the layout file\n# that represents doxygen's defaults, run doxygen with the -l option. You can\n# optionally specify a file name after the option, if omitted DoxygenLayout.xml\n# will be used as the name of the layout file.\n#\n# Note that if you run doxygen from a directory containing a file called\n# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE\n# tag is left empty.\n\nLAYOUT_FILE            =\n\n# The CITE_BIB_FILES tag can be used to specify one or more bib files containing\n# the reference definitions. This must be a list of .bib files. The .bib\n# extension is automatically appended if omitted. This requires the bibtex tool\n# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.\n# For LaTeX the style of the bibliography can be controlled using\n# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the\n# search path. See also \\cite for info how to create references.\n\nCITE_BIB_FILES         =\n\n#---------------------------------------------------------------------------\n# Configuration options related to warning and progress messages\n#---------------------------------------------------------------------------\n\n# The QUIET tag can be used to turn on/off the messages that are generated to\n# standard output by doxygen. If QUIET is set to YES this implies that the\n# messages are off.\n# The default value is: NO.\n\nQUIET                  = NO\n\n# The WARNINGS tag can be used to turn on/off the warning messages that are\n# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES\n# this implies that the warnings are on.\n#\n# Tip: Turn warnings on while writing the documentation.\n# The default value is: YES.\n\nWARNINGS               = YES\n\n# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate\n# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag\n# will automatically be disabled.\n# The default value is: YES.\n\nWARN_IF_UNDOCUMENTED   = YES\n\n# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for\n# potential errors in the documentation, such as not documenting some parameters\n# in a documented function, or documenting parameters that don't exist or using\n# markup commands wrongly.\n# The default value is: YES.\n\nWARN_IF_DOC_ERROR      = YES\n\n# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that\n# are documented, but have no documentation for their parameters or return\n# value. If set to NO, doxygen will only warn about wrong or incomplete\n# parameter documentation, but not about the absence of documentation.\n# The default value is: NO.\n\nWARN_NO_PARAMDOC       = NO\n\n# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when\n# a warning is encountered.\n# The default value is: NO.\n\nWARN_AS_ERROR          = NO\n\n# The WARN_FORMAT tag determines the format of the warning messages that doxygen\n# can produce. The string should contain the $file, $line, and $text tags, which\n# will be replaced by the file and line number from which the warning originated\n# and the warning text. Optionally the format may contain $version, which will\n# be replaced by the version of the file (if it could be obtained via\n# FILE_VERSION_FILTER)\n# The default value is: $file:$line: $text.\n\nWARN_FORMAT            = \"$file:$line: $text\"\n\n# The WARN_LOGFILE tag can be used to specify a file to which warning and error\n# messages should be written. If left blank the output is written to standard\n# error (stderr).\n\nWARN_LOGFILE           = doxygen_warnings.txt\n\n#---------------------------------------------------------------------------\n# Configuration options related to the input files\n#---------------------------------------------------------------------------\n\n# The INPUT tag is used to specify the files and/or directories that contain\n# documented source files. You may enter file names like myfile.cpp or\n# directories like /usr/src/myproject. Separate the files or directories with\n# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING\n# Note: If this tag is empty the current directory is searched.\n\nINPUT   = @CMAKE_CURRENT_SOURCE_DIR@/../../include @CMAKE_CURRENT_SOURCE_DIR@/../dot \\\n          README.md\n\n# This tag can be used to specify the character encoding of the source files\n# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses\n# libiconv (or the iconv built into libc) for the transcoding. See the libiconv\n# documentation (see: http://www.gnu.org/software/libiconv) for the list of\n# possible encodings.\n# The default value is: UTF-8.\n\nINPUT_ENCODING         = UTF-8\n\n# If the value of the INPUT tag contains directories, you can use the\n# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and\n# *.h) to filter out the source-files in the directories.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# read by doxygen.\n#\n# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,\n# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,\n# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,\n# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,\n# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.\n\nFILE_PATTERNS          = *.c \\\n                         *.cc \\\n                         *.cxx \\\n                         *.cpp \\\n                         *.c++ \\\n                         *.java \\\n                         *.ii \\\n                         *.ixx \\\n                         *.ipp \\\n                         *.i++ \\\n                         *.inl \\\n                         *.idl \\\n                         *.ddl \\\n                         *.odl \\\n                         *.h \\\n                         *.hh \\\n                         *.hxx \\\n                         *.hpp \\\n                         *.h++ \\\n                         *.cs \\\n                         *.d \\\n                         *.php \\\n                         *.php4 \\\n                         *.php5 \\\n                         *.phtml \\\n                         *.inc \\\n                         *.m \\\n                         *.markdown \\\n                         *.md \\\n                         *.mm \\\n                         *.dox \\\n                         *.py \\\n                         *.pyw \\\n                         *.f90 \\\n                         *.f \\\n                         *.for \\\n                         *.tcl \\\n                         *.vhd \\\n                         *.vhdl \\\n                         *.ucf \\\n                         *.qsf \\\n                         *.as \\\n                         *.js\n\n# The RECURSIVE tag can be used to specify whether or not subdirectories should\n# be searched for input files as well.\n# The default value is: NO.\n\nRECURSIVE              = YES\n\n# The EXCLUDE tag can be used to specify files and/or directories that should be\n# excluded from the INPUT source files. This way you can easily exclude a\n# subdirectory from a directory tree whose root is specified with the INPUT tag.\n#\n# Note that relative paths are relative to the directory from which doxygen is\n# run.\n\nEXCLUDE                =\n\n# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or\n# directories that are symbolic links (a Unix file system feature) are excluded\n# from the input.\n# The default value is: NO.\n\nEXCLUDE_SYMLINKS       = NO\n\n# If the value of the INPUT tag contains directories, you can use the\n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude\n# certain files from those directories.\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories for example use the pattern */test/*\n\nEXCLUDE_PATTERNS       = */include/proto/*.h\n\n# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names\n# (namespaces, classes, functions, etc.) that should be excluded from the\n# output. The symbol name can be a fully qualified name, a word, or if the\n# wildcard * is used, a substring. Examples: ANamespace, AClass,\n# AClass::ANamespace, ANamespace::*Test\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories use the pattern */test/*\n\nEXCLUDE_SYMBOLS        = proto\n\n# The EXAMPLE_PATH tag can be used to specify one or more files or directories\n# that contain example code fragments that are included (see the \\include\n# command).\n\nEXAMPLE_PATH           =\n\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the\n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and\n# *.h) to filter out the source-files in the directories. If left blank all\n# files are included.\n\nEXAMPLE_PATTERNS       = *\n\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be\n# searched for input files to be used with the \\include or \\dontinclude commands\n# irrespective of the value of the RECURSIVE tag.\n# The default value is: NO.\n\nEXAMPLE_RECURSIVE      = NO\n\n# The IMAGE_PATH tag can be used to specify one or more files or directories\n# that contain images that are to be included in the documentation (see the\n# \\image command).\n\nIMAGE_PATH             =\n\n# The INPUT_FILTER tag can be used to specify a program that doxygen should\n# invoke to filter for each input file. Doxygen will invoke the filter program\n# by executing (via popen()) the command:\n#\n# <filter> <input-file>\n#\n# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the\n# name of an input file. Doxygen will then use the output that the filter\n# program writes to standard output. If FILTER_PATTERNS is specified, this tag\n# will be ignored.\n#\n# Note that the filter must not add or remove lines; it is applied before the\n# code is scanned, but not when the output code is generated. If lines are added\n# or removed, the anchors will not be placed correctly.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by doxygen.\n\nINPUT_FILTER           =\n\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern\n# basis. Doxygen will compare the file name with each pattern and apply the\n# filter if there is a match. The filters are a list of the form: pattern=filter\n# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how\n# filters are used. If the FILTER_PATTERNS tag is empty or if none of the\n# patterns match the file name, INPUT_FILTER is applied.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by doxygen.\n\nFILTER_PATTERNS        =\n\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using\n# INPUT_FILTER) will also be used to filter the input files that are used for\n# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).\n# The default value is: NO.\n\nFILTER_SOURCE_FILES    = NO\n\n# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file\n# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and\n# it is also possible to disable source filtering for a specific pattern using\n# *.ext= (so without naming a filter).\n# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.\n\nFILTER_SOURCE_PATTERNS =\n\n# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that\n# is part of the input, its contents will be placed on the main page\n# (index.html). This can be useful if you have a project on for instance GitHub\n# and want to reuse the introduction page also for the doxygen output.\n\nUSE_MDFILE_AS_MAINPAGE = README.md\n\n#---------------------------------------------------------------------------\n# Configuration options related to source browsing\n#---------------------------------------------------------------------------\n\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will be\n# generated. Documented entities will be cross-referenced with these sources.\n#\n# Note: To get rid of all source code in the generated output, make sure that\n# also VERBATIM_HEADERS is set to NO.\n# The default value is: NO.\n\nSOURCE_BROWSER         = NO\n\n# Setting the INLINE_SOURCES tag to YES will include the body of functions,\n# classes and enums directly into the documentation.\n# The default value is: NO.\n\nINLINE_SOURCES         = NO\n\n# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any\n# special comment blocks from generated source code fragments. Normal C, C++ and\n# Fortran comments will always remain visible.\n# The default value is: YES.\n\nSTRIP_CODE_COMMENTS    = YES\n\n# If the REFERENCED_BY_RELATION tag is set to YES then for each documented\n# function all documented functions referencing it will be listed.\n# The default value is: NO.\n\nREFERENCED_BY_RELATION = NO\n\n# If the REFERENCES_RELATION tag is set to YES then for each documented function\n# all documented entities called/used by that function will be listed.\n# The default value is: NO.\n\nREFERENCES_RELATION    = NO\n\n# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set\n# to YES then the hyperlinks from functions in REFERENCES_RELATION and\n# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will\n# link to the documentation.\n# The default value is: YES.\n\nREFERENCES_LINK_SOURCE = YES\n\n# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the\n# source code will show a tooltip with additional information such as prototype,\n# brief description and links to the definition and documentation. Since this\n# will make the HTML file larger and loading of large files a bit slower, you\n# can opt to disable this feature.\n# The default value is: YES.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nSOURCE_TOOLTIPS        = YES\n\n# If the USE_HTAGS tag is set to YES then the references to source code will\n# point to the HTML generated by the htags(1) tool instead of doxygen built-in\n# source browser. The htags tool is part of GNU's global source tagging system\n# (see http://www.gnu.org/software/global/global.html). You will need version\n# 4.8.6 or higher.\n#\n# To use it do the following:\n# - Install the latest version of global\n# - Enable SOURCE_BROWSER and USE_HTAGS in the config file\n# - Make sure the INPUT points to the root of the source tree\n# - Run doxygen as normal\n#\n# Doxygen will invoke htags (and that will in turn invoke gtags), so these\n# tools must be available from the command line (i.e. in the search path).\n#\n# The result: instead of the source browser generated by doxygen, the links to\n# source code will now point to the output of htags.\n# The default value is: NO.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nUSE_HTAGS              = NO\n\n# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a\n# verbatim copy of the header file for each class for which an include is\n# specified. Set to NO to disable this.\n# See also: Section \\class.\n# The default value is: YES.\n\nVERBATIM_HEADERS       = YES\n\n# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the\n# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the\n# cost of reduced performance. This can be particularly helpful with template\n# rich C++ code for which doxygen's built-in parser lacks the necessary type\n# information.\n# Note: The availability of this option depends on whether or not doxygen was\n# generated with the -Duse-libclang=ON option for CMake.\n# The default value is: NO.\n\nCLANG_ASSISTED_PARSING = NO\n\n# If clang assisted parsing is enabled you can provide the compiler with command\n# line options that you would normally use when invoking the compiler. Note that\n# the include paths will already be set by doxygen for the files and directories\n# specified with INPUT and INCLUDE_PATH.\n# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.\n\nCLANG_OPTIONS          =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the alphabetical class index\n#---------------------------------------------------------------------------\n\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all\n# compounds will be generated. Enable this if the project contains a lot of\n# classes, structs, unions or interfaces.\n# The default value is: YES.\n\nALPHABETICAL_INDEX     = YES\n\n# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in\n# which the alphabetical index list will be split.\n# Minimum value: 1, maximum value: 20, default value: 5.\n# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.\n\nCOLS_IN_ALPHA_INDEX    = 5\n\n# In case all classes in a project start with a common prefix, all classes will\n# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag\n# can be used to specify a prefix (or a list of prefixes) that should be ignored\n# while generating the index headers.\n# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.\n\nIGNORE_PREFIX          =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the HTML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output\n# The default value is: YES.\n\nGENERATE_HTML          = YES\n\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_OUTPUT            = html/cpp\n\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each\n# generated HTML page (for example: .htm, .php, .asp).\n# The default value is: .html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FILE_EXTENSION    = .html\n\n# The HTML_HEADER tag can be used to specify a user-defined HTML header file for\n# each generated HTML page. If the tag is left blank doxygen will generate a\n# standard header.\n#\n# To get valid HTML the header file that includes any scripts and style sheets\n# that doxygen needs, which is dependent on the configuration options used (e.g.\n# the setting GENERATE_TREEVIEW). It is highly recommended to start with a\n# default header using\n# doxygen -w html new_header.html new_footer.html new_stylesheet.css\n# YourConfigFile\n# and then modify the file new_header.html. See also section \"Doxygen usage\"\n# for information on how to generate the default header that doxygen normally\n# uses.\n# Note: The header is subject to change so you typically have to regenerate the\n# default header when upgrading to a newer version of doxygen. For a description\n# of the possible markers and block names see the documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_HEADER            =\n\n# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each\n# generated HTML page. If the tag is left blank doxygen will generate a standard\n# footer. See HTML_HEADER for more information on how to generate a default\n# footer and what special commands can be used inside the footer. See also\n# section \"Doxygen usage\" for information on how to generate the default footer\n# that doxygen normally uses.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FOOTER            =\n\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style\n# sheet that is used by each HTML page. It can be used to fine-tune the look of\n# the HTML output. If left blank doxygen will generate a default style sheet.\n# See also section \"Doxygen usage\" for information on how to generate the style\n# sheet that doxygen normally uses.\n# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as\n# it is more robust and this tag (HTML_STYLESHEET) will in the future become\n# obsolete.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_STYLESHEET        =\n\n# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# cascading style sheets that are included after the standard style sheets\n# created by doxygen. Using this option one can overrule certain style aspects.\n# This is preferred over using HTML_STYLESHEET since it does not replace the\n# standard style sheet and is therefore more robust against future updates.\n# Doxygen will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list). For an example see the documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_STYLESHEET  =\n\n# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the HTML output directory. Note\n# that these files will be copied to the base HTML output directory. Use the\n# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these\n# files. In the HTML_STYLESHEET file, use the file name only. Also note that the\n# files will be copied as-is; there are no commands or markers available.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_FILES       =\n\n# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen\n# will adjust the colors in the style sheet and background images according to\n# this color. Hue is specified as an angle on a colorwheel, see\n# http://en.wikipedia.org/wiki/Hue for more information. For instance the value\n# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300\n# purple, and 360 is red again.\n# Minimum value: 0, maximum value: 359, default value: 220.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_HUE    = 220\n\n# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors\n# in the HTML output. For a value of 0 the output will use grayscales only. A\n# value of 255 will produce the most vivid colors.\n# Minimum value: 0, maximum value: 255, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_SAT    = 100\n\n# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the\n# luminance component of the colors in the HTML output. Values below 100\n# gradually make the output lighter, whereas values above 100 make the output\n# darker. The value divided by 100 is the actual gamma applied, so 80 represents\n# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not\n# change the gamma.\n# Minimum value: 40, maximum value: 240, default value: 80.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_GAMMA  = 80\n\n# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML\n# page will contain the date and time when the page was generated. Setting this\n# to YES can help to show when doxygen was last run and thus if the\n# documentation is up to date.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_TIMESTAMP         = NO\n\n# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML\n# documentation will contain sections that can be hidden and shown after the\n# page has loaded.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_DYNAMIC_SECTIONS  = NO\n\n# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries\n# shown in the various tree structured indices initially; the user can expand\n# and collapse entries dynamically later on. Doxygen will expand the tree to\n# such a level that at most the specified number of entries are visible (unless\n# a fully collapsed tree already exceeds this amount). So setting the number of\n# entries 1 will produce a full collapsed tree by default. 0 is a special value\n# representing an infinite number of entries and will result in a full expanded\n# tree by default.\n# Minimum value: 0, maximum value: 9999, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_INDEX_NUM_ENTRIES = 100\n\n# If the GENERATE_DOCSET tag is set to YES, additional index files will be\n# generated that can be used as input for Apple's Xcode 3 integrated development\n# environment (see: http://developer.apple.com/tools/xcode/), introduced with\n# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a\n# Makefile in the HTML output directory. Running make will produce the docset in\n# that directory and running make install will install the docset in\n# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at\n# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html\n# for more information.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_DOCSET        = NO\n\n# This tag determines the name of the docset feed. A documentation feed provides\n# an umbrella under which multiple documentation sets from a single provider\n# (such as a company or product suite) can be grouped.\n# The default value is: Doxygen generated docs.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_FEEDNAME        = \"Doxygen generated docs\"\n\n# This tag specifies a string that should uniquely identify the documentation\n# set bundle. This should be a reverse domain-name style string, e.g.\n# com.mycompany.MyDocSet. Doxygen will append .docset to the name.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_BUNDLE_ID       = org.doxygen.Project\n\n# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify\n# the documentation publisher. This should be a reverse domain-name style\n# string, e.g. com.mycompany.MyDocSet.documentation.\n# The default value is: org.doxygen.Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_ID    = org.doxygen.Publisher\n\n# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.\n# The default value is: Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_NAME  = Publisher\n\n# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three\n# additional HTML index files: index.hhp, index.hhc, and index.hhk. The\n# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop\n# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on\n# Windows.\n#\n# The HTML Help Workshop contains a compiler that can convert all HTML output\n# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML\n# files are now used as the Windows 98 help format, and will replace the old\n# Windows help format (.hlp) on all Windows platforms in the future. Compressed\n# HTML files also contain an index, a table of contents, and you can search for\n# words in the documentation. The HTML workshop also contains a viewer for\n# compressed HTML files.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_HTMLHELP      = NO\n\n# The CHM_FILE tag can be used to specify the file name of the resulting .chm\n# file. You can add a path in front of the file if the result should not be\n# written to the html output directory.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_FILE               =\n\n# The HHC_LOCATION tag can be used to specify the location (absolute path\n# including file name) of the HTML help compiler (hhc.exe). If non-empty,\n# doxygen will try to run the HTML help compiler on the generated index.hhp.\n# The file has to be specified with full path.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nHHC_LOCATION           =\n\n# The GENERATE_CHI flag controls if a separate .chi index file is generated\n# (YES) or that it should be included in the master .chm file (NO).\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nGENERATE_CHI           = NO\n\n# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)\n# and project file content.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_INDEX_ENCODING     =\n\n# The BINARY_TOC flag controls whether a binary table of contents is generated\n# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it\n# enables the Previous and Next buttons.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nBINARY_TOC             = NO\n\n# The TOC_EXPAND flag can be set to YES to add extra items for group members to\n# the table of contents of the HTML help documentation and to the tree view.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nTOC_EXPAND             = NO\n\n# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and\n# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that\n# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help\n# (.qch) of the generated HTML documentation.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_QHP           = NO\n\n# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify\n# the file name of the resulting .qch file. The path specified is relative to\n# the HTML output folder.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQCH_FILE               =\n\n# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help\n# Project output. For more information please see Qt Help Project / Namespace\n# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_NAMESPACE          = org.doxygen.Project\n\n# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt\n# Help Project output. For more information please see Qt Help Project / Virtual\n# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-\n# folders).\n# The default value is: doc.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_VIRTUAL_FOLDER     = doc\n\n# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom\n# filter to add. For more information please see Qt Help Project / Custom\n# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-\n# filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_NAME   =\n\n# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the\n# custom filter to add. For more information please see Qt Help Project / Custom\n# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-\n# filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_ATTRS  =\n\n# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this\n# project's filter section matches. Qt Help Project / Filter Attributes (see:\n# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_SECT_FILTER_ATTRS  =\n\n# The QHG_LOCATION tag can be used to specify the location of Qt's\n# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the\n# generated .qhp file.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHG_LOCATION           =\n\n# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be\n# generated, together with the HTML files, they form an Eclipse help plugin. To\n# install this plugin and make it available under the help contents menu in\n# Eclipse, the contents of the directory containing the HTML and XML files needs\n# to be copied into the plugins directory of eclipse. The name of the directory\n# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.\n# After copying Eclipse needs to be restarted before the help appears.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_ECLIPSEHELP   = NO\n\n# A unique identifier for the Eclipse help plugin. When installing the plugin\n# the directory name containing the HTML and XML files should also have this\n# name. Each documentation set should have its own identifier.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.\n\nECLIPSE_DOC_ID         = org.doxygen.Project\n\n# If you want full control over the layout of the generated HTML pages it might\n# be necessary to disable the index and replace it with your own. The\n# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top\n# of each HTML page. A value of NO enables the index and the value YES disables\n# it. Since the tabs in the index contain the same information as the navigation\n# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nDISABLE_INDEX          = NO\n\n# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index\n# structure should be generated to display hierarchical information. If the tag\n# value is set to YES, a side panel will be generated containing a tree-like\n# index structure (just like the one that is generated for HTML Help). For this\n# to work a browser that supports JavaScript, DHTML, CSS and frames is required\n# (i.e. any modern browser). Windows users are probably better off using the\n# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can\n# further fine-tune the look of the index. As an example, the default style\n# sheet generated by doxygen has an example that shows how to put an image at\n# the root of the tree instead of the PROJECT_NAME. Since the tree basically has\n# the same information as the tab index, you could consider setting\n# DISABLE_INDEX to YES when enabling this option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_TREEVIEW      = NO\n\n# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that\n# doxygen will group on one line in the generated HTML documentation.\n#\n# Note that a value of 0 will completely suppress the enum values from appearing\n# in the overview section.\n# Minimum value: 0, maximum value: 20, default value: 4.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nENUM_VALUES_PER_LINE   = 4\n\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used\n# to set the initial width (in pixels) of the frame in which the tree is shown.\n# Minimum value: 0, maximum value: 1500, default value: 250.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nTREEVIEW_WIDTH         = 250\n\n# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to\n# external symbols imported via tag files in a separate window.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nEXT_LINKS_IN_WINDOW    = NO\n\n# Use this tag to change the font size of LaTeX formulas included as images in\n# the HTML documentation. When you change the font size after a successful\n# doxygen run you need to manually remove any form_*.png images from the HTML\n# output directory to force them to be regenerated.\n# Minimum value: 8, maximum value: 50, default value: 10.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFORMULA_FONTSIZE       = 10\n\n# Use the FORMULA_TRANPARENT tag to determine whether or not the images\n# generated for formulas are transparent PNGs. Transparent PNGs are not\n# supported properly for IE 6.0, but are supported on all modern browsers.\n#\n# Note that when changing this option you need to delete any form_*.png files in\n# the HTML output directory before the changes have effect.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFORMULA_TRANSPARENT    = YES\n\n# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see\n# http://www.mathjax.org) which uses client side Javascript for the rendering\n# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX\n# installed or if you want to formulas look prettier in the HTML output. When\n# enabled you may also need to install MathJax separately and configure the path\n# to it using the MATHJAX_RELPATH option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nUSE_MATHJAX            = NO\n\n# When MathJax is enabled you can set the default output format to be used for\n# the MathJax output. See the MathJax site (see:\n# http://docs.mathjax.org/en/latest/output.html) for more details.\n# Possible values are: HTML-CSS (which is slower, but has the best\n# compatibility), NativeMML (i.e. MathML) and SVG.\n# The default value is: HTML-CSS.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_FORMAT         = HTML-CSS\n\n# When MathJax is enabled you need to specify the location relative to the HTML\n# output directory using the MATHJAX_RELPATH option. The destination directory\n# should contain the MathJax.js script. For instance, if the mathjax directory\n# is located at the same level as the HTML output directory, then\n# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax\n# Content Delivery Network so you can quickly see the result without installing\n# MathJax. However, it is strongly recommended to install a local copy of\n# MathJax from http://www.mathjax.org before deployment.\n# The default value is: http://cdn.mathjax.org/mathjax/latest.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest\n\n# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax\n# extension names that should be enabled during MathJax rendering. For example\n# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_EXTENSIONS     =\n\n# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces\n# of code that will be used on startup of the MathJax code. See the MathJax site\n# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an\n# example see the documentation.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_CODEFILE       =\n\n# When the SEARCHENGINE tag is enabled doxygen will generate a search box for\n# the HTML output. The underlying search engine uses javascript and DHTML and\n# should work on any modern browser. Note that when using HTML help\n# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)\n# there is already a search function so this one should typically be disabled.\n# For large projects the javascript based search engine can be slow, then\n# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to\n# search using the keyboard; to jump to the search box use <access key> + S\n# (what the <access key> is depends on the OS and browser, but it is typically\n# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down\n# key> to jump into the search results window, the results can be navigated\n# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel\n# the search. The filter options can be selected when the cursor is inside the\n# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>\n# to select a filter and <Enter> or <escape> to activate or cancel the filter\n# option.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nSEARCHENGINE           = YES\n\n# When the SERVER_BASED_SEARCH tag is enabled the search engine will be\n# implemented using a web server instead of a web client using Javascript. There\n# are two flavors of web server based searching depending on the EXTERNAL_SEARCH\n# setting. When disabled, doxygen will generate a PHP script for searching and\n# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing\n# and searching needs to be provided by external tools. See the section\n# \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSERVER_BASED_SEARCH    = NO\n\n# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP\n# script for searching. Instead the search results are written to an XML file\n# which needs to be processed by an external indexer. Doxygen will invoke an\n# external search engine pointed to by the SEARCHENGINE_URL option to obtain the\n# search results.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see: http://xapian.org/).\n#\n# See the section \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH        = NO\n\n# The SEARCHENGINE_URL should point to a search engine hosted by a web server\n# which will return the search results when EXTERNAL_SEARCH is enabled.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see: http://xapian.org/). See the section \"External Indexing and\n# Searching\" for details.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHENGINE_URL       =\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed\n# search data is written to a file for indexing by an external tool. With the\n# SEARCHDATA_FILE tag the name of this file can be specified.\n# The default file is: searchdata.xml.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHDATA_FILE        = searchdata.xml\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the\n# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is\n# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple\n# projects and redirect the results back to the right project.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH_ID     =\n\n# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen\n# projects other than the one defined by this configuration file, but that are\n# all added to the same external search index. Each project needs to have a\n# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of\n# to a relative location where the documentation can be found. The format is:\n# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTRA_SEARCH_MAPPINGS  =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the LaTeX output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.\n# The default value is: YES.\n\nGENERATE_LATEX         = NO\n\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: latex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_OUTPUT           = latex\n\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be\n# invoked.\n#\n# Note that when enabling USE_PDFLATEX this option is only used for generating\n# bitmaps for formulas in the HTML output, but not in the Makefile that is\n# written to the output directory.\n# The default file is: latex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_CMD_NAME         = latex\n\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate\n# index for LaTeX.\n# The default file is: makeindex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nMAKEINDEX_CMD_NAME     = makeindex\n\n# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nCOMPACT_LATEX          = NO\n\n# The PAPER_TYPE tag can be used to set the paper type that is used by the\n# printer.\n# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x\n# 14 inches) and executive (7.25 x 10.5 inches).\n# The default value is: a4.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPAPER_TYPE             = a4\n\n# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names\n# that should be included in the LaTeX output. The package can be specified just\n# by its name or with the correct syntax as to be used with the LaTeX\n# \\usepackage command. To get the times font for instance you can specify :\n# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}\n# To use the option intlimits with the amsmath package you can specify:\n# EXTRA_PACKAGES=[intlimits]{amsmath}\n# If left blank no extra packages will be included.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nEXTRA_PACKAGES         =\n\n# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the\n# generated LaTeX document. The header should contain everything until the first\n# chapter. If it is left blank doxygen will generate a standard header. See\n# section \"Doxygen usage\" for information on how to let doxygen write the\n# default header to a separate file.\n#\n# Note: Only use a user-defined header if you know what you are doing! The\n# following commands have a special meaning inside the header: $title,\n# $datetime, $date, $doxygenversion, $projectname, $projectnumber,\n# $projectbrief, $projectlogo. Doxygen will replace $title with the empty\n# string, for the replacement values of the other commands the user is referred\n# to HTML_HEADER.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HEADER           =\n\n# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the\n# generated LaTeX document. The footer should contain everything after the last\n# chapter. If it is left blank doxygen will generate a standard footer. See\n# LATEX_HEADER for more information on how to generate a default footer and what\n# special commands can be used inside the footer.\n#\n# Note: Only use a user-defined footer if you know what you are doing!\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_FOOTER           =\n\n# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# LaTeX style sheets that are included after the standard style sheets created\n# by doxygen. Using this option one can overrule certain style aspects. Doxygen\n# will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list).\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_STYLESHEET =\n\n# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the LATEX_OUTPUT output\n# directory. Note that the files will be copied as-is; there are no commands or\n# markers available.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_FILES      =\n\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is\n# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will\n# contain links (just like the HTML output) instead of page references. This\n# makes the output suitable for online browsing using a PDF viewer.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPDF_HYPERLINKS         = YES\n\n# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate\n# the PDF file directly from the LaTeX files. Set this option to YES, to get a\n# higher quality PDF documentation.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nUSE_PDFLATEX           = YES\n\n# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode\n# command to the generated LaTeX files. This will instruct LaTeX to keep running\n# if errors occur, instead of asking the user for help. This option is also used\n# when generating formulas in HTML.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BATCHMODE        = NO\n\n# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the\n# index chapters (such as File Index, Compound Index, etc.) in the output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HIDE_INDICES     = NO\n\n# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source\n# code with syntax highlighting in the LaTeX output.\n#\n# Note that which sources are shown also depends on other settings such as\n# SOURCE_BROWSER.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_SOURCE_CODE      = NO\n\n# The LATEX_BIB_STYLE tag can be used to specify the style to use for the\n# bibliography, e.g. plainnat, or ieeetr. See\n# http://en.wikipedia.org/wiki/BibTeX and \\cite for more info.\n# The default value is: plain.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BIB_STYLE        = plain\n\n# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated\n# page will contain the date and time when the page was generated. Setting this\n# to NO can help when comparing the output of multiple runs.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_TIMESTAMP        = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the RTF output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The\n# RTF output is optimized for Word 97 and may not look too pretty with other RTF\n# readers/editors.\n# The default value is: NO.\n\nGENERATE_RTF           = NO\n\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: rtf.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_OUTPUT             = rtf\n\n# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nCOMPACT_RTF            = NO\n\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will\n# contain hyperlink fields. The RTF file will contain links (just like the HTML\n# output) instead of page references. This makes the output suitable for online\n# browsing using Word or some other Word compatible readers that support those\n# fields.\n#\n# Note: WordPad (write) and others do not support links.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_HYPERLINKS         = NO\n\n# Load stylesheet definitions from file. Syntax is similar to doxygen's config\n# file, i.e. a series of assignments. You only have to provide replacements,\n# missing definitions are set to their default value.\n#\n# See also section \"Doxygen usage\" for information on how to generate the\n# default style sheet that doxygen normally uses.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_STYLESHEET_FILE    =\n\n# Set optional variables used in the generation of an RTF document. Syntax is\n# similar to doxygen's config file. A template extensions file can be generated\n# using doxygen -e rtf extensionFile.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_EXTENSIONS_FILE    =\n\n# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code\n# with syntax highlighting in the RTF output.\n#\n# Note that which sources are shown also depends on other settings such as\n# SOURCE_BROWSER.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_SOURCE_CODE        = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the man page output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for\n# classes and files.\n# The default value is: NO.\n\nGENERATE_MAN           = NO\n\n# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it. A directory man3 will be created inside the directory specified by\n# MAN_OUTPUT.\n# The default directory is: man.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_OUTPUT             = man\n\n# The MAN_EXTENSION tag determines the extension that is added to the generated\n# man pages. In case the manual section does not start with a number, the number\n# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is\n# optional.\n# The default value is: .3.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_EXTENSION          = .3\n\n# The MAN_SUBDIR tag determines the name of the directory created within\n# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by\n# MAN_EXTENSION with the initial . removed.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_SUBDIR             =\n\n# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it\n# will generate one additional man file for each entity documented in the real\n# man page(s). These additional files only source the real man page, but without\n# them the man command would be unable to find the correct page.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_LINKS              = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the XML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that\n# captures the structure of the code including all documentation.\n# The default value is: NO.\n\nGENERATE_XML           = NO\n\n# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: xml.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_OUTPUT             = xml\n\n# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program\n# listings (including syntax highlighting and cross-referencing information) to\n# the XML output. Note that enabling this will significantly increase the size\n# of the XML output.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_PROGRAMLISTING     = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to the DOCBOOK output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files\n# that can be used to generate PDF.\n# The default value is: NO.\n\nGENERATE_DOCBOOK       = NO\n\n# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in\n# front of it.\n# The default directory is: docbook.\n# This tag requires that the tag GENERATE_DOCBOOK is set to YES.\n\nDOCBOOK_OUTPUT         = docbook\n\n# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the\n# program listings (including syntax highlighting and cross-referencing\n# information) to the DOCBOOK output. Note that enabling this will significantly\n# increase the size of the DOCBOOK output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_DOCBOOK is set to YES.\n\nDOCBOOK_PROGRAMLISTING = NO\n\n#---------------------------------------------------------------------------\n# Configuration options for the AutoGen Definitions output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an\n# AutoGen Definitions (see http://autogen.sf.net) file that captures the\n# structure of the code including all documentation. Note that this feature is\n# still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_AUTOGEN_DEF   = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the Perl module output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module\n# file that captures the structure of the code including all documentation.\n#\n# Note that this feature is still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_PERLMOD       = NO\n\n# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary\n# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI\n# output from the Perl module output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_LATEX          = NO\n\n# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely\n# formatted so it can be parsed by a human reader. This is useful if you want to\n# understand what is going on. On the other hand, if this tag is set to NO, the\n# size of the Perl module output will be much smaller and Perl will parse it\n# just the same.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_PRETTY         = YES\n\n# The names of the make variables in the generated doxyrules.make file are\n# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful\n# so different doxyrules.make files included by the same Makefile don't\n# overwrite each other's variables.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_MAKEVAR_PREFIX =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the preprocessor\n#---------------------------------------------------------------------------\n\n# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all\n# C-preprocessor directives found in the sources and include files.\n# The default value is: YES.\n\nENABLE_PREPROCESSING   = YES\n\n# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names\n# in the source code. If set to NO, only conditional compilation will be\n# performed. Macro expansion can be done in a controlled way by setting\n# EXPAND_ONLY_PREDEF to YES.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nMACRO_EXPANSION        = YES\n\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then\n# the macro expansion is limited to the macros specified with the PREDEFINED and\n# EXPAND_AS_DEFINED tags.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_ONLY_PREDEF     = YES\n\n# If the SEARCH_INCLUDES tag is set to YES, the include files in the\n# INCLUDE_PATH will be searched if a #include is found.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSEARCH_INCLUDES        = YES\n\n# The INCLUDE_PATH tag can be used to specify one or more directories that\n# contain include files that are not input files but should be processed by the\n# preprocessor.\n# This tag requires that the tag SEARCH_INCLUDES is set to YES.\n\nINCLUDE_PATH           =\n\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard\n# patterns (like *.h and *.hpp) to filter out the header-files in the\n# directories. If left blank, the patterns specified with FILE_PATTERNS will be\n# used.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nINCLUDE_FILE_PATTERNS  =\n\n# The PREDEFINED tag can be used to specify one or more macro names that are\n# defined before the preprocessor is started (similar to the -D option of e.g.\n# gcc). The argument of the tag is a list of macros of the form: name or\n# name=definition (no spaces). If the definition and the \"=\" are omitted, \"=1\"\n# is assumed. To prevent a macro definition from being undefined via #undef or\n# recursively expanded use the := operator instead of the = operator.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nPREDEFINED             = GTIRB_DEPRECATED_UTILS\n\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this\n# tag can be used to specify a list of macro names that should be expanded. The\n# macro definition that is found in the sources will be used. Use the PREDEFINED\n# tag if you want to use a different macro definition that overrules the\n# definition found in the source code.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_AS_DEFINED      =\n\n# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will\n# remove all references to function-like macros that are alone on a line, have\n# an all uppercase name, and do not end with a semicolon. Such function macros\n# are typically used for boiler-plate code, and will confuse the parser if not\n# removed.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSKIP_FUNCTION_MACROS   = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to external references\n#---------------------------------------------------------------------------\n\n# The TAGFILES tag can be used to specify one or more tag files. For each tag\n# file the location of the external documentation should be added. The format of\n# a tag file without this location is as follows:\n# TAGFILES = file1 file2 ...\n# Adding location for the tag files is done as follows:\n# TAGFILES = file1=loc1 \"file2 = loc2\" ...\n# where loc1 and loc2 can be relative or absolute paths or URLs. See the\n# section \"Linking to external documentation\" for more information about the use\n# of tag files.\n# Note: Each tag file must have a unique name (where the name does NOT include\n# the path). If a tag file is not located in the directory in which doxygen is\n# run, you must also specify the path to the tagfile here.\n\nTAGFILES               =\n\n# When a file name is specified after GENERATE_TAGFILE, doxygen will create a\n# tag file that is based on the input files it reads. See section \"Linking to\n# external documentation\" for more information about the usage of tag files.\n\nGENERATE_TAGFILE       = @CPP_TAGFILE@\n\n# If the ALLEXTERNALS tag is set to YES, all external class will be listed in\n# the class index. If set to NO, only the inherited external classes will be\n# listed.\n# The default value is: NO.\n\nALLEXTERNALS           = NO\n\n# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed\n# in the modules index. If set to NO, only the current project's groups will be\n# listed.\n# The default value is: YES.\n\nEXTERNAL_GROUPS        = YES\n\n# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in\n# the related pages index. If set to NO, only the current project's pages will\n# be listed.\n# The default value is: YES.\n\nEXTERNAL_PAGES         = YES\n\n# The PERL_PATH should be the absolute path and name of the perl script\n# interpreter (i.e. the result of 'which perl').\n# The default file (with absolute path) is: /usr/bin/perl.\n\nPERL_PATH              = /usr/bin/perl\n\n#---------------------------------------------------------------------------\n# Configuration options related to the dot tool\n#---------------------------------------------------------------------------\n\n# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram\n# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to\n# NO turns the diagrams off. Note that this option also works with HAVE_DOT\n# disabled, but it is recommended to install and use dot, since it yields more\n# powerful graphs.\n# The default value is: YES.\n\nCLASS_DIAGRAMS         = YES\n\n# You can define message sequence charts within doxygen comments using the \\msc\n# command. Doxygen will then run the mscgen tool (see:\n# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the\n# documentation. The MSCGEN_PATH tag allows you to specify the directory where\n# the mscgen tool resides. If left empty the tool is assumed to be found in the\n# default search path.\n\nMSCGEN_PATH            =\n\n# You can include diagrams made with dia in doxygen documentation. Doxygen will\n# then run dia to produce the diagram and insert it in the documentation. The\n# DIA_PATH tag allows you to specify the directory where the dia binary resides.\n# If left empty dia is assumed to be found in the default search path.\n\nDIA_PATH               =\n\n# If set to YES the inheritance and collaboration graphs will hide inheritance\n# and usage relations if the target is undocumented or is not a class.\n# The default value is: YES.\n\nHIDE_UNDOC_RELATIONS   = YES\n\n# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is\n# available from the path. This tool is part of Graphviz (see:\n# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent\n# Bell Labs. The other options in this section have no effect if this option is\n# set to NO\n# The default value is: YES.\n\nHAVE_DOT               = YES\n\n# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed\n# to run in parallel. When set to 0 doxygen will base this on the number of\n# processors available in the system. You can set it explicitly to a value\n# larger than 0 to get control over the balance between CPU load and processing\n# speed.\n# Minimum value: 0, maximum value: 32, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_NUM_THREADS        = 0\n\n# When you want a differently looking font in the dot files that doxygen\n# generates you can specify the font name using DOT_FONTNAME. You need to make\n# sure dot is able to find the font, which can be done by putting it in a\n# standard location or by setting the DOTFONTPATH environment variable or by\n# setting DOT_FONTPATH to the directory containing the font.\n# The default value is: Helvetica.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTNAME           = Helvetica\n\n# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of\n# dot graphs.\n# Minimum value: 4, maximum value: 24, default value: 10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTSIZE           = 10\n\n# By default doxygen will tell dot to use the default font as specified with\n# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set\n# the path where dot can find it using this tag.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTPATH           =\n\n# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for\n# each documented class showing the direct and indirect inheritance relations.\n# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCLASS_GRAPH            = YES\n\n# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a\n# graph for each documented class showing the direct and indirect implementation\n# dependencies (inheritance, containment, and class references variables) of the\n# class with other documented classes.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCOLLABORATION_GRAPH    = YES\n\n# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for\n# groups, showing the direct groups dependencies.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGROUP_GRAPHS           = YES\n\n# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and\n# collaboration diagrams in a style similar to the OMG's Unified Modeling\n# Language.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nUML_LOOK               = NO\n\n# If the UML_LOOK tag is enabled, the fields and methods are shown inside the\n# class node. If there are many fields or methods and many nodes the graph may\n# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the\n# number of items for each type to make the size more manageable. Set this to 0\n# for no limit. Note that the threshold may be exceeded by 50% before the limit\n# is enforced. So when you set the threshold to 10, up to 15 fields may appear,\n# but if the number exceeds 15, the total amount of fields shown is limited to\n# 10.\n# Minimum value: 0, maximum value: 100, default value: 10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nUML_LIMIT_NUM_FIELDS   = 10\n\n# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and\n# collaboration graphs will show the relations between templates and their\n# instances.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nTEMPLATE_RELATIONS     = NO\n\n# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to\n# YES then doxygen will generate a graph for each documented file showing the\n# direct and indirect include dependencies of the file with other documented\n# files.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDE_GRAPH          = YES\n\n# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are\n# set to YES then doxygen will generate a graph for each documented file showing\n# the direct and indirect include dependencies of the file with other documented\n# files.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDED_BY_GRAPH      = YES\n\n# If the CALL_GRAPH tag is set to YES then doxygen will generate a call\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable call graphs for selected\n# functions only using the \\callgraph command. Disabling a call graph can be\n# accomplished by means of the command \\hidecallgraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALL_GRAPH             = NO\n\n# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable caller graphs for selected\n# functions only using the \\callergraph command. Disabling a caller graph can be\n# accomplished by means of the command \\hidecallergraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALLER_GRAPH           = NO\n\n# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical\n# hierarchy of all classes instead of a textual one.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGRAPHICAL_HIERARCHY    = YES\n\n# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the\n# dependencies a directory has on other directories in a graphical way. The\n# dependency relations are determined by the #include relations between the\n# files in the directories.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDIRECTORY_GRAPH        = YES\n\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images\n# generated by dot. For an explanation of the image formats see the section\n# output formats in the documentation of the dot tool (Graphviz (see:\n# http://www.graphviz.org/)).\n# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order\n# to make the SVG files visible in IE 9+ (other browsers do not have this\n# requirement).\n# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,\n# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,\n# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,\n# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and\n# png:gdiplus:gdiplus.\n# The default value is: png.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_IMAGE_FORMAT       = png\n\n# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to\n# enable generation of interactive SVG images that allow zooming and panning.\n#\n# Note that this requires a modern browser other than Internet Explorer. Tested\n# and working are Firefox, Chrome, Safari, and Opera.\n# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make\n# the SVG files visible. Older versions of IE do not have SVG support.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINTERACTIVE_SVG        = NO\n\n# The DOT_PATH tag can be used to specify the path where the dot tool can be\n# found. If left blank, it is assumed the dot tool can be found in the path.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_PATH               =\n\n# The DOTFILE_DIRS tag can be used to specify one or more directories that\n# contain dot files that are included in the documentation (see the \\dotfile\n# command).\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOTFILE_DIRS           =\n\n# The MSCFILE_DIRS tag can be used to specify one or more directories that\n# contain msc files that are included in the documentation (see the \\mscfile\n# command).\n\nMSCFILE_DIRS           =\n\n# The DIAFILE_DIRS tag can be used to specify one or more directories that\n# contain dia files that are included in the documentation (see the \\diafile\n# command).\n\nDIAFILE_DIRS           =\n\n# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the\n# path where java can find the plantuml.jar file. If left blank, it is assumed\n# PlantUML is not used or called during a preprocessing step. Doxygen will\n# generate a warning when it encounters a \\startuml command in this case and\n# will not generate output for the diagram.\n\nPLANTUML_JAR_PATH      =\n\n# When using plantuml, the specified paths are searched for files specified by\n# the !include statement in a plantuml block.\n\nPLANTUML_INCLUDE_PATH  =\n\n# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes\n# that will be shown in the graph. If the number of nodes in a graph becomes\n# larger than this value, doxygen will truncate the graph, which is visualized\n# by representing a node as a red box. Note that doxygen if the number of direct\n# children of the root node in a graph is already larger than\n# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that\n# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.\n# Minimum value: 0, maximum value: 10000, default value: 50.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_GRAPH_MAX_NODES    = 50\n\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs\n# generated by dot. A depth value of 3 means that only nodes reachable from the\n# root by following a path via at most 3 edges will be shown. Nodes that lay\n# further from the root node will be omitted. Note that setting this option to 1\n# or 2 may greatly reduce the computation time needed for large code bases. Also\n# note that the size of a graph can be further restricted by\n# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.\n# Minimum value: 0, maximum value: 1000, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nMAX_DOT_GRAPH_DEPTH    = 0\n\n# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent\n# background. This is disabled by default, because dot on Windows does not seem\n# to support this out of the box.\n#\n# Warning: Depending on the platform used, enabling this option may lead to\n# badly anti-aliased labels on the edges of a graph (i.e. they become hard to\n# read).\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_TRANSPARENT        = NO\n\n# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output\n# files in one run (i.e. multiple -o and -T options on the command line). This\n# makes dot run faster, but since only newer versions of dot (>1.8.10) support\n# this, this feature is disabled by default.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_MULTI_TARGETS      = NO\n\n# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page\n# explaining the meaning of the various boxes and arrows in the dot generated\n# graphs.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGENERATE_LEGEND        = YES\n\n# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot\n# files that are used to generate the various graphs.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_CLEANUP            = YES\n"
  },
  {
    "path": "doc/cpp/DoxygenLayout.xml",
    "content": "<doxygenlayout version=\"1.0\">\n  <!-- Customized for gtirb C++ API based on doxygen 1.8.14 -->\n  <!-- Navigation index tabs for HTML output -->\n  <navindex>\n    <tab type=\"mainpage\" visible=\"yes\" title=\"C++ API Home\"/>\n    <tab type=\"user\" visible=\"yes\" title=\"GTIRB Home\" url=\"../index.html\"/>\n    <tab type=\"classes\" visible=\"yes\" title=\"C++ API Details\">\n      <tab type=\"classlist\" visible=\"yes\" title=\"\" intro=\"\"/>\n      <tab type=\"classindex\" visible=\"$ALPHABETICAL_INDEX\" title=\"\"/>\n      <tab type=\"hierarchy\" visible=\"yes\" title=\"\" intro=\"\"/>\n      <tab type=\"classmembers\" visible=\"yes\" title=\"\" intro=\"\"/>\n      <tab type=\"modules\" visible=\"yes\" title=\"\" intro=\"\"/>\n      <tab type=\"namespacelist\" visible=\"yes\" title=\"\" intro=\"\"/>\n      <tab type=\"namespacemembers\" visible=\"yes\" title=\"\" intro=\"\"/>\n      <tab type=\"filelist\" visible=\"yes\" title=\"\" intro=\"\"/>\n      <tab type=\"globals\" visible=\"yes\" title=\"\" intro=\"\"/>\n    </tab>\n    <tab type=\"user\" visible=\"yes\" title=\"API Component Descriptions\" url=\"../md__c_o_m_p_o_n_e_n_t_s.html\"/>\n  </navindex>\n\n  <!-- Layout definition for a class page -->\n  <class>\n    <briefdescription visible=\"yes\"/>\n    <includes visible=\"$SHOW_INCLUDE_FILES\"/>\n    <inheritancegraph visible=\"$CLASS_GRAPH\"/>\n    <collaborationgraph visible=\"$COLLABORATION_GRAPH\"/>\n    <memberdecl>\n      <nestedclasses visible=\"yes\" title=\"\"/>\n      <publictypes title=\"\"/>\n      <services title=\"\"/>\n      <interfaces title=\"\"/>\n      <publicslots title=\"\"/>\n      <signals title=\"\"/>\n      <publicmethods title=\"\"/>\n      <publicstaticmethods title=\"\"/>\n      <publicattributes title=\"\"/>\n      <publicstaticattributes title=\"\"/>\n      <protectedtypes title=\"\"/>\n      <protectedslots title=\"\"/>\n      <protectedmethods title=\"\"/>\n      <protectedstaticmethods title=\"\"/>\n      <protectedattributes title=\"\"/>\n      <protectedstaticattributes title=\"\"/>\n      <packagetypes title=\"\"/>\n      <packagemethods title=\"\"/>\n      <packagestaticmethods title=\"\"/>\n      <packageattributes title=\"\"/>\n      <packagestaticattributes title=\"\"/>\n      <properties title=\"\"/>\n      <events title=\"\"/>\n      <privatetypes title=\"\"/>\n      <privateslots title=\"\"/>\n      <privatemethods title=\"\"/>\n      <privatestaticmethods title=\"\"/>\n      <privateattributes title=\"\"/>\n      <privatestaticattributes title=\"\"/>\n      <friends title=\"\"/>\n      <related title=\"\" subtitle=\"\"/>\n      <membergroups visible=\"yes\"/>\n    </memberdecl>\n    <detaileddescription title=\"\"/>\n    <memberdef>\n      <inlineclasses title=\"\"/>\n      <typedefs title=\"\"/>\n      <enums title=\"\"/>\n      <services title=\"\"/>\n      <interfaces title=\"\"/>\n      <constructors title=\"\"/>\n      <functions title=\"\"/>\n      <related title=\"\"/>\n      <variables title=\"\"/>\n      <properties title=\"\"/>\n      <events title=\"\"/>\n    </memberdef>\n    <allmemberslink visible=\"yes\"/>\n    <usedfiles visible=\"$SHOW_USED_FILES\"/>\n    <authorsection visible=\"yes\"/>\n  </class>\n\n  <!-- Layout definition for a namespace page -->\n  <namespace>\n    <briefdescription visible=\"yes\"/>\n    <memberdecl>\n      <nestednamespaces visible=\"yes\" title=\"\"/>\n      <constantgroups visible=\"yes\" title=\"\"/>\n      <classes visible=\"yes\" title=\"\"/>\n      <typedefs title=\"\"/>\n      <enums title=\"\"/>\n      <functions title=\"\"/>\n      <variables title=\"\"/>\n      <membergroups visible=\"yes\"/>\n    </memberdecl>\n    <detaileddescription title=\"\"/>\n    <memberdef>\n      <inlineclasses title=\"\"/>\n      <typedefs title=\"\"/>\n      <enums title=\"\"/>\n      <functions title=\"\"/>\n      <variables title=\"\"/>\n    </memberdef>\n    <authorsection visible=\"yes\"/>\n  </namespace>\n\n  <!-- Layout definition for a file page -->\n  <file>\n    <briefdescription visible=\"yes\"/>\n    <includes visible=\"$SHOW_INCLUDE_FILES\"/>\n    <includegraph visible=\"$INCLUDE_GRAPH\"/>\n    <includedbygraph visible=\"$INCLUDED_BY_GRAPH\"/>\n    <sourcelink visible=\"yes\"/>\n    <memberdecl>\n      <classes visible=\"yes\" title=\"\"/>\n      <namespaces visible=\"yes\" title=\"\"/>\n      <constantgroups visible=\"yes\" title=\"\"/>\n      <defines title=\"\"/>\n      <typedefs title=\"\"/>\n      <enums title=\"\"/>\n      <functions title=\"\"/>\n      <variables title=\"\"/>\n      <membergroups visible=\"yes\"/>\n    </memberdecl>\n    <detaileddescription title=\"\"/>\n    <memberdef>\n      <inlineclasses title=\"\"/>\n      <defines title=\"\"/>\n      <typedefs title=\"\"/>\n      <enums title=\"\"/>\n      <functions title=\"\"/>\n      <variables title=\"\"/>\n    </memberdef>\n    <authorsection/>\n  </file>\n\n  <!-- Layout definition for a group page -->\n  <group>\n    <briefdescription visible=\"yes\"/>\n    <groupgraph visible=\"$GROUP_GRAPHS\"/>\n    <memberdecl>\n      <nestedgroups visible=\"yes\" title=\"\"/>\n      <dirs visible=\"yes\" title=\"\"/>\n      <files visible=\"yes\" title=\"\"/>\n      <namespaces visible=\"yes\" title=\"\"/>\n      <classes visible=\"yes\" title=\"\"/>\n      <defines title=\"\"/>\n      <typedefs title=\"\"/>\n      <enums title=\"\"/>\n      <enumvalues title=\"\"/>\n      <functions title=\"\"/>\n      <variables title=\"\"/>\n      <signals title=\"\"/>\n      <publicslots title=\"\"/>\n      <protectedslots title=\"\"/>\n      <privateslots title=\"\"/>\n      <events title=\"\"/>\n      <properties title=\"\"/>\n      <friends title=\"\"/>\n      <membergroups visible=\"yes\"/>\n    </memberdecl>\n    <detaileddescription title=\"\"/>\n    <memberdef>\n      <pagedocs/>\n      <inlineclasses title=\"\"/>\n      <defines title=\"\"/>\n      <typedefs title=\"\"/>\n      <enums title=\"\"/>\n      <enumvalues title=\"\"/>\n      <functions title=\"\"/>\n      <variables title=\"\"/>\n      <signals title=\"\"/>\n      <publicslots title=\"\"/>\n      <protectedslots title=\"\"/>\n      <privateslots title=\"\"/>\n      <events title=\"\"/>\n      <properties title=\"\"/>\n      <friends title=\"\"/>\n    </memberdef>\n    <authorsection visible=\"yes\"/>\n  </group>\n\n  <!-- Layout definition for a directory page -->\n  <directory>\n    <briefdescription visible=\"yes\"/>\n    <directorygraph visible=\"yes\"/>\n    <memberdecl>\n      <dirs visible=\"yes\"/>\n      <files visible=\"yes\"/>\n    </memberdecl>\n    <detaileddescription title=\"\"/>\n  </directory>\n</doxygenlayout>\n"
  },
  {
    "path": "doc/cpp/README.md",
    "content": "# Using the C++ Library\n\nWe have provided several C++ examples in directory\n`gtirb/doc/examples`. See the [Examples page](../examples.html) for more\ninformation.\n\nThe remainder of this section provides examples walking through common\ntasks using the GTIRB C++ library API.\n\n- [Using the C++ Library](#using-the-c-library)\n  - [Building](#building)\n    - [Requirements](#requirements)\n    - [Building on Windows](#building-on-windows)\n    - [As a dependency](#as-a-dependency)\n  - [Using the API](#using-the-api)\n\n## Building\n\n### Requirements\n\nTo build and install GTIRB, the following requirements should be installed in addition to the [common requirements](../../README.md#requirements):\n\n- [Boost](https://www.boost.org/), version 1.68.0 or later.\n  - No version of Ubuntu provides this version of Boost yet; you must build it from source.\n\n### Building on Windows\n\nCMake can optionally use a toolchain file, as generated by\n[Microsoft's vcpkg](https://github.com/Microsoft/vcpkg), to find packages like\nboost or protobuf on Windows. One way to install GTIRB's dependencies is to run\n`vcpkg` before running `cmake`:\n\n```\nvcpkg.exe install --triplet x64-windows protobuf boost\n```\n\nand pass the path to the toolchain file when executing the CMake command above:\n\n```\n    -DCMAKE_TOOLCHAIN_FILE=\"C:\\path\\to\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake\"\n```\n\n### As a dependency\n\nNote that, to compile a C++ client that uses the GTIRB library,\nyou have to inform the compiler and linker where to find GTIRB's\nheader files and library archives. In addition, the OS also needs to\nbe informed about where to find GTIRB's dynamic libraries. These files\nare located under `include` and `lib` in the build output directory\nyou picked when running CMake originally. How to do this will depend\non the particular compiler tool chain and context you are working\nwith.\n\nIf the C++ client in question also uses CMake, then it can find gtirb as a dependency by adding this to thier `CMakeLists.txt`:\n\n```cmake\nfind_package(gtirb REQUIRED)\n```\n\nOn Linux systems, If GTIRB was installed (perhaps via `make install` or via APT package),\nusing GTIRB as a library is as simple as specifying `-lgtirb` or similar on your C compiler's command line.\n\nIf you choose to install a static build of GTIRB (via `-DGTIRB_BUILD_SHARED_LIBS=OFF`),\nthen you must provide `-lgtirb_proto` on your command line as well as `-lgtirb`.\n\n## Using the API\n\nSee [api-walkthrough.cpp](../api-walkthrough_8cpp-example.html) (in\nthe repository at `gtirb/doc/examples/api-walkthrough.cpp`) for a\nbasic introduction to using the GTIRB API in C++.\n\n## Iteration Order\n\\anchor iteration_order\n\n### Blocks\n\nIterating over blocks on a ByteInterval will yield them in order of offset,\nsize, kind, decode mode, and UUID. Iterating over blocks on other containers,\nsuch as Section or Module, will yield them in order of address, size, kind,\ndecode mode, and UUID.\n\n### Sections and ByteIntervals\n\nIterating over Sections or ByteIntervals will yield them in order of address,\nsize, and UUID.\n\n### Iterator Invalidation\n\nAltering a property that affects sort order will not cause iterators to be\ninvalidated. However, it may cause objects to be visited more than once or\nto be skipped completely.\n"
  },
  {
    "path": "doc/dot/gtirb.dot",
    "content": ""
  },
  {
    "path": "doc/examples/CMakeLists.txt",
    "content": "if(CL_API)\n  list(APPEND EXAMPLE_FILES_IN \"${CMAKE_CURRENT_SOURCE_DIR}/cfg-paths.lisp\"\n              \"${CMAKE_CURRENT_SOURCE_DIR}/data-symbols.lisp\"\n              \"${CMAKE_CURRENT_SOURCE_DIR}/show-cfg.lisp\"\n  )\nendif(CL_API)\n\nif(CXX_API)\n  include_directories(\"${CMAKE_SOURCE_DIR}/include\")\n  # Find protobuf generated headers in the build directory\n  include_directories(\"${CMAKE_BINARY_DIR}/src/\")\n  # Find our version.h header file\n  include_directories(\"${CMAKE_BINARY_DIR}/include\")\n\n  # Suppress warning from protobuf headers.\n  if(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)\n    add_compile_options(-wd4100)\n  endif()\n\n  add_executable(ex-api-walkthrough api-walkthrough.cpp)\n  target_link_libraries(ex-api-walkthrough gtirb)\n  target_compile_definitions(\n    ex-api-walkthrough PRIVATE GTIRB_WRAP_UTILS_IN_NAMESPACE\n  )\n\n  add_executable(ex-data-symbols data-symbols.cpp)\n  target_link_libraries(ex-data-symbols gtirb)\n  target_compile_definitions(\n    ex-data-symbols PRIVATE GTIRB_WRAP_UTILS_IN_NAMESPACE\n  )\n\n  add_executable(ex-cfg-paths cfg-paths.cpp)\n  target_link_libraries(ex-cfg-paths gtirb)\n  target_compile_definitions(ex-cfg-paths PRIVATE GTIRB_WRAP_UTILS_IN_NAMESPACE)\n\n  add_executable(ex-functions functions.cpp)\n  target_link_libraries(ex-functions gtirb)\n  target_compile_definitions(ex-functions PRIVATE GTIRB_WRAP_UTILS_IN_NAMESPACE)\n\n  find_library(CAPSTONE NAMES capstone)\n  if(CAPSTONE)\n    add_executable(ex-jumps jumps.cpp)\n    target_link_libraries(ex-jumps gtirb ${CAPSTONE})\n    target_compile_definitions(ex-jumps PRIVATE GTIRB_WRAP_UTILS_IN_NAMESPACE)\n  endif()\n\n  list(\n    APPEND EXAMPLE_FILES_IN\n           \"${CMAKE_CURRENT_SOURCE_DIR}/api-walkthrough.cpp\"\n           \"${CMAKE_CURRENT_SOURCE_DIR}/cfg-paths.cpp\"\n           \"${CMAKE_CURRENT_SOURCE_DIR}/data-symbols.cpp\"\n           \"${CMAKE_CURRENT_SOURCE_DIR}/functions.cpp\"\n           \"${CMAKE_CURRENT_SOURCE_DIR}/jumps.cpp\"\n  )\nendif(CXX_API)\n\nif(JAVA_API)\n  list(APPEND EXAMPLE_FILES_IN \"${CMAKE_CURRENT_SOURCE_DIR}/cfgpaths.java\"\n              \"${CMAKE_CURRENT_SOURCE_DIR}/datasymbols.java\"\n  )\nendif(JAVA_API)\n\nif(PY_API)\n  list(APPEND EXAMPLE_FILES_IN \"${CMAKE_CURRENT_SOURCE_DIR}/cfg-paths.py\"\n              \"${CMAKE_CURRENT_SOURCE_DIR}/data-symbols.py\"\n              \"${CMAKE_CURRENT_SOURCE_DIR}/show-cfg.py\"\n  )\nendif(PY_API)\n\nmacro(move_filename file_list newdir)\n  foreach(src_file ${${file_list}})\n    get_filename_component(src_file_name \"${src_file}\" NAME)\n    list(REMOVE_ITEM ${file_list} \"${src_file}\")\n    list(APPEND ${file_list} \"${newdir}/${src_file_name}\")\n  endforeach()\nendmacro()\n\nset(EXAMPLE_FILES ${EXAMPLE_FILES_IN})\nmove_filename(EXAMPLE_FILES ${CMAKE_CURRENT_BINARY_DIR})\n\nif(NOT \"${CMAKE_CURRENT_SOURCE_DIR}\" STREQUAL \"${CMAKE_CURRENT_BINARY_DIR}\")\n  foreach(_inmd ${EXAMPLE_FILES_IN})\n    get_filename_component(_outmd \"${_inmd}\" NAME)\n    add_custom_command(\n      OUTPUT ${_outmd}\n      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}\n      DEPENDS ${_inmd}\n      COMMAND ${CMAKE_COMMAND} -E copy ${_inmd} \"${_outmd}\"\n      COMMENT \"copying ${_outmd}\"\n      VERBATIM\n    )\n  endforeach()\nendif()\n\nadd_custom_target(\n  doc_examples\n  DEPENDS ${EXAMPLE_FILES}\n  COMMENT \"copying examples to output\"\n  VERBATIM\n)\n\nadd_dependencies(doc doc_examples)\n"
  },
  {
    "path": "doc/examples/api-walkthrough.cpp",
    "content": "#include <gtirb/gtirb.hpp>\n#include <boost/uuid/uuid_io.hpp>\n#include <fstream>\n#include <iostream>\n\nusing namespace gtirb;\n\nint main() {\n  // BEGIN\n  //\n  // ### Initialization for AuxData usage\n  //\n  // To make use of the auxiliary data mechanism, each schema that is\n  // intended to be used must be registered with the API before doing\n  // anything else with GTIRB. Typically, this is easiest to do as one\n  // of the first steps in main().\n  AuxDataContainer::registerAuxDataType<gtirb::schema::Types>();\n  //\n  // ### Populating the IR\n  //\n  // GTIRB representation objects have class `gtirb::IR`, and are created within\n  // a context object (`gtirb::Context`). Freeing the context will also destroy\n  // all the objects within it.\n  Context C;\n  auto* Ir = IR::Create(C);\n\n  // Every IR holds a set of modules (`gtirb::Module`).\n  auto* M = Module::Create(C, \"example\");\n  Ir->addModule(M);\n  // Could also have written: auto* M = Ir->addModule(C);\n\n  // Every module holds a set of sections (`gtirb::Section`).\n  auto* S = Section::Create(C, \".text\");\n  M->addSection(S);\n  // Could also have written: auto* S = M->addSection(C, \".text\");\n\n  // Every section has a set of byte intervals (`gtirb::ByteInterval`).\n  auto* BI = ByteInterval::Create(C, Addr(2048), 466);\n  S->addByteInterval(BI);\n  // Could also have written: auto* BI = S->addByteInterval(C, Addr(2048), 466);\n\n  // Create some data objects. These only define the layout and do not directly\n  // store any data.\n  auto* D1 = DataBlock::Create(C, 6);\n  BI->addBlock(0, D1);\n  auto* D2 = DataBlock::Create(C, 2);\n  BI->addBlock(6, D2);\n  // The actual data is stored in the blocks' byte interval:\n  std::array<uint8_t, 8> Bytes{1, 0, 2, 0, 115, 116, 114, 108};\n  BI->insertBytes(const_cast<const ByteInterval*>(BI)->bytes_begin<uint8_t>(),\n                  Bytes.begin(), Bytes.end());\n  // Symbols (`gtirb::Symbol`) associate a name with a block in the IR, such as\n  // code blocks, data blocks, or proxy blocks. They can optionally store an\n  // address instead.\n  [[maybe_unused]] auto* Sym1 = M->addSymbol(Symbol::Create(C, D1, \"data1\"));\n  [[maybe_unused]] auto* Sym2 = M->addSymbol(Symbol::Create(C, D2, \"data2\"));\n  // GTIRB can store multiple symbols with the same address or referent.\n  M->addSymbol(Symbol::Create(C, D2, \"duplicateReferent\"));\n  M->addSymbol(Symbol::Create(C, Addr(2048), \"duplicateName\"));\n  M->addSymbol(Symbol::Create(C, Addr(4096), \"duplicateName\"));\n  // Basic blocks are stored as `gtirb::CodeBlock`s. Like data blocks, code\n  // blocks reference data in a byte interval but do not directly hold any data\n  // themselves. GTIRB does not directly represent instructions.\n  auto* B1 = CodeBlock::Create(C, 4);\n  BI->addBlock(12, B1);\n  auto* B2 = CodeBlock::Create(C, 6);\n  BI->addBlock(16, B2);\n  // GTIRB has an interprocedural control flow graph (`gtirb::CFG`) to track\n  // relations between code blocks. The `CFG` can be populated with edges to\n  // denote control flow.\n  auto& Cfg = Ir->getCFG();\n  auto E = *addEdge(B1, B2, Cfg);\n  // Edges can have labels, indicating the type of control flow:\n  Cfg[E] = std::make_tuple(ConditionalEdge::OnFalse, DirectEdge::IsDirect,\n                           EdgeType::Fallthrough);\n  // Symbolic expressions indicate that the value of a range of bytes depends on\n  // the value of a symbol.\n  BI->addSymbolicExpression(14, SymAddrConst{0, Sym1});\n  // Finally, auxiliary data can be used to store additional information at the\n  // IR and module level. A `gtirb::AuxData` object can store integers, strings,\n  // GTIRB types such as `gtirb::Addr` and `gtirb::UUID`, and various containers\n  // over these types. There are predefined AuxData schema for you to use, but\n  // you can also use your own custom AuxData schema. Here is use of a\n  // predefined schema, `gtirb::schema::Types`:\n  M->addAuxData<gtirb::schema::Types>(\n      {{D1->getUUID(), \"string\"}, {D2->getUUID(), \"uleb128\"}});\n  //\n  // ### Querying the IR\n  //\n  // Symbols can be looked up by address or name.  Any number of symbols can\n  // share an address or name, so be prepared to deal with multiple results.\n  for (const auto& Sym : M->findSymbols(Addr(2054))) {\n    [[maybe_unused]] const auto& _ = Sym;\n    assert(Sym.getAddress() == Addr(2054));\n    assert(Sym.getName() == \"data2\" || Sym.getName() == \"duplicateReferent\");\n    assert(Sym.getReferent<DataBlock>() == nullptr ||\n           Sym.getReferent<DataBlock>() == D2);\n  }\n  for (const auto& Sym : M->findSymbols(\"duplicateName\")) {\n    [[maybe_unused]] const auto& _ = Sym;\n    assert(Sym.getName() == \"duplicateName\");\n    assert(Sym.getAddress() == Addr(2048) || Sym.getAddress() == Addr(4096));\n  }\n  // Use a symbol's referent (either a Block or DataObject) to get more\n  // information about the object to which the symbol points.\n  [[maybe_unused]] auto* Referent = Sym1->getReferent<DataBlock>();\n  assert(Referent != nullptr);\n  assert(Referent->getAddress() == Addr(2054));\n  assert(Referent->getSize() == 2);\n  assert(Referent->getByteInterval() == BI);\n  assert(Referent->getOffset() == 6);\n  // Alternatively, blocks can be looked up by an address contained within the\n  // object. Any number of blocks may overlap and contain an address, so be\n  // prepared to deal with multiple results.\n  auto Blocks = M->findBlocksAt(Addr(2048), Addr(4096));\n  assert(std::distance(Blocks.begin(), Blocks.end()) == 4);\n  // The CFG uses\n  // [boost::graph](https://www.boost.org/doc/libs/1_68_0/libs/graph/doc/).\n  // GTIRB also provides a convenience function for iterating over blocks:\n  for (const auto& B : blocks(Cfg)) {\n    std::cout << \"Block at address \" << B.getAddress() << std::endl;\n  }\n  // To use boost::graph directly, you'll need to convert blocks into\n  // `vertex_descriptor`s:\n  auto [VerticesBegin, VerticesEnd] = boost::vertices(Cfg);\n  for (const auto& Vertex :\n       boost::make_iterator_range(VerticesBegin, VerticesEnd)) {\n    if (Cfg[Vertex] == B2) {\n      std::cout << \"B2's vertex descriptor is: \" << Vertex << std::endl;\n    }\n  }\n  // And once you have those, you can use `edge_descriptor`s to look up labels\n  // and the source/target blocks:\n  auto [EdgesBegin, EdgesEnd] = boost::edges(Cfg);\n  for (const auto& Edge : boost::make_iterator_range(EdgesBegin, EdgesEnd)) {\n    auto V1 = boost::source(Edge, Cfg);\n    auto V2 = boost::target(Edge, Cfg);\n    std::cout << \"Edge: \" << Cfg[V1] << \" => \" << Cfg[V2] << std::endl;\n\n    auto Label = *Cfg[Edge];\n    std::cout << \"Conditional? \"\n              << (std::get<ConditionalEdge>(Label) == ConditionalEdge::OnTrue)\n              << std::endl;\n    std::cout << \"Direct? \"\n              << (std::get<DirectEdge>(Label) == DirectEdge::IsDirect)\n              << std::endl;\n    std::cout << \"Fallthrough? \"\n              << (std::get<EdgeType>(Label) == EdgeType::Fallthrough)\n              << std::endl;\n  }\n  // Aux data can be retrieved based on the schema and queried upon.\n  auto* typesMap = M->getAuxData<gtirb::schema::Types>();\n  if (typesMap) {\n    for (const auto& [DataBlockID, BlockType] : *typesMap) {\n      std::cout << \"Data block with UUID \" << DataBlockID << \" is of type \"\n                << BlockType << \"!\";\n    }\n  }\n  //\n  // ### Serialization\n  //\n  // Serialize IR to a file with `gtirb::IR::save`.\n  std::ofstream Out(\"path/to/file\");\n  Ir->save(Out);\n  // Deserialize from a file with `gtirb::IR::load`.\n  std::ifstream In(\"path/to/file\");\n  [[maybe_unused]] auto& NewIR = *IR::load(C, In);\n  // END\n  return 0;\n}\n"
  },
  {
    "path": "doc/examples/cfg-paths.cpp",
    "content": "// An example program which opens an IR and prints every control-flow path\n// from some basic block to another basic block.\n\n#include <gtirb/gtirb.hpp>\n#include <fstream>\n#include <iomanip>\n#include <iostream>\n#include <set>\n#include <vector>\n\nusing namespace gtirb;\n\n// Print Addrs in hex format\nstd::ostream& operator<<(std::ostream& Os, Addr A) {\n  auto Flags = Os.flags();\n  Os << \"0x\" << std::hex << std::setw(8) << std::setfill('0') << uint64_t(A);\n  Os.flags(Flags);\n  return Os;\n}\n\n// Depth-first search of a graph, printing all paths between two given vertices.\n// boost::graph::depth_first_search is not a good fit for this, because we\n// need to visit nodes multiple times (while still avoiding cycles). So we\n// have to implement our own.\nclass PrintPathsVisitor {\npublic:\n  using Vertex = CFG::vertex_descriptor;\n\n  PrintPathsVisitor(const CFG& G, const CodeBlock& B)\n      : Graph(G), Target(*getVertex(&B, G)) {}\n\n  void visit(Vertex V) {\n    // Mark as visited to avoid cycles\n    Visited.insert(V);\n\n    // At target, print the path\n    if (V == Target) {\n      for (auto U : Path) {\n        std::cout << dyn_cast<CodeBlock>(Graph[U])->getAddress() << \", \";\n      }\n      std::cout << dyn_cast<CodeBlock>(Graph[Target])->getAddress() << \"\\n\";\n    } else {\n      // Otherwise, extend the path and keep searching.\n      Path.push_back(V);\n      // Check all outgoing edges from this vertex\n      auto [Begin, End] = out_edges(V, Graph);\n      for (auto It = Begin; It != End; It++) {\n        // If edge target has not been visited, do so now\n        auto T = target(*It, Graph);\n        if (Visited.find(T) == Visited.end()) {\n          visit(T);\n        }\n      }\n      Path.pop_back();\n    }\n\n    // Unmark the node so it can be visited again in other paths.\n    Visited.erase(V);\n  }\n\n  const CFG& Graph;\n  Vertex Target;\n  std::vector<Vertex> Path;\n  std::set<Vertex> Visited;\n};\n\nint main(int argc, char** argv) {\n  // Create a context to manage memory for gtirb objects\n  Context C;\n\n  // Load the IR\n  IR* I = nullptr;\n\n  if (argc == 4) {\n    std::ifstream in(argv[1]);\n    if (auto IoE = IR::load(C, in); IoE)\n      I = *IoE;\n  }\n\n  if (!I)\n    return EXIT_FAILURE;\n\n  // Addresses of source and target blocks\n  Addr Source(std::stoul(argv[2], nullptr, 16));\n  Addr Target(std::stoul(argv[3], nullptr, 16));\n\n  // Search for the requested blocks in the first module\n  const auto& Mod = *I->modules_begin();\n  const auto& Cfg = I->getCFG();\n  const CodeBlock *SourceBlock, *TargetBlock;\n\n  if (auto Range = Mod.findCodeBlocksAt(Source); !Range.empty()) {\n    SourceBlock = &*Range.begin();\n  } else {\n    std::cerr << \"No block at source address \" << Source << \"\\n\";\n    exit(EXIT_FAILURE);\n  }\n\n  if (auto Range = Mod.findCodeBlocksAt(Target); !Range.empty()) {\n    TargetBlock = &*Range.begin();\n  } else {\n    std::cerr << \"No block at target address \" << Target << \"\\n\";\n    exit(EXIT_FAILURE);\n  }\n\n  std::cout << \"Paths from \" << SourceBlock->getAddress() << \" to \"\n            << TargetBlock->getAddress() << \"\\n\";\n  // Print paths\n  PrintPathsVisitor(Cfg, *TargetBlock).visit(*getVertex(SourceBlock, Cfg));\n  return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "doc/examples/cfg-paths.lisp",
    "content": ";;;; cfg-paths.lisp --- Print the shortest path between two blocks\n;;;\n;;; To run this example, do the following.\n;;;\n;;; 1. Install all required packages with quicklisp.\n;;;\n;;;    NOTE: you might need to install the :graph library from source\n;;;          as the `all-paths' function isn't in the quicklisp\n;;;          version at the time  of writing of this example.\n;;;\n;;;    (mapcar #'ql:quickload '(:gt :gtirb :graph)\n;;;\n;;; 2. Run ddisasm to disassemble a binary to GTIRB.\n;;;\n;;;    $ echo 'main(){puts(\"hello world\");}'|gcc -x c - -o /tmp/hello\n;;;    $ ddisasm /tmp/hello --ir /tmp/hello.gtirb\n;;;\n;;; 3. Evaluate this file using the path of the GTIRB file produced by\n;;;    ddisasm and the addresses of two basic blocks.\n;;;\n(defpackage :cfg-paths\n  (:use :gt :gtirb :graph)\n  (:shadow :symbol :size :copy))\n(in-package :cfg-paths)\n\n(defun cfg-paths (path from to)\n  \"Return all paths in the cfg of the GTIRB file from FROM to TO.\nFROM and TO are the addresses of the start of blocks.\"\n  (let ((ir (read-gtirb path)))\n    (flet ((block-uuid-at (address)\n             (uuid (find-if (lambda (it) (typep it 'code-block))\n                            (at-address ir address)))))\n      (all-paths (cfg ir) (block-uuid-at from) (block-uuid-at to)))))\n"
  },
  {
    "path": "doc/examples/cfg-paths.py",
    "content": "#!/usr/bin/python\n#\n# An example program which opens an IR and prints all paths between\n# two blocks.\n#\n# To run this example, do the following.\n#\n# 1. Install the gtirb package from Pypi.\n#\n# 2. Run ddisasm to disassemble a binary to GTIRB.\n#\n#    $ echo 'main(){puts(\"hello world\");}'|gcc -x c - -o /tmp/hello\n#    $ ddisasm /tmp/hello --ir /tmp/hello.gtirb\n#\n# 3. Execute the following command to run the program on the\n#    serialized GTIRB data.\n#\n#    $ ./doc/examples/cfg-paths.py /tmp/hello.gtirb\nimport sys\n\nimport networkx as nx\n\nimport gtirb\n\nif len(sys.argv) < 4:\n    print(f\"Usage: {sys.argv[0]} /path/to/file.gtirb source target\")\n    quit(1)\n\nir = gtirb.ir.IR.load_protobuf(sys.argv[1])\nG = nx.DiGraph()\n\nfor edge in ir.cfg:\n    if isinstance(edge.target, gtirb.block.ProxyBlock):\n        # Represent ProxyBlocks (which don't have an address) with their UUID.\n        G.add_edge(edge.source.address, edge.target.uuid)\n    else:\n        G.add_edge(edge.source.address, edge.target.address)\n\nfor path in nx.all_simple_paths(G, int(sys.argv[2]), int(sys.argv[3])):\n    print(path)\n"
  },
  {
    "path": "doc/examples/cfgpaths.java",
    "content": "// An example program which opens an IR and prints every control-flow\n// path from some basic block to another basic block.\n//\n// To run this example, do the following.\n//\n// 1. Install the protobuf compiler (protoc) from\n//    https://github.com/protocolbuffers/protobuf/releases (if you have\n//    not already done so).\n//\n// 2. Download the protobuf Java runtime from\n//    https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java\n//    and save it somewhere suitable.\n//\n// 3. Generate Java message definitions.\n//\n//    $ mkdir -p java $ for f in src/proto/*.proto; do\n//         protoc -Isrc/proto --java_out=java $f\n//      done\n//\n//    This will create a subdirectory java/proto/, containing a\n//    number of files with names of the form <bn>OuterClass.java:\n//    one for each <bn>.proto in src/proto/.\n//\n// 4. Compile the Java message definitions, making sure the protobuf\n//    Java runtime .jar file is in your CLASSPATH.\n//\n//    $ mkdir -p java/classfiles\n//    $ CLASSPATH=<path/to/protobuf_jar> \\\n//         javac -d java/classfiles java/proto/*.java\n//\n// 5. Compile the datasymbols class defined in this file, making sure\n//    your CLASSPATH contains both the Java runtime .jar file and the\n//    compiled Java message definition classes.\n//    (Note that the path separator is OS-dependent.)\n//\n//    $ CLASSPATH=<path/to/protobuf_jar>:./java/classfiles/ \\\n//         javac doc/examples/cfgpaths.java\n//\n// 6. Execute the following command to run the program on the\n//    serialized GTIRB data located at <path-to-ir> printing every\n//    control-flow path between the block with address <source-addr>\n//    and the block with address <target-addr>.\n//\n//    $  CLASSPATH=<path/to/protobuf_jar>:./java/classfiles/:doc/examples/ \\\n//          java cfgpaths <path-to-ir>  <source-addr> <target-addr>\n\nimport com.google.protobuf.ByteString;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.PrintStream;\nimport java.lang.Long;\nimport java.util.*;\nimport proto.BlockOuterClass.Block;\nimport proto.CFGOuterClass.CFG;\nimport proto.CFGOuterClass.Edge;\nimport proto.IROuterClass.IR;\nimport proto.ModuleOuterClass.Module;\n\nclass cfgpaths {\n\n    // Avoid duplicated effort by caching the uuids of Blocks from\n    // which we have the target is unreachable.\n    static Set<ByteString> unreachability_cache = new HashSet<ByteString>();\n\n    // Print one path.\n    static void printPath(Stack<Long> path) {\n        Set<Long> pathset = new HashSet<Long>();\n        pathset.addAll(path);\n        //\tassert path.size() == pathset.size();\n        for (Long addr : path) {\n            System.out.print(String.format(\"0x%08X \", addr));\n        }\n        System.out.println();\n    }\n\n    // Use depth-first search to print all paths from the Block with\n    // uuid src to targ to the Block with uuid targ.\n    static int printPathsRec(ByteString src, ByteString targ,\n                             Map<ByteString, Block> blocks,\n                             Map<ByteString, Set<ByteString>> edges,\n                             Set<ByteString> visited, Stack<Long> path) {\n\n        int printed = 0;\n        path.push(blocks.get(src).getAddress());\n        visited.add(src);\n        if (src.equals(targ)) {\n            printPath(path);\n            printed = 1;\n        } else {\n            for (ByteString next : edges.get(src)) {\n                if (!visited.contains(next) &&\n                    !unreachability_cache.contains(next)) {\n                    printed +=\n                        printPathsRec(next, targ, blocks, edges, visited, path);\n                }\n            }\n        }\n        visited.remove(src);\n        path.pop();\n        if (printed == 0) {\n            unreachability_cache.add(src);\n        }\n        return printed;\n    }\n\n    // Print all paths from source to target in cfg.\n    static void printPaths(Block source, Block target, CFG cfg) {\n        Map<ByteString, Block> blocks = new HashMap<ByteString, Block>();\n        Map<ByteString, Set<ByteString>> edges =\n            new HashMap<ByteString, Set<ByteString>>();\n        Set<ByteString> visited = new HashSet<ByteString>();\n\n        for (Block b : cfg.getBlocksList()) {\n            blocks.put(b.getUuid(), b);\n            edges.put(b.getUuid(), new HashSet<ByteString>());\n        }\n\n        for (Edge e : cfg.getEdgesList()) {\n            edges.get(e.getSourceUuid()).add(e.getTargetUuid());\n        }\n\n        int numpaths =\n            printPathsRec(source.getUuid(), target.getUuid(), blocks, edges,\n                          new HashSet<ByteString>(), new Stack<Long>());\n        System.out.println(numpaths + \" paths found.\");\n    }\n\n    static Block findBlockByAddr(Long addr, CFG cfg) {\n        for (Block b : cfg.getBlocksList()) {\n            if (b.getAddress() == addr) {\n                return b;\n            }\n        }\n        return Block.getDefaultInstance();\n    }\n\n    public static void main(String[] args) {\n\n        IR ir = IR.getDefaultInstance();\n        Block defaultblock = Block.getDefaultInstance();\n        Block from_block = defaultblock;\n        Block to_block = defaultblock;\n        CFG cfg = CFG.getDefaultInstance();\n        boolean blocks_found = false;\n        Long from_addr = -1L;\n        Long to_addr = -1L;\n\n        if (args.length < 3) {\n            System.err.println(\n                \"Requires three arguments: <gtirb-file> <from-address> <to-address> \");\n            System.exit(-1);\n        }\n\n        // Read serialized GTIRB data from the specified file.\n        try {\n            ir = IR.parseFrom(new FileInputStream(args[0]));\n        } catch (FileNotFoundException fe) {\n            System.err.println(\"File not found: \" + args[0]);\n            System.exit(-1);\n        } catch (IOException ie) {\n            System.err.println(\"Problem reading file: \" + args[0]);\n            System.exit(-1);\n        }\n\n        try {\n            from_addr = Long.decode(args[1]);\n            to_addr = Long.decode(args[2]);\n        } catch (NumberFormatException nfe) {\n            System.err.println(\n                \"Specify block addresses as numbers in decimal, hexadecimal, or octal format.\");\n            System.exit(-1);\n        }\n\n        // Check one module at a time (the GTIRB CFGs do not have\n        // edges across module boundaries, so if the specified blocks\n        // are in different modules there cannot be any paths between\n        // them).\n        for (Module m : ir.getModulesList()) {\n            cfg = m.getCfg();\n            from_block = findBlockByAddr(from_addr, cfg);\n            to_block = findBlockByAddr(to_addr, cfg);\n\n            // Neither block is in this module: go on to next module.\n            if (from_block == defaultblock && to_block == defaultblock) {\n                System.out.println(\"Blocks not found in module \" + m.getName());\n                continue;\n            }\n\n            // One block is in this module and the other isn't: error.\n            if (to_block == defaultblock) {\n                System.err.println(String.format(\n                    \"The block at from-address 0x%08X is located in a module that does not contain a block at to-address 0x%08X.  The block at 0x%08X may be in a different module, or may not exist.\",\n                    from_addr, to_addr, to_addr));\n                System.exit(-1);\n            }\n            if (from_block == defaultblock) {\n                System.err.println(String.format(\n                    \"The block at  to-address 0x%08X is located in a module that does not contain a block at from-address 0x%08X. The block at 0x%08X may be in a different module, or may not exist.\",\n                    to_addr, from_addr, from_addr));\n                System.exit(-1);\n            }\n\n            // At this point, both to_block and from_block must be\n            // present in this module.\n            blocks_found = true;\n            System.out.println(\"Blocks found in module \" + m.getName());\n            printPaths(from_block, to_block, cfg);\n            break;\n        }\n\n        // If never found either block, notify user.\n        if (!blocks_found) {\n            System.err.println(String.format(\n                \"No blocks found at either of the specified addresses: \\n to-address: 0x%08X \\n from-address: 0x%08X\",\n                to_addr, from_addr));\n            System.exit(-1);\n        }\n    }\n}\n"
  },
  {
    "path": "doc/examples/data-symbols.cpp",
    "content": "// An example program which opens an IR and prints information about all\n// symbols pointing to data.\n\n#include <gtirb/gtirb.hpp>\n#include <fstream>\n#include <iomanip>\n#include <iostream>\n\nusing namespace gtirb;\n\n// Print Addrs in hex format\nstd::ostream& operator<<(std::ostream& Os, Addr A) {\n  auto Flags = Os.flags();\n  Os << \"0x\" << std::hex << std::setw(8) << std::setfill('0') << uint64_t(A);\n  Os.flags(Flags);\n  return Os;\n}\n\nint main(int argc, char** argv) {\n  // Create a context to manage memory for gtirb objects\n  Context C;\n\n  // Load the IR\n  IR* I = nullptr;\n\n  if (argc == 2) {\n    std::ifstream in(argv[1]);\n    if (auto IoE = IR::load(C, in); IoE)\n      I = *IoE;\n  }\n\n  if (!I)\n    return EXIT_FAILURE;\n\n  for (const auto& M : I->modules()) {\n    std::cout << \"Module \" << M.getName() << \"\\n\";\n    // Examine all symbols in the module\n    for (const auto& Sym : M.symbols()) {\n      if (auto* Ref = Sym.getReferent<DataBlock>(); Ref != nullptr) {\n        // If the symbol refers to data, print some information about it\n        std::cout << Sym.getName() << \":\\t\" << Ref->getAddress() << \"\\t\"\n                  << Ref->getSize() << \" bytes\\n\";\n      }\n    }\n  }\n  return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "doc/examples/data-symbols.lisp",
    "content": ";;;; data-symbols.lisp --- Print the names of all symbols pointing to data\n;;;\n;;; To run this example, do the following.\n;;;\n;;; 1. Install the gtirb and gtirb/dot packages with quicklisp\n;;;\n;;;    (mapcar #'ql:quickload '(:gt :gtirb)\n;;;\n;;; 2. Run ddisasm to disassemble a binary to GTIRB.\n;;;\n;;;    $ echo 'main(){puts(\"hello world\");}'|gcc -x c - -o /tmp/hello\n;;;    $ ddisasm /tmp/hello --ir /tmp/hello.gtirb\n;;;\n;;; 3. Evaluate this file using the path of the GTIRB file produced by\n;;;    ddisasm and the addresses of two basic blocks.\n;;;\n(defpackage :data-symbols\n  (:use :gt :gtirb)\n  (:shadow :symbol :size))\n(in-package :data-symbols)\n(in-readtable :curry-compose-reader-macros)\n\n(defun data-symbols (path)\n  \"Print the names of all symbols pointing to data in GTIRB at PATH.\"\n  (nest (format t \"~{~a~%~}\")\n        (mapcar #'name)\n        (remove-if-not [{typep _ 'data-block} #'payload])\n        (mappend #'symbols (modules (read-gtirb path)))))\n"
  },
  {
    "path": "doc/examples/data-symbols.py",
    "content": "#!/usr/bin/python\n#\n# An example program which opens an IR and prints information about all\n# symbols pointing to data.\n#\n# To run this example, do the following.\n#\n# 1. Install the gtirb package from Pypi.\n#\n# 2. Run ddisasm to disassemble a binary to GTIRB.\n#\n#    $ echo 'main(){puts(\"hello world\");}'|gcc -x c - -o /tmp/hello\n#    $ ddisasm /tmp/hello --ir /tmp/hello.gtirb\n#\n# 3. Execute the following command to run the program on the\n#    serialized GTIRB data.\n#\n#    $ ./doc/examples/data-symbols.py /tmp/hello.gtirb\nimport sys\n\nimport gtirb\n\nif len(sys.argv) < 2:\n    print(f\"Usage: {sys.argv[0]} /path/to/file.gtirb\")\n    quit(1)\n\nir = gtirb.ir.IR.load_protobuf(sys.argv[1])\n\nfor m in ir.modules:\n    for s in m.symbols:\n        ref = s.referent\n        if isinstance(ref, gtirb.block.DataBlock):\n            print(s.name)\n"
  },
  {
    "path": "doc/examples/datasymbols.java",
    "content": "// An example program which opens an IR and prints information about all\n// symbols pointing to data.\n//\n// To run this example, do the following.\n//\n// 1. Install the protobuf compiler (protoc) from\n//    https://github.com/protocolbuffers/protobuf/releases (if you have\n//    not already done so).\n//\n// 2. Download the protobuf Java runtime from\n//    https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java\n//    and save it somewhere suitable.\n//\n// 3. Generate Java message definitions.\n//\n//    $ mkdir -p java $ for f in src/proto/*.proto; do\n//         protoc -Isrc/proto --java_out=java $f\n//      done\n//\n//    This will create a subdirectory java/proto/, containing a\n//    number of files with names of the form <bn>OuterClass.java:\n//    one for each <bn>.proto in src/proto/.\n//\n// 4. Compile the Java message definitions, making sure the protobuf\n//    Java runtime .jar file is in your CLASSPATH.\n//\n//    $ mkdir -p java/classfiles\n//    $ CLASSPATH=<path/to/protobuf_jar> \\\n//         javac -d java/classfiles java/proto/*.java\n//\n// 5. Compile the datasymbols class defined in this file, making sure\n//    your CLASSPATH contains both the Java runtime .jar file and the\n//    compiled Java message definition classes.\n//    (Note that the path separator is OS-dependent.)\n//\n//    $ CLASSPATH=<path/to/protobuf_jar>:./java/classfiles/ \\\n//         javac -classpath  doc/examples/datasymbols.java\n//\n// 6. Execute the following command to run the program on the\n//    serialized GTIRB data located at <path-to-ir>.\n//\n//    $  CLASSPATH=<path/to/protobuf_jar>:./java/classfiles/:doc/examples/ \\\n//          java datasymbols <path-to-ir>\n\nimport com.google.protobuf.ByteString;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.PrintStream;\nimport java.lang.Long;\nimport java.util.*;\nimport proto.DataObjectOuterClass.DataObject;\nimport proto.IROuterClass.IR;\nimport proto.ModuleOuterClass.Module;\nimport proto.SymbolOuterClass.Symbol;\n\nclass datasymbols {\n\n    public static void main(String[] args) {\n\n        IR ir = IR.getDefaultInstance();\n        DataObject data_obj;\n\n        if (args.length < 1) {\n            System.err.println(\"No GTIRB file specified.\");\n            System.exit(-1);\n        }\n\n        // Read serialized GTIRB data from the specified file.\n        try {\n            ir = IR.parseFrom(new FileInputStream(args[0]));\n        } catch (FileNotFoundException fe) {\n            System.err.println(\"File not found: \" + args[0]);\n            System.exit(-1);\n        } catch (IOException ie) {\n            System.err.println(\"Problem reading file: \" + args[0]);\n            System.exit(-1);\n        }\n\n        for (Module m : ir.getModulesList()) {\n\n            // Print the name of each Module.\n            System.out.println(\"Module \" + m.getName());\n\n            // Make a map uuid->DataObject for the Module.\n            Map<Long, DataObject> datamap = m.getDataMap();\n            Map<ByteString, DataObject> data_objects =\n                new HashMap<ByteString, DataObject>();\n            for (DataObject d : datamap.values()) {\n                data_objects.put(d.getUuid(), d);\n            }\n\n            // Examine all symbols in the module\n            for (Symbol sym : m.getSymbolsList()) {\n                data_obj = data_objects.get(sym.getReferentUuid());\n                if (data_obj != null) {\n                    // If the symbol refers to data, print some information\n                    // about it\n                    System.out.println(String.format(\n                        \"%s:\\t0x%08X\\t %d bytes\", sym.getName(),\n                        data_obj.getAddress(), data_obj.getSize()));\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "doc/examples/functions.cpp",
    "content": "// An example program which opens and IR and prints information about\n// functions.\n\n#include <gtirb/gtirb.hpp>\n#include <boost/uuid/uuid_io.hpp>\n#include <fstream>\n#include <iomanip>\n#include <iostream>\n#include <map>\n\nusing namespace gtirb;\n\n// Print Addrs in hex format\nstd::ostream& operator<<(std::ostream& Os, Addr A) {\n  auto Flags = Os.flags();\n  Os << \"0x\" << std::hex << std::setw(8) << std::setfill('0') << uint64_t(A);\n  Os.flags(Flags);\n  return Os;\n}\n\nvoid register_aux_data_types() {\n  using namespace gtirb::schema;\n  AuxDataContainer::registerAuxDataType<FunctionEntries>();\n  AuxDataContainer::registerAuxDataType<FunctionBlocks>();\n}\n\nint main(int argc, char** argv) {\n  // Register the AuxData we'll want to use.\n  register_aux_data_types();\n\n  // Create a context to manage memory for gtirb objects\n  Context C;\n\n  // Load the IR\n  IR* I = nullptr;\n\n  if (argc == 2) {\n    std::ifstream in(argv[1]);\n    if (auto IoE = IR::load(C, in); IoE)\n      I = *IoE;\n  }\n\n  if (!I)\n    return EXIT_FAILURE;\n\n  // Load function information from AuxData.\n  // This information is not guaranteed to be present. For the purposes of\n  // this example we assume that it exists, but real code should check for\n  // nullptr in the return value of getAuxData.\n  auto& FunctionEntries =\n      *(I->modules_begin()->getAuxData<gtirb::schema::FunctionEntries>());\n  auto& FunctionBlocks =\n      *(I->modules_begin()->getAuxData<gtirb::schema::FunctionBlocks>());\n\n  // Print function information\n  for (auto& [Function, Entries] : FunctionEntries) {\n\n    // Note: this prints out the function's UUID.\n    std::cout << boost::uuids::to_string(Function) << \"\\n\";\n\n    // Print information about entry points.\n    // TODO: add symbols\n    std::cout << \"  Entries:\\n\";\n    for (auto EntryUUID : Entries) {\n      auto EntryNode = Node::getByUUID(C, EntryUUID);\n      assert(EntryNode);\n      auto EntryBlock = dyn_cast_or_null<CodeBlock>(EntryNode);\n      assert(EntryBlock);\n      std::cout << \"    \" << EntryBlock->getAddress() << \"\\n\";\n    }\n\n    // Examine all blocks in the function.\n    std::cout << \"  Blocks:\\n\";\n    auto It = FunctionBlocks.find(Function);\n    assert(It != FunctionBlocks.end());\n    auto& Blocks = It->second;\n    for (auto BlockUUID : Blocks) {\n      auto BlockNode = Node::getByUUID(C, BlockUUID);\n      assert(BlockNode);\n      auto Block = dyn_cast_or_null<CodeBlock>(BlockNode);\n      assert(Block);\n      std::cout << \"    \" << Block->getAddress() << \"\\n\";\n    }\n  }\n  return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "doc/examples/jumps.cpp",
    "content": "// An example program which opens an IR and prints information about every\n// jump instruction.\n\n#include <gtirb/gtirb.hpp>\n#include <capstone/capstone.h>\n#include <fstream>\n#include <iomanip>\n#include <iostream>\n\nusing namespace gtirb;\n\n// Print Addrs in hex format\nstd::ostream& operator<<(std::ostream& Os, Addr A) {\n  auto Flags = Os.flags();\n  Os << \"0x\" << std::hex << std::setw(8) << std::setfill('0') << uint64_t(A);\n  Os.flags(Flags);\n  return Os;\n}\n\nint main(int argc, char** argv) {\n  // Create a context to manage memory for gtirb objects\n  Context C;\n\n  // Load the IR\n  IR* Ir = nullptr;\n\n  if (argc == 2) {\n    std::ifstream in(argv[1]);\n    if (auto IoE = IR::load(C, in); IoE)\n      Ir = *IoE;\n  }\n\n  if (!Ir)\n    return EXIT_FAILURE;\n\n  // Initialize capstone for decoding instructions.\n  csh CsHandle;\n  [[maybe_unused]] int Ret = cs_open(CS_ARCH_X86, CS_MODE_64, &CsHandle);\n  assert(Ret == CS_ERR_OK);\n  cs_option(CsHandle, CS_OPT_DETAIL, CS_OPT_ON);\n\n  // Examine all blocks in the first module\n  for (const auto& B : blocks(Ir->getCFG())) {\n    // Get the contents of the block and decode with capstone\n    cs_insn* Insn;\n    size_t count =\n        cs_disasm(CsHandle, B.rawBytes<uint8_t>(), B.getSize(),\n                  (uint64_t)B.getAddress().value_or(Addr(0)), 0, &Insn);\n\n    // Exception-safe cleanup of instructions\n    std::unique_ptr<cs_insn, std::function<void(cs_insn*)>> freeInsn(\n        Insn, [count](cs_insn* i) { cs_free(i, count); });\n\n    // Examine all instructions in the block\n    for (size_t I = 0; I < count; I++) {\n      const auto& Inst = Insn[I];\n      auto& Detail = *Inst.detail;\n      for (int G = 0; G < Detail.groups_count; G++) {\n        // Print jump instructions\n        if (Detail.groups[G] == CS_GRP_JUMP) {\n          std::cout << Addr(Inst.address) << \": \" << Inst.mnemonic << \"\\t\";\n          auto& Op = Detail.x86.operands[0];\n          if (Op.type == X86_OP_IMM) {\n            std::cout << Addr(Op.imm) << \"\\n\";\n          } else {\n            std::cout << \"<indirect>\\n\";\n          }\n          break;\n        }\n      }\n    }\n  }\n  return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "doc/examples/show-cfg.lisp",
    "content": ";;;; show-cfg.lisp --- An example program which opens an IR and draws the CFG\n;;;\n;;; To run this example, do the following.\n;;;\n;;; 1. Install the gtirb and gtirb/dot packages with quicklisp\n;;;\n;;;    (ql:quickload :gtirb/dot)\n;;;\n;;; 2. Run ddisasm to disassemble a binary to GTIRB.\n;;;\n;;;    $ echo 'main(){puts(\"hello world\");}'|gcc -x c - -o /tmp/hello\n;;;    $ ddisasm /tmp/hello --ir /tmp/hello.gtirb\n;;;\n;;; 3. Evaluate this file.\n;;;\n;;; 4. Process the resultant dot file into a png\n;;;\n;;;    $ cat /tmp/hello.dot|dot -Tpng > /tmp/hello.png\n;;;\n(in-package :gtirb/dot)\n(to-dot-file (read-gtirb \"/tmp/hello.gtirb\") \"/tmp/hello.dot\")\n"
  },
  {
    "path": "doc/examples/show-cfg.py",
    "content": "#!/usr/bin/python\n#\n# An example program which opens an IR and draws the CFG to the screen.\n#\n# To run this example, do the following.\n#\n# 1. Install the gtirb package from Pypi.\n#\n# 2. Run ddisasm to disassemble a binary to GTIRB.\n#\n#    $ echo 'main(){puts(\"hello world\");}'|gcc -x c - -o /tmp/hello\n#    $ ddisasm /tmp/hello --ir /tmp/hello.gtirb\n#\n# 3. Execute the following command to run the program on the\n#    serialized GTIRB data.\n#\n#    $ ./doc/examples/show-cfg.py /tmp/hello.gtirb\nimport sys\n\nimport matplotlib.pyplot as plt\nimport networkx as nx\n\nimport gtirb\n\nif len(sys.argv) < 2:\n    print(f\"Usage: {sys.argv[0]} /path/to/file.gtirb\")\n    quit(1)\n\nir = gtirb.ir.IR.load_protobuf(sys.argv[1])\nG = nx.DiGraph()\n\nfor edge in ir.cfg:\n    if isinstance(edge.target, gtirb.block.ProxyBlock):\n        # Represent ProxyBlocks (which don't have an address) with their UUID.\n        G.add_edge(edge.source.address, edge.target.uuid)\n    else:\n        G.add_edge(edge.source.address, edge.target.address)\n\nnx.draw(G, with_labels=True)\nplt.show()\n"
  },
  {
    "path": "doc/examples/stack-stamp.md",
    "content": "GTIRB Stack Stamp\n=================\n\nTLDR; It is very easy to write binary transforms in GTIRB, see\n[gtirb-stack-stamp](https://github.com/grammatech/gtirb-stack-stamp).\n\nThis tutorial demonstrates the development of a binary hardening\ntransform built on [GTIRB](https://grammatech.github.io/gtirb) (a data\nstructure that represents binary executables).  We implement *stack\nstamping* (a simple return oriented programming, or ROP, defense) as a\nGTIRB-to-GTIRB transformation.  We leverage the\n[ddisasm](https://github.com/grammatech/ddisasm) front-end to\ndisassemble binaries to GTIRB and the\n[gtirb-pprinter](https://github.com/grammatech/gtirb-pprinter)\nback-end to produce a new hardened executable from the stack stamped\nGTIRB.  In practice the stack-stamp transform could be chained with\nother GTIRB binary analysis or transformation passes.  Implementations\nof the stack stamping transform are given in all three GTIRB API\nlanguages;\nPython [API](https://grammatech.github.io/gtirb/python/index.html)/[stack_stamp.py](https://github.com/GrammaTech/gtirb-stack-stamp/blob/master/gtirb_stack_stamp/stack_stamp.py),\nC++ [API](https://grammatech.github.io/gtirb/cpp/index.html)/[gtirb_stack_stamp.hpp](https://github.com/GrammaTech/gtirb-stack-stamp/blob/master/include/gtirb_stack_stamp.hpp), and\nCommon Lisp [API](https://grammatech.github.io/gtirb/cl/index.html)/[gtirb-stack-stamp.lisp](https://github.com/GrammaTech/gtirb-stack-stamp/blob/master/gtirb-stack-stamp.lisp).\n\nThis document walks through the whole process of writing and applying\nthe *stack stamping* binary ROP protection in following steps:\n\n- A. [Install Dependencies](#a-install-all-required-libraries-and-utilities)\n- B. [Lift a binary to GTIRB](#b-lift-a-binary-to-gtirb)\n- C.a [Implement your own stack-stamp transform](#ca-implement-your-own-stack-stamp-transform)\n- C.b [Just run our stack-stamp transform](#cb-just-run-our-stack-stamp-transform)\n- D. [Serialize GTIRB to a new executable and test](#d-serialize-gtirb-to-a-new-executable-and-test)\n- E. [Visualize the difference using the gtirb-ghidra-plugin](#e-visualize-the-difference-using-gtirb-ghidra-plugin)\n- F. Let us know what you think.  You can open an issue against\n  [github.com/grammatech/gtirb](https://github.com/grammatech/gtirb)\n  or email us at `gtirb@grammatech.com`.\n\n\n## A. Install all required libraries and utilities\n\nThe following should be sufficient to install the required GTIRB\nlibraries and utilities (for complete installation instructions see\n[GTIRB#Install](https://github.com/grammatech/gtirb#installing)).\n\n1. Install the required binaries.\n\n   - Windows:\n\n     > NOTE: Windows users are warned that (1) you can't assemble and\n     > link your rewritten ELF file on Windows unless you have the\n     > required Linux build tool installed (2) the Common Lisp APIs\n     > are not tested on Windows -- although they might work.\n\n     1. Download `ddisasm-artifacts.zip`, `gtirb-artifacts.zip`, and\n        `gtirb-pprinter-artifacts.zip` from\n        [https://grammatech.github.io/gtirb/pkgs/windows-release](https://grammatech.github.io/gtirb/pkgs/windows-release);\n     2. Extract each ZIP file to a suitable location.\n     3. Add the /bin directory from each extracted ZIP file to your `PATH` environment variable.\n        (Alternatively, provide the full path when you invoke the extracted executables.)\n     4. If it is not already present on your system, install\n        [Protobuf](https://developers.google.com/protocol-buffers/)\n        version 3.0.0 or higher.\n     5. If you plan to work in C++, you will also need\n        [Boost](https://www.boost.org/), version 1.68.0 or higher.\n\n   - Ubuntu16: install the binaries from the GTIRB xenial repository as follows.\n     ```bash\n     sudo apt-get install software-properties-common\n     sudo add-apt-repository ppa:maarten-fonville/protobuf\n     sudo add-apt-repository ppa:mhier/libboost-latest\n     echo \"deb https://grammatech.github.io/gtirb/pkgs/xenial ./\" | sudo tee -a /etc/apt/sources.list.d/gtirb.list\n     sudo apt-get update\n     sudo apt-get install --allow-unauthenticated libgtirb-dev gtirb-pprinter ddisasm\n     ```\n\n   - Ubuntu18: install the binaries from the GTIRB bionic repository as follows.\n     ```bash\n     sudo apt-get install software-properties-common\n     sudo add-apt-repository ppa:mhier/libboost-latest\n     echo \"deb [trusted=yes] https://grammatech.github.io/gtirb/pkgs/bionic ./\" | sudo tee -a /etc/apt/sources.list.d/gtirb.list\n     sudo apt-get update\n     sudo apt-get install libgtirb-dev gtirb-pprinter ddisasm\n     ```\n\n   - Ubuntu20: install the binaries from the GTIRB focal repository as follows.\n     ```bash\n     sudo apt-get install software-properties-common\n     echo \"deb [trusted=yes] https://grammatech.github.io/gtirb/pkgs/focal ./\" | sudo tee -a /etc/apt/sources.list.d/gtirb.list\n     sudo apt-get update\n     sudo apt-get install libgtirb-dev gtirb-pprinter ddisasm\n     ```\n\n   - Arch Linux: install pre-built `pacman` packages from\n     [https://grammatech.github.io/gtirb/pkgs/arch](https://grammatech.github.io/gtirb/pkgs/arch)\n     or install using the popular [aur helper](https://wiki.archlinux.org/index.php/AUR_helpers)\n     [yay](https://github.com/Jguer/yay),\n     ```bash\n     yay -Sy gtirb-git gtirb-pprinter-git ddisasm-git\n     ```\n\n2. For the Common Lisp and C++ API, install [Keystone](https://github.com/keystone-engine/keystone).\n   Keystone does not have prebuilt packages, so you must install this from\n   source.  For Linux systems, this generally looks like:\n   ```bash\n   git clone https://github.com/keystone-engine/keystone.git\n   cd keystone\n   mkdir build\n   cd build\n   ../make-share.sh\n   make install\n   ```\n\n3. Make sure the required GTIRB components are available to your\n   development environment.  This will depend on the language you want\n   to work in:\n\n   - C++: when you compile your transform, do all of the following.\n     - Specify that the GTIRB `lib/` is a library directory.\n     - Specify that the GTIRB `include/` is an include directory.\n     - Link against the `gtirb` and `proto` libraries\n       (Windows: `gtirb.lib`, `proto.lib`; Linux: `gtirb.so`, `proto.so`).\n\n   - Python (note: must be Python 3):\n     ```bash\n     pip3 install gtirb gtirb-functions gtirb-capstone\n     ```\n\n   - Common Lisp:\n     1. Clone the latest versions of these repositories into your\n        `~/quicklisp/local-projects` directory (the versions in quicklisp\n        don't yet have some important bugfixes)\n        ```bash\n        cd ~/quicklisp/local-projects\n        git clone https://github.com/brown/protobuf\n        git clone --single-branch --branch quicklisp https://github.com/grammatech/gtirb\n        git clone https://github.com/grammatech/gtirb-capstone\n        git clone https://github.com/grammatech/gtirb-functions\n        ```\n\n     2. Install with quicklisp.\n        ```lisp\n        (ql:quickload '(:gtirb :gtirb-functions :gtirb-capstone))\n        ```\n\n## B. Lift a binary to GTIRB\n\nGrammaTech's open-source GTIRB tooling supports disassembly of ELF\nbinaries only.\n\nThe example used in this tutorial is a Linux `ls` binary.  If you\nprefer, you can work with a different ELF binary: just amend the\ncommand lines as necessary to accommodate any file name differences.\n\nIf you are on a Linux system, you can analyze your system `ls`. For\nWindows users, we have provided additional instructions for obtaining\na Linux `ls` binary.\n\nUbuntu 16, Ubuntu18, Ubuntu20, Arch Linux:\n\n  1. Change to a suitable working directory.\n\n  2. Run the datalog disassembler to analyze the binary and produce a\n     GTIRB representation.\n\n     ```bash\n     ddisasm $(which ls) --ir ls.gtirb\n     ```\n\n\nWindows:\n\n  1. Do you have easy access to a Linux `ls` binary? (For example, can\n     you copy one from another local system?)\n\n     - YES: Copy the binary to a suitable working directory and go to step 4.\n\n     - NO: Go on to step 2.\n\n  2. Download a Linux coreutils package from\n     http://launchpadlibrarian.net/340091849/coreutils_8.26-3ubuntu4_amd64.deb\n     (or another location if you prefer).\n\n  3. Use a tool such as [7-Zip](https://www.7-zip.org/) to extract\n     `/bin/ls` from the package, then copy it to a suitable working\n     directory.\n\n     (If your tool does not support selective extraction, unpack the\n     entire package to a temporary location, then copy `/bin/ls` to\n     your working directory.)\n\n  4. Change to your working directory.\n\n\nIf you are not able to successfully analyze your chosen binary, please\n[open an issue](https://github.com/GrammaTech/ddisasm/issues/new) to\nlet us know.\n\n\n## C.a Implement your own stack-stamp transform\n\nStack stamping is a technique to help mitigate ROP style attacks.\nThis is done by 'stamping' (`xor`ing with a random number) the return\naddress on the stack at the beginning of every function, thus\nencrypting it.  At the end of the function, before the return address\nis popped off the stack and used, it is decrypted by `xor`ing it again\nwith the same random number.  This can be a very efficient protection.\nBecause it only requires an `xor` instruction this implementation\nrequires no registers, and while flags are affected, they are only\naffected at function entry/exits where they do not need to be\npreserved.  The effect of encrypting and decrypting the return address\non the stack like this is that ROP payloads become much more difficult\nto write.  The attacker would have to know the random `xor` number for\nevery return to encrypt the return addresses in the payload.  These\nnumbers could easily be regenerated for every instance of a deployed\nbinary making generic payloads impossible.\n\n![Stack Stamp Figure](.stack-stamp.svg)\n\nRegardless of the implementation language the mechanics of this\ntransform will be the same -- we'll write a GTIRB-to-GTIRB rewriting\npass (the design of GTIRB is similar to LLVM in that it leverages\nstand-alone passes for analysis or transformation).\n\n```\n  For each function f that has a single entry and single return.\n     Build a random key k_f for f.\n     On entry to f, encrypt the return address using k_f.\n     On exit from f, decrypt the return address using k_f.\n```\n\n\n1. Implement the transform, using the [GTIRB\n   manual](https://grammatech.github.io/gtirb/) as a reference.\n\n   If you're developing in Python or Common Lisp you can work directly in\n   a Read Eval Print Loop (REPL), or use it to\n   prototype a stand-alone implementation.\n\n   - For all languages, start by importing the `gtirb` API and then\n   loading your `ls.gtirb` file. For Common Lisp and Python, you will\n   also need to import the `gtirb-functions` and `gtirb-capstone`\n   APIs.\n\n      - Python\n        ```python\n        from gtirb import *\n        import gtirb_functions\n        import gtirb_capstone\n        ir = IR.load_protobuf(\"ls.gtirb\")\n        ```\n\n      - C++\n        ```c++\n        #include <gtirb.hpp>\n        gtirb::Context Ctx;\n        std::ifstream File(\"ls.gtirb\");\n        gtirb::IR* Ir = *gtirb::IR::load(Ctx, File);\n        ```\n\n      - Common Lisp\n        ```lisp\n        (mapcar #'use-package '(:gtirb :gtirb-capstone :gtirb-functions))\n        (defparameter *ir* (read-gtirb \"ls.gtirb\"))\n        ```\n\n   - The mechanism for identifying functions and their entry points\n     depends on the API language you are using.\n\n     - Python: Use the `gtirb-functions` API functionality\n       ([Python](https://github.com/GrammaTech/gtirb-functions/tree/master/gtirb_functions))\n       to obtain the set of recovered functions, and the\n       sets of entry and exit blocks for each function.\n\n     - C++: The GTIRB\n       [sanctioned AuxData tables](https://grammatech.github.io/gtirb/md__aux_data.html)\n       are populated by `ddisasm`: use the `gtirb` API to access the\n       information in these tables.\n\n     - Common Lisp: Use the `gtirb-functions` API functionality\n       ([Common Lisp](https://github.com/GrammaTech/gtirb-functions/blob/master/gtirb-functions.lisp))\n       to obtain the set of recovered functions, and the\n       sets of entry and exit blocks for each function.\n\n\n2. When you're done, compare your implementation to the corresponding\n   completed transform in the gtirb-stack-stamp repository on GitHub:\n\n   - [Python](https://github.com/GrammaTech/gtirb-stack-stamp/blob/master/gtirb_stack_stamp/stack_stamp.py#L36)\n   - [C++](https://github.com/GrammaTech/gtirb-stack-stamp/blob/master/src/gtirb_stack_stamp.cpp)\n   - [Common Lisp](https://github.com/GrammaTech/gtirb-stack-stamp/blob/master/gtirb-stack-stamp.lisp#L24)\n\n\n3. Apply your transform to `ls.gtirb`.\n\n4. Serialize the transformed GTIRB to a new file `ls-ss.gtirb`.\n\n   - Python\n     ```python\n     ir.save_protobuf(\"ls-ss.gtirb\")\n     ```\n\n   - C++\n     ```c++\n     std::ofstream File(\"ls-ss.gtirb\");\n     Ir->save(File);\n     ```\n\n   - Common Lisp\n     ```lisp\n     (write-gtirb *ir* \"ls-ss.gtirb\")\n     ```\n\n## C.b Just run our stack-stamp transform\n\nIf you're interested in applying this transform but not writing it\nyourself you can try our implementation available at\n[https://github.com/GrammaTech/gtirb-stack-stamp](https://github.com/GrammaTech/gtirb-stack-stamp).\n\n- Python\n  ```bash\n  pip install gtirb\n  python -m gtirb_stack_stamp /tmp/ls.gtirb --outfile /tmp/ls-ss.gtirb --rebuild /tmp/ls-ss\n  ```\n\n- C++\n  ```bash\n  mkdir build\n  cmake -Bbuild\n  make -Cbuild\n  ./build/bin/gtirb-stack-stamp -i /tmp/ls.gtirb -o /tmp/ls-ss.gtirb\n  ```\n\n- Common Lisp\n  ```bash\n  sbcl --eval '(ql:quickload :gtirb-stack-stamp)' --eval '(asdf:make :gtirb-stack-stamp :type :program :monolithic t)'\n  ./stack-stamp -g /tmp/ls-ss.gtirb -b /tmp/ls-ss\n  ```\n\n## D. Serialize GTIRB to a new executable and test\n\nThe final step is to use the GTIRB pretty printer to convert your\nGTIRB representation to a new binary.\n\n> NOTE: Although you can pretty-print GTIRB to assembly on Windows you\n> can't actually assemble or link the assembler to an ELF file on\n> Windows because the required `as` and `ld` commands are typically\n> not installed.  So this is likely the end of the road for users\n> without access to a Linux machine.\n\n1. Run the following command.\n\n   ```bash\n   gtirb-pprinter ls-ss.gtirb --skip-section .eh_frame \\\n               --asm ls.ss.s \\\n               --binary ls.ss\n   ```\n\n2. Try running the new binary. Its behavior should be\n   indistinguishable from the original.\n\n   (You will not be able to do this on Windows. However, if you have\n   access to a Linux system, you can copy your new binary there and\n   try it out.)\n\n## E. Visualize the difference using gtirb-ghidra-plugin\n\n[Ghidra](https://ghidra-sre.org) is a reverse engineering framework\ndeveloped by the National Security Agency (NSA).\nWith a GTIRB plug-in, Ghidra offers a useful GUI for examining the\ndifferences between GTIRB files.\n\nProcedure:\n\n- a. [Install prerequisites if they are not already installed](#a-install-prerequisites-if-they-are-not-already-installed)\n- b. [Import and analyze the files](#b-import-and-analyze-the-files)\n- c. [Use the Version Tracking tool to match function locations](#c-use-the-version-tracking-tool-to-match-function-locations)\n- d. [Examine the changes in a side-by-side view](#d-examine-the-changes-in-a-side-by-side-view)\n\n\n### a. Install prerequisites if they are not already installed\n\n1. Java 11 (a prerequisite for Ghidra):\n   [Ubuntu18](https://www.linuxbabe.com/ubuntu/install-oracle-java-8-openjdk-11-ubuntu-18-04-18-10),\n   [Windows](https://access.redhat.com/documentation/en-us/openjdk/11/html/openjdk_11_for_windows_getting_started_guide/index)\n\n2. [Ghidra](https://ghidra-sre.org/).\n\n3. The [GTIRB Ghidra plugin](https://github.com/GrammaTech/gtirb-ghidra-plugin).\n\n\n### b. Import and analyze the files\n\n1. Start Ghidra and open a project or create a new one.\n\n2. Import `ls.gtirb` and double-click it to open a Code Browser.\n\n3. When prompted to analyze it, hit \"Yes\" and select \"Disassemble\n   Entry Points\" (only).\n\n   This will populate the listing with disassembly for all functions.\n\n4. When the analysis is complete, save the file and close the Code\n   Browser.\n\n5. Repeat steps 2-4 for `ls-ss.gtirb`\n\n### c. Use the Version Tracking tool to match function locations\n\n1. Click on the \"Footprints\" icon to start the Version Tracking tool.\n\n2. The Version Tracking tool also has a footprints icon, click on this\n   to start a new session wizard.\n\n3. Enter a session name and select the before and after files as\n   Source and Destination.\n\n4. Skip the precondition checks and click Finish.\n\n   This will open source and destination tools, which you can\n   minimize as we don't need them.\n\n### d. Examine the changes in a side-by-side view\n\n1. In the Version Tracking tool, click the green \"+\" (plus sign) to start\n   comparing the files.\n\n2. In the wizard that comes up, select \"Exact Symbol Name Match\"\n   (only). This will allow us to do a side-by-side comparison of\n   functions of the same name.\n\n3. Click Next and Finish.\n\n   The Version Tracking Matches window will be populated with a list\n   of matches. (If you don't see a Version Tracking Matches window, go\n   to Window in the top menu and select Version Tracking\n   Matches).\n\n4. Select a function by clicking on a row with type\n   Function.\n\n5. Go to the Version Tracking Markup window to see a comparison of\n   this function (if you don't see source and destination sections in\n   the Version Tracking Markup window, click the \"Book\" icon in the\n   upper right corner of the Version Tracking Markup window.\n"
  },
  {
    "path": "doc/general/AuxDataContainer.md",
    "content": "AuxDataContainer\n================\n\nAn AuxDataContainer object provides functionality for associating\n[auxiliary data](../AuxData.md) with elements of the representation.\n\nGuaranteed Properties\n---------------------\n\n- An **AuxDataContainer** must have all the guaranteed properties of a\n  [Node](Node.md).\n  - It is *not* required that **AuxDataContainer** be a subclass of\n    **Node**, even if the API language would support this.\n\n- All **AuxDataContainer** objects store a (possibly empty) map of\n  strings to [AuxData](../AuxData.md) entries.\n\n- The string->AuxData map must provide the following functionality.\n  - Insert or overwrite AuxData given a name, a type hint string, and\n    a value of the correct target-language type.\n  - Erase an existing AuxData given its name.\n  - Retrieve AuxData of a given name (and given target-language type,\n    if the target language needs this information).\n  - Inspect AuxData of a given name and determine its type hint.\n\n- The AuxData system must have the following properties.\n  - All core types in the AuxData system must have a corresponding\n    type in the target language.\n  - AuxData of all types, including unknown types, must be retrievable\n    as a byte array.\n\n\n\n\n\nAPI Implementations\n-------------------\n\nThe guaranteed functionality is provided as follows.\n\n### AuxDataContainer Classes and Node properties\n\n| Language    | AuxDataContainer Class  | guaranteed Node Properties           |\n|:------------|:------------------------|:-------------------------------------|\n| C++         | gtirb::AuxDataContainer | through inheritance from gtirb::Node |\n| Python      | gtirb.AuxDataContainer  | through inheritance from gtirb.Node  |\n| Common Lisp | No explicit implementation; relevant classes **ir** and **module** implement required functionality directly. | . |\n\n### string->AuxData map\n\n\n\n| Language    | Get AuxData by name  | Insert/Overwrite AuxData  | Erase AuxData   |\n|:------------|:---------------------|:--------------------------|:----------------|\n| C++         |  gtirb::AuxDataContainer::getAuxData () | gtirb::AuxDataContainer::addAuxData(), gtirb::AuxData::operator=() | gtirb::AuxDataContainer::removeAuxData() |\n| Python      | dict lookup in gtirb.AuxDataContainer.auxdata | dict insert/overwrite on gtirb.AuxDataContainer.auxdata | dict pop on gtirb.AuxDataContainer.auxdata |\n| Common Lisp | **aux-data** *object* => *result* has **module** and **gtirb** specializations; extract the required named data extraction from the *result* alist |  extract auxiliary data alist with **aux-data** accessor, update alist as needed, then use (setf (**aux-data** *object*) *new-value*) which has **module** and **gtirb** specializations | as for insert/overwrite |\n\n\n### AuxData Inspection\n\n\n| Language    | Get AuxData data                         | Get AuxData type hint                    |\n|:------------|:-----------------------------------------|:-----------------------------------------|\n| C++         | gtirb::AuxData::get()                    | gtirb::AuxData::typeName()               |\n| Python      | gtirb.AuxData.data                       | gtirb.AuxData.type_name                  |\n| Common Lisp | **aux-data-data** *aux-data* => *result* | **aux-data-type** *aux-data* => *result* |\n\n\n\nLinks\n--------------------\n\n- [Standard AuxData Schemata](../../AuxData.md)\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/Block.md",
    "content": "Block\n============\n\n**Block** represents a base class for blocks. [Symbol](Symbol.md)\nobjects may have references to any kind of **Block**.\n\nGuaranteed Properties\n---------------------\n\n- A **Block** is a [Node](Node.md).\n\n\nAPI Implementations\n--------------------\n\nThe guaranteed functionality is provided as follows.\n\n### Block Classes\n\n| Language    | Block Class     |\n|:------------|:----------------|\n| C++         | no explicit **Block** class; see individual classes gtirb::CodeBlock ([CodeBlock](CodeBlock.md)), gtirb::DataBlock ([DataBlock](DataBlock.md)),  gtirb::CfgNode ([CfgNode](CfgNode.md)) |\n| Python      | gtirb.Block     |\n| Common Lisp | **gtirb-block** |\n\n\nLinks\n--------------------\n\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/ByteBlock.md",
    "content": "ByteBlock\n====================\n\n**ByteBlock** is the base class for blocks that belong to a\n[ByteInterval](ByteInterval.md) and store their bytes there.\n\n\nGuaranteed Properties\n---------------------\n\n- A **ByteBlock** is a [Block](Block.md).\n\n- Each **ByteBlock** object must store an integral **size** that is\n  readable and writable.\n\n- Each **ByteBlock** must belong to either zero (0) or one (1)\n  [ByteInterval](ByteInterval.md) objects. The owning **ByteInterval**\n  must be stored as a reference.\n  - This reference may be null, in which case the **ByteBlock** is\n    freestanding and does not belong to any **ByteInterval**.\n\n- If a **ByteBlock** belongs to a **ByteInterval** then it must be\n  able to retrieve its offset in the **ByteInterval**.\n\n- If a **ByteBlock** belongs to a **ByteInterval** that has an address\n  then it must be able to retrieve its address, calculated as the\n  **ByteInterval** address plus the **ByteBlock** offset.\n\n\nAPI Implementations\n--------------------\n\nThe guaranteed functionality is provided as follows.\n\n### ByteBlock Classes\n\n| Language    | ByteBlock Class |\n|:------------|:----------------|\n| C++         | no explicit **ByteBlock** class; see individual classes gtirb::CodeBlock ([CodeBlock](CodeBlock.md)), gtirb::DataBlock ([DataBlock](DataBlock.md)) |\n| Python      | gtirb.ByteBlock    |\n| Common Lisp | **gtirb-byte-block** |\n\n\n\n### Size Getters/Setters\n\n| Language    | Get size                  | Set size                  |\n|:------------|:--------------------------|:--------------------------|\n| C++         | gtirb::CodeBlock::getSize(), gtirb::DataBlock::getSize() | gtirb::CodeBlock::setSize(), gtirb::DataBlock::setSize() |\n| Python      | read gtirb.ByteBlock.size   | write gtirb.ByteBlock.size  |\n| Common Lisp | **size** (*obj* *code-block*) => *result*, **size** (*obj* *data-block*) => *result* | (setf (**size** (*obj* *code-block*)) *new*), (setf (**size** (*obj* *data-block*)) *new*) |\n\n\n### Associated ByteInterval\n\n#### Get Associated ByteInterval\n\n| Language    | Get Associated ByteInterval         |\n|:------------|:------------------------------------|\n| C++         | gtirb::ByteBlock::getByteInterval() |\n| Python      | gtirb.ByteBlock.byte_interval       |\n| Common Lisp | **byte-interval** (*object* *code-block*) => *result*,  **byte-interval** (*object* *data-block*) => *result* |\n\n\n#### ByteBlock Offset in Associated ByteInterval\n\n| Language    | Offset                              |\n|:------------|:------------------------------------|\n| C++         | gtirb::CodeBlock::getOffset(), gtirb::DataBlock::getOffset() |\n| Python      | gtirb.ByteBlock.offset              |\n| Common Lisp | **offset** (*obj* *code-block*) => *result*,  **offset** (*obj* *data-block*) => *result* |\n\n\n\n#### ByteBlock Address\n\n| Language    | Address                          |\n|:------------|:---------------------------------|\n| C++         | gtirb::DataBlock::getAddress(), gtirb::DataBlock::getAddress() |\n| Python      | gtirb.ByteBlock.address          |\n| Common Lisp | **address** *obj* => *result*    |\n\n\nLinks\n--------------------\n\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/ByteInterval.md",
    "content": "ByteInterval\n====================\n\nA **ByteInterval** represents a named section of a binary.\n\nThe corresponding Protobuf message type is `ByteInterval`.\n\n\nGuaranteed Properties\n---------------------\n\n- A **ByteInterval** is a [Node](Node.md).\n\n- Each **ByteInterval** object must have the following information,\n  and the API must provide functionality for getting and setting each.\n\n  - **blocks** (as a collection of [ByteBlock](ByteBlock.md) objects,\n    in offset order)\n\n  - **symbolic_expressions** (as a collection of\n    [SymbolicExpression](SymbolicExpression.md) objects, in offset\n    order)\n\n  - **contents** (as a byte array)\n\n  - **size**\n\n  - **address** (Must be either optional or nullable. It is not valid\n    to have a sentinel value in the range of a 64-bit integer as an\n    indication of nullness.)\n\n- A **ByteInterval** must provide the following functionality for its\n  **blocks**.\n  - Insert a **ByteBlock** at a specified offset.\n  - Remove an existing **ByteBlock**.\n  - Retrieve all **ByteBlock** objects at a specified offset.\n  - Iterate over all **ByteBlock** objects.\n  - Find all **CodeBlock** objects that intersect a given address or\n    range of addresses.\n  - Find all **CodeBlock** objects that start at a given address or\n    range of addresses. This operation must complete in O(m + log n) time,\n    where m is the size of the returned set and n is the number of\n    **ByteBlock** objects in **blocks**.\n  - Find all **DataBlock** objects that intersect a given address or\n    range of addresses.\n  - Find all **DataBlock** objects that start at a given address or\n    range of addresses. This operation must complete in O(m + log n) time,\n    where m is the size of the returned set and n is the number of\n    **ByteBlock** objects in **blocks**.\n\n- A **ByteInterval** must provide the following functionality for its\n  **symbolic_expressions**.\n  - Insert a **SymbolicExpression** at a specified offset.\n  - Remove an existing **SymbolicExpression**.\n  - Retrieve all **SymbolicExpression** objects at a specified offset.\n  - Iterate over all **SymbolicExpression** objects.\n  - Find all **SymbolicExpression** objects that start at a given\n    address or range of addresses. This operation must complete in\n    O(log n) time, where n is the number of **SymbolicExpression**\n    objects in **symbolic_expressions**. (There is no corresponding\n    address *intersection* requirement: **SymbolicExpressions** have no size.)\n\n\n- The **contents** have the following requirements.\n  - The size of **contents** must be less than or equal to the size of\n    the **ByteInterval**.\n  - If the size of a **ByteInterval** is changed to a value that is\n    less than the size of its **contents**, its **contents** must be\n    truncated.\n\n\n- Each **ByteInterval** must belong to either zero (0) or one (1)\n  [Section](Section.md) objects. The owning **Section** must be stored as\n  a reference.\n  - This reference may be null, in which case the **ByteInterval** is\n    freestanding and does not belong to any **Section**.\n\n\n\nAPI Implementations\n--------------------\n\nThe guaranteed functionality is provided as follows.\n\n### ByteInterval Classes\n\n| Language    | ByteInterval Class  |\n|:------------|:--------------------|\n| C++         | gtirb::ByteInterval |\n| Python      | gtirb.ByteInterval  |\n| Common Lisp | **byte-interval**   |\n\n\n### blocks\n\n#### Get and Set\n\n\n| Language    | Get blocks | Set blocks |\n|:------------|:---------------|:---------------|\n| C++         | gtirb::ByteInterval::blocks() | gtirb::ByteInterval::addBlock(), gtirb::ByteInterval::RemoveBlock() |\n| Python      | read gtirb.ByteInterval.blocks | write gtirb.ByteInterval.blocks |\n| Common Lisp | **blocks** (*object* *byte-interval*) => *result* | (setf (**blocks** (*object* *byte-interval*)) *new-value*) |\n\n\n\n#### ByteBlock operations\n\n\n| Language    | Insert at offset | Remove | Retrieve from offset | Iterate |\n|:------------|:---------------|:---------------|:---------------|:---------------|\n| C++         | gtirb::ByteInterval::addBlock() | gtirb::ByteInterval::removeBlock() | gtirb::ByteInterval::findBlocksAtOffset | gtirb::ByteInterval::blocks_begin() |\n| Python      | for all these operations, interact directly with gtirb.ByteInterval.blocks: each gtirb.ByteBlock object stores its own offset. | . | . | . |\n| Common Lisp | for all these operations, interact with the blocks through the **blocks** accessor: each **byte-block** object stores its own offset. | . | . | . |\n\n\n#### Find  CodeBlock Objects...\n\n| Language    | ...that intersect an address/range | ...that begin at an address/range\n|:------------|:---------------------------|:---------------------------|\n| C++         | gtirb::ByteInterval::findCodeBlocksOn() | gtirb::ByteInterval::findCodeBlocksAt() |\n| Python      | gtirb.ByteInterval.code_blocks_in() | gtirb.ByteInterval.code_blocks_at() |\n| Common Lisp | **in-address** *object* *start-address* &optional *end-address* => *result*, then filter *result* to extract the **code-block** objects | **at-address** *object* *address* => *result*, then filter *result* to extract the **code-block** objects. [*] |\n\n[*] Address range checking is not yet implemented for Common Lisp\n**at-address**\n\n\n#### Find  DataBlock Objects...\n\n| Language    | ...that intersect an address/range | ...that begin at an address/range\n|:------------|:---------------------------|:---------------------------|\n| C++         | gtirb::ByteInterval::findDataBlocksOn() | gtirb::ByteInterval::findDataBlocksAt() |\n| Python      | gtirb.ByteInterval.data_blocks_in() | gtirb.ByteInterval.data_blocks_at() |\n| Common Lisp |  **in-address** *object* *start-address* &optional *end-address* => *result*, then filter *result* to extract the **data-block** objects | **at-address** *object* *address* => *result*, then filter *result* to extract the **data-block** objects. [*] |\n\n[*] Address range checking is not yet implemented for Common Lisp\n**at-address**\n\n\n### symbolic_expressions\n\n#### Get and Set\n\n| Language    | Get symbolic_expressions | Set symbolic_expressions |\n|:------------|:---------------|:---------------|\n| C++         | gtirb::ByteInterval | gtirb::ByteInterval |\n| Python      | gtirb.ByteInterval |  gtirb.ByteInterval |\n| Common Lisp | **symbolic-expressions** (*object* *byte-interval*) => *result* | (setf (**symbolic-expressions** (*object* *byte-interval*)) *new-value*) |\n\n\n#### Find SymbolicExpression Objects...\n\n| Language    | ...that begin at an address/range                |\n|:------------|:-------------------------------------------------|\n| C++         | gtirb::ByteInterval::findSymbolicExpressionsAt() |\n| Python      | gtirb.ByteInterval.symbolic_expressions_at()     |\n| Common Lisp |  **at-address** *object* *address* => *result*, then filter *result* to extract the symbolic expression objects. [*] |\n\n[*] Address range checking is not yet implemented for Common Lisp\n**at-address**\n\n#### Other Required SymbolicExpression Operations\n\n\n| Language    | Insert at offset | Remove | Retrieve from offset | Iterate |\n|:------------|:---------------|:---------------|:---------------|:---------------|\n| C++         | gtirb::ByteInterval::addSymbolicExpression() | gtirb::ByteInterval::removeBlock() | gtirb::ByteInterval::findSymbolicExpressionsAtOffset | gtirb::ByteInterval::symbolic_expressions_begin() |\n| Python      | for all these operations, interact directly with gtirb.ByteInterval.symbolic_expressions, which is a mapping indexed by offset. | . | . | . |\n| Common Lisp | for all these operations, interact with the SymbolicExpression objects through the **symbolic-expressions** accessor: **symbolic-expression** hashes are keyed by offset. | . | . | . |\n\n\n\n### contents\n\n#### Get and Set\n\n\n| Language    | Get contents | Set contents |\n|:------------|:-------------|:-------------|\n| C++         | read gtirb::ByteInterval::bytes() | write gtirb::ByteInterval::bytes() |\n| Python      | read gtirb.ByteInterval.contents  | write gtirb.ByteInterval.contents |\n| Common Lisp | **contents** (*obj* *byte-interval*) => *result* | (setf (**contents** (*obj* *byte-interval*)) *new*) |\n\n\n### size\n\n#### Get and Set\n\n\n| Language    | Get size                      | Set size                      |\n|:------------|:------------------------------|:------------------------------|\n| C++         | gtirb::ByteInterval.getSize() | gtirb::ByteInterval.setSize() |\n| Python      | read gtirb.ByteInterval.size  | write gtirb.ByteInterval.size |\n| Common Lisp | **size** (*obj* *byte-interval*) => *result* | (setf (**size** (*obj* *byte-interval*)) *new*) |\n\n\n\n### address\n\n#### Get and Set\n\n\n| Language    | Get address | Set address |\n|:------------|:------------|:------------|\n| C++         | gtirb::ByteInterval::getAddress() | gtirb::ByteInterval::setAddress |\n| Python      | read gtirb.ByteInterval.address | write gtirb.ByteInterval.address |\n| Common Lisp | **address** (*obj* *byte-interval*) => *result* | (setf (**address** (*obj* *byte-interval*)) *new*) |\n\n\n\n\n\n\n### Associated Section\n\n\n| Language    | Associated Section                                 |\n|:------------|:---------------------------------------------------|\n| C++         | gtirb::ByteInterval::getSection()                  |\n| Python      | gtirb.ByteInterval.section                         |\n| Common Lisp | **section** (*object* *byte-interval*) => *result* |\n\n\n\nLinks\n--------------------\n\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/CFG.md",
    "content": "CFG\n====================\n\nA **CFG** represents the interprocedural control flow graph.\n\nThe corresponding Protobuf message type is `CFG`.\n\n- The vertices of a **CFG** correspond to [CfgNode](CfgNode.md)\n  - objects.  Every **CfgNode** object in the [IR](IR.md) is\n    potentially a vertex in the **CFG**.\n\n- The edges of a **CFG** correspond to [CfgEdge](CfgEdge.md) objects.\n\n- There are no guaranteed properties for the **CFG**. There are,\n  however, guaranteed properties for constituent components\n  [CfgNode](CfgNode.md) and [CfgEdgeLabel](CfgEdgeLabel.md).\n\n\nAPI Implementations\n--------------------\n\n\n| Language    | CFG Implementation     |\n|:------------|:-----------------------|\n| C++         | gtirb::CFG             |\n| Python      | typing.set[gtirb.Edge] |\n| Common Lisp | a [graph:digraph](http://eschulte.github.io/graph/) whose nodes hold **code-block** UUIDs and edges are labeled with **edge_label** objects    |\n\n\nLinks\n--------------------\n\n- [Advice on when to Place ICFG Edges](../CFG-Edges.md)\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/CMakeLists.txt",
    "content": "# based on sample in https://majewsky.wordpress.com/2010/08/14/tip-of-the-day-\n# cmake-and-doxygen/ add a target to generate API documentation with Doxygen\n\ncmake_minimum_required(VERSION 3.3)\n\nfind_package(Doxygen 1.8.11)\nif(DOXYGEN_FOUND)\n\n  set(DOC_INDIR \"${CMAKE_CURRENT_SOURCE_DIR}/..\")\n  set(ROOTDIR \"${CMAKE_CURRENT_SOURCE_DIR}/../..\")\n\n  set(BUILDFILES_IN ../preprocmd.py DoxygenLayout.xml)\n  foreach(_inf ${BUILDFILES_IN})\n    configure_file(\n      ${CMAKE_CURRENT_SOURCE_DIR}/${_inf} ${CMAKE_CURRENT_BINARY_DIR}/${_inf}\n      @ONLY\n    )\n  endforeach()\n\n  # Handle version initialization\n  file(READ \"${ROOTDIR}/version.txt\" ver)\n\n  string(REGEX MATCH \"VERSION_MAJOR ([0-9]*)\" _ ${ver})\n  set(GTIRB_MAJOR_VERSION ${CMAKE_MATCH_1})\n\n  string(REGEX MATCH \"VERSION_MINOR ([0-9]*)\" _ ${ver})\n  set(GTIRB_MINOR_VERSION ${CMAKE_MATCH_1})\n\n  string(REGEX MATCH \"VERSION_PATCH ([0-9]*)\" _ ${ver})\n  set(GTIRB_PATCH_VERSION ${CMAKE_MATCH_1})\n\n  configure_file(\n    \"${ROOTDIR}/include/gtirb/version.h.in\"\n    \"${ROOTDIR}/include/gtirb/version.h\" @ONLY\n  )\n\n  configure_file(\n    \"${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in\"\n    \"${CMAKE_CURRENT_BINARY_DIR}/Doxyfile\" @ONLY\n  )\n\n  configure_file(\n    \"${CMAKE_CURRENT_SOURCE_DIR}/examples.dox\"\n    \"${CMAKE_CURRENT_BINARY_DIR}/examples.dox\" @ONLY\n  )\n\n  # adapted from https://gist.github.com/abravalheri/11214134\n\n  macro(move_filename file_list newdir)\n    foreach(src_file ${${file_list}})\n      get_filename_component(src_file_name \"${src_file}\" NAME)\n      list(REMOVE_ITEM ${file_list} \"${src_file}\")\n      list(APPEND ${file_list} \"${newdir}/${src_file_name}\")\n    endforeach()\n  endmacro()\n\n  # ----------------------------------------------------------------------\n  # copy dot files into a subdir of the working directory\n  # ----------------------------------------------------------------------\n  file(GLOB DOTFILES_IN \"${DOC_INDIR}/dot/*\")\n\n  set(DOTFILES ${DOTFILES_IN})\n  move_filename(DOTFILES ${CMAKE_CURRENT_BINARY_DIR})\n\n  # message(\"DOTFILES = ${DOTFILES}\")\n\n  add_custom_command(\n    OUTPUT ${DOTFILES}\n    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}\n    DEPENDS ${DOTFILES_IN}\n    COMMAND mkdir -p dot\n    COMMAND ${CMAKE_COMMAND} -E copy_directory ${DOC_INDIR}/dot dot\n    COMMENT \"copying dot dir\"\n    VERBATIM\n  )\n\n  # ----------------------------------------------------------------------\n  # copy md files into the working directory\n  # ----------------------------------------------------------------------\n\n  set(MDFILES_IN\n      \"${DOC_INDIR}/general/AuxDataContainer.md\"\n      \"${DOC_INDIR}/general/Block.md\"\n      \"${DOC_INDIR}/general/ByteBlock.md\"\n      \"${DOC_INDIR}/general/ByteInterval.md\"\n      \"${DOC_INDIR}/general/CFG.md\"\n      \"${DOC_INDIR}/general/CfgEdge.md\"\n      \"${DOC_INDIR}/general/CfgEdgeLabel.md\"\n      \"${DOC_INDIR}/general/CfgNode.md\"\n      \"${DOC_INDIR}/general/CodeBlock.md\"\n      \"${DOC_INDIR}/general/COMPONENTS.md\"\n      \"${DOC_INDIR}/general/DataBlock.md\"\n      \"${DOC_INDIR}/general/IR.md\"\n      \"${DOC_INDIR}/general/Module.md\"\n      \"${DOC_INDIR}/general/Node.md\"\n      \"${DOC_INDIR}/general/ProxyBlock.md\"\n      \"${DOC_INDIR}/general/Section.md\"\n      \"${DOC_INDIR}/general/Symbol.md\"\n      \"${DOC_INDIR}/general/SymbolicExpression.md\"\n      \"${DOC_INDIR}/general/SymAddrAddr.md\"\n      \"${DOC_INDIR}/general/SymAddrConst.md\"\n      \"${DOC_INDIR}/general/Version.md\"\n      \"${DOC_INDIR}/binary-representation.md\"\n      \"${DOC_INDIR}/CFG-Edges.md\"\n      \"${ROOTDIR}/AuxData.md\"\n      \"${ROOTDIR}/CONTRIBUTING.md\"\n      \"${ROOTDIR}/FAQ.md\"\n      \"${ROOTDIR}/PROTOBUF.md\"\n      \"${ROOTDIR}/README.md\"\n      \"${DOC_INDIR}/examples/stack-stamp.md\"\n  )\n  set(MDFILES ${MDFILES_IN})\n  move_filename(MDFILES ${CMAKE_CURRENT_BINARY_DIR})\n\n  gtirb_find_python()\n  foreach(_inmd ${MDFILES_IN})\n    get_filename_component(_outmd \"${_inmd}\" NAME)\n    add_custom_command(\n      OUTPUT ${_outmd}\n      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}\n      DEPENDS ${_inmd} ../preprocmd.py\n      COMMAND ${CMAKE_COMMAND} -E copy ${_inmd} \"${_outmd}.in\"\n      COMMAND ${PYTHON} ../preprocmd.py \"${_outmd}.in\" ${_outmd}\n      COMMENT \"processing ${_outmd}\"\n      VERBATIM\n    )\n  endforeach()\n\n  set(SVGFILES_IN \"${ROOTDIR}/.gtirb.svg\"\n                  \"${DOC_INDIR}/examples/.stack-stamp.svg\"\n  )\n  set(SVGFILES ${SVGFILES_IN})\n  move_filename(SVGFILES ${CMAKE_CURRENT_BINARY_DIR})\n\n  foreach(_insvg ${SVGFILES_IN})\n    get_filename_component(_outsvg \"${_insvg}\" NAME)\n    add_custom_command(\n      OUTPUT ${_outsvg}\n      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}\n      DEPENDS ${_insvg}\n      COMMAND ${CMAKE_COMMAND} -E copy ${_insvg} \"${_outsvg}\"\n      COMMENT \"copying ${_outsvg}\"\n      VERBATIM\n    )\n  endforeach()\n\n  # ----------------------------------------------------------------------\n  # Main target\n  # ----------------------------------------------------------------------\n\n  add_custom_target(\n    general_doxyout\n    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}\n    DEPENDS ${MDFILES}\n    DEPENDS ${SVGFILES}\n    COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile\n    COMMENT \"Generating general API documentation with Doxygen\"\n    VERBATIM\n  )\n\n  add_dependencies(doc general_doxyout)\n\n  if(CXX_API)\n    add_dependencies(general_doxyout cpp_doxyout)\n  endif()\n\nendif(DOXYGEN_FOUND)\n"
  },
  {
    "path": "doc/general/COMPONENTS.md",
    "content": "GTIRB Components\n================\n\nThe pages in this section serve two purposes.\n\n* A language-agnostic description of the representation components,\n  with references to language-specific API implementations of these\n  components.\n\n* A normative description of required API features for GTIRB.\n  If you implement a new API for GTIRB, it must satisfy all these requirements.\n\n\n\nComponents that must be represented\n-----------------------------------\n\n| Component                                 | Protobuf Message Type | Notes |\n|-------------------------------------------|-----------------------|-------|\n| [Node](Node.md)                           | -                     | Root class for many components |\n| [IR](IR.md)                               | `IR`                  | A complete internal representation. |\n| [Module](Module.md)                       | `Module`              | Represents a single binary (library or executable) |\n| [Section](Section.md)                     | `Section`             | A named section of a binary. |\n| [ByteInterval](ByteInterval.md)           | `ByteInterval`        | A contiguous region of bytes in a binary.|\n| [CodeBlock](CodeBlock.md)                 | `CodeBlock`           | A basic block in the binary. |\n| [DataBlock](DataBlock.md)                 | `DataBlock`           | A data object, possibly symbolic. |\n| [ProxyBlock](ProxyBlock.md)               | `ProxyBlock`          | A placeholder to serve as the endpoint (source or target) of a [CfgEdge](CfgEdge.md). |\n| [Symbol](Symbol.md)                       | `Symbol`              | Maps a name to an object in the IR. |\n| [CFG](CFG.md)                             | `CFG`                 | The interprocedural control flow graph. |\n| [AuxDataContainer](AuxDataContainer.md)   | -                     | Functionality for associating [auxiliary data](AuxData.md) with elements of the representation.      |\n| [Block](Block.md)                         | -                     | Base class for blocks. |\n| [ByteBlock](ByteBlock.md)                 | -                     | Base class for blocks that belong to a **ByteInterval** and store their bytes there. |\n| [CfgNode](CfgNode.md)                     | -                     | A block that may appear as a vertex in the CFG. |\n| [CfgEdge](CfgEdge.md)                     | `Edge`                | An edge in the CFG. |\n| [CfgEdgeLabel](CfgEdgeLabel.md)           | `EdgeLabel`           | The label on a CfgEdge. |\n| [SymbolicExpression](SymbolicExpression.md) | -                     | A data value or instruction operand which should be interpreted as referring to a symbol. |\n| [SymAddrConst](SymAddrConst.md)           | `SymAddrConst`        | A symbolic operand of the form \"Sym + Offset\". |\n| [SymAddrAddr](SymAddrAddr.md)             | `SymAddrAddr`         | A symbolic operand of the form \"(Sym1 - Sym2) / Scale + Offset\". |\n| [Version information](Version.md)         | -                     | The applicable GTIRB and Protobuf versions. |\n"
  },
  {
    "path": "doc/general/CfgEdge.md",
    "content": "CfgEdge\n====================\n\nA **CfgEdge** represents an edge in the interprocedural\n[control flow graph](CFG.md) (CFG).\n\nThe corresponding Protobuf message type is `Edge`.\n\n\n- A **CfgEdge** may optionally store a [CfgEdgeLabel](CfgEdgeLabel.md).\n\n- There are no guaranteed properties for the **CFG**. There are,\n  however, guaranteed properties for constituent component\n  [CfgEdgeLabel](CfgEdgeLabel.md).\n\n\nAPI Implementations\n--------------------\n\n| Language    | CfgEdge Implementation                            |\n|:------------|:--------------------------------------------------|\n| C++         | no explicit type: add edges with gtirb::addEdge() |\n| Python      | gtirb.Edge                                        |\n| Common Lisp | see [http://eschulte.github.io/graph/](http://eschulte.github.io/graph/). Edges in the CFG are labeled with **edge-label** objects. |\n\n\n\nLinks\n--------------------\n\n- [Advice on when to Place ICFG Edges](../CFG-Edges.md)\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/CfgEdgeLabel.md",
    "content": "CfgEdgeLabel\n====================\n\nA **CfgEdgeLabel** represents the optional label on an edge\n([CfgEdge](CfgEdge.md)) in the interprocedural [control flow\ngraph](CFG.md) (CFG).\n\nThe corresponding Protobuf message type is `EdgeLabel`.\n\n\n\nGuaranteed Properties\n---------------------\n\n- Each **CfgEdgeLabel** object must have the following information,\n  and the API must provide functionality for getting and setting each.\n  - **conditional**\n  - **direct**\n  - **type**\n\n\n\nAPI Implementations\n--------------------\n\n| Language    | CfgEdgeLabel Implementation             |\n|:------------|:----------------------------------------|\n| C++         | gtirb::EdgeLabel                        |\n| Python      | gtirb.Label (inner class of gtirb.Edge) |\n| Common Lisp | **edge-label**                          |\n\n\n\n\n\n### Required Field Getters/Setters\n\n\n#### conditional\n\n| Language    | Get/Set conditional | Get/Set conditional |\n|:------------|:--------------------|:--------------------|\n| C++         | read std::get<ConditionalEdge>(E) for gtirb::EdgeLabel E | read std::get<ConditionalEdge>(E) for gtirb::EdgeLabel E |\n| Python      | read gtirb.CFG.label.conditional | write gtirb.CFG.label.conditional |\n| Common Lisp | **conditional** (*obj* *edge-label*) => *result* | (setf (**conditional** (*obj* *edge-label*)) *new*) |\n\n\n#### direct\n\n| Language    | Get direct | Set direct |\n|:------------|:-----------|:-----------|\n| C++         | read std::get<DirectEdge>(E) for gtirb::EdgeLabel E | read std::get<DirectEdge>(E) for gtirb::EdgeLabel E |\n| Python      | read gtirb.CFG.label.direct | write gtirb.CFG.label.direct |\n| Common Lisp | **direct** (*obj* *edge-label*) => *result* | (setf (**direct** (*obj* *edge-label*)) *new*) |\n\n\n\n\n#### type\n\n| Language    | Get type | Set type |\n|:------------|:---------|:---------|\n| C++         |  read std::get<EdgeType>(E) for gtirb::EdgeLabel E | read std::get<EdgeType>(E) for gtirb::EdgeLabel E |\n| Python      | read gtirb.CFG.label.type | write gtirb.CFG.label.type |\n| Common Lisp | **edge-type** (*obj* *edge-label*) => *result* | (setf (**edge-type** (*obj* *edge-label*)) *new*) |\n\n\n\nLinks\n--------------------\n\n- [Advice on when to Place ICFG Edges](../CFG-Edges.md)\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/CfgNode.md",
    "content": "CfgNode\n====================\n\n**CfgNode** represents a base class for blocks that may appear as\nvertices in the control flow graph (CFG).\n\nGuaranteed Properties\n---------------------\n\n- A **CfgNode** is a [Node](Node.md).\n\n\nAPI Implementations\n--------------------\n\nThe guaranteed functionality is provided as follows.\n\n### CfgNode Classes\n\n| Language    | CfgNode Class  |\n|:------------|:---------------|\n| C++         | gtirb::CfgNode |\n| Python      | gtirb.CfgNode  |\n| Common Lisp | see [http://eschulte.github.io/graph/](http://eschulte.github.io/graph/). Nodes in the CFG contain the UUIDs of **code-block** objects which can be looked up using **get-uuid**. |\n\n\n\nLinks\n--------------------\n\n- [Advice on when to Place ICFG Edges](../CFG-Edges.md)\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/CodeBlock.md",
    "content": "CodeBlock\n====================\n\nA **CodeBlock** represents a basic block in the binary.\n\nThe corresponding Protobuf message type is `CodeBlock`.\n\n\nGuaranteed Properties\n---------------------\n\n- A **CodeBlock** is a [ByteBlock](ByteBlock.md) and a [CfgNode](CfgNode.md).\n\n- Each **CodeBlock** must store its **decode_mode**, and this value\n  must be readable and writable.\n\n\nAPI Implementations\n--------------------\n\nThe guaranteed functionality is provided as follows.\n\n### CodeBlock Classes\n\n| Language    | CodeBlock Class  |\n|:------------|:-----------------|\n| C++         | gtirb::CodeBlock |\n| Python      | gtirb.CodeBlock  |\n| Common Lisp | **code-block**   |\n\n\n\n### decode_mode Getters/Setters\n\n| Language    | Get decode_mode           | Set decode_mode           |\n|:------------|:--------------------------|:--------------------------|\n| C++         | gtirb::CodeBlock::getDecodeMode() | gtirb::Section::setDecodeMode() |\n| Python      | read gtirb.CodeBlock.decode_mode | write gtirb.CodeBlock.decode_mode  |\n| Common Lisp | **decode-mode** (*obj* *code-block*) => *result* | (setf (**decode-mode** (*obj* *code-block*)) *new*) |\n\n\nLinks\n--------------------\n\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/DataBlock.md",
    "content": "DataBlock\n====================\n\nA **DataBlock** represents a data object, possibly symbolic.\n\nThe corresponding Protobuf message type is `DataBlock`.\n\n\nGuaranteed Properties\n---------------------\n\n- A **DataBlock** is a [ByteBlock](ByteBlock.md).\n\n\nAPI Implementations\n--------------------\n\nThe guaranteed functionality is provided as follows.\n\n### DataBlock Classes\n\n| Language    | DataBlock Class  |\n|:------------|:-----------------|\n| C++         | gtirb::DataBlock |\n| Python      | gtirb.DataBlock  |\n| Common Lisp | **data-block**   |\n\n\nLinks\n--------------------\n\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/Doxyfile.in",
    "content": "# Doxyfile 1.8.11\n\n# This file describes the settings to be used by the documentation system\n# doxygen (www.doxygen.org) for a project.\n#\n# All text after a double hash (##) is considered a comment and is placed in\n# front of the TAG it is preceding.\n#\n# All text after a single hash (#) is considered a comment and will be ignored.\n# The format is:\n# TAG = value [value, ...]\n# For lists, items can also be appended using:\n# TAG += value [value, ...]\n# Values that contain spaces should be placed between quotes (\\\" \\\").\n\n#---------------------------------------------------------------------------\n# Project related configuration options\n#---------------------------------------------------------------------------\n\n# This tag specifies the encoding used for all characters in the config file\n# that follow. The default is UTF-8 which is also the encoding used for all text\n# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv\n# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv\n# for the list of possible encodings.\n# The default value is: UTF-8.\n\nDOXYFILE_ENCODING      = UTF-8\n\n# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by\n# double-quotes, unless you are using Doxywizard) that should identify the\n# project for which the documentation is generated. This name is used in the\n# title of most generated pages and in a few other places.\n# The default value is: My Project.\n\nPROJECT_NAME           = GTIRB\n\n# The PROJECT_NUMBER tag can be used to enter a project or revision number. This\n# could be handy for archiving the generated documentation or if some version\n# control system is used.\n\nPROJECT_NUMBER         = v@GTIRB_MAJOR_VERSION@.@GTIRB_MINOR_VERSION@.@GTIRB_PATCH_VERSION@\n\n# Using the PROJECT_BRIEF tag one can provide an optional one line description\n# for a project that appears at the top of each page and should give viewer a\n# quick idea about the purpose of the project. Keep the description short.\n\nPROJECT_BRIEF          = \"GrammaTech Intermediate Representation for Binaries\"\n\n# With the PROJECT_LOGO tag one can specify a logo or an icon that is included\n# in the documentation. The maximum height of the logo should not exceed 55\n# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy\n# the logo to the output directory.\n\nPROJECT_LOGO           =\n\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path\n# into which the generated documentation will be written. If a relative path is\n# entered, it will be relative to the location where doxygen was started. If\n# left blank the current directory will be used.\n\nOUTPUT_DIRECTORY       = @CMAKE_BINARY_DIR@/doc\n\n# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-\n# directories (in 2 levels) under the output directory of each output format and\n# will distribute the generated files over these directories. Enabling this\n# option can be useful when feeding doxygen a huge amount of source files, where\n# putting all generated files in the same directory would otherwise causes\n# performance problems for the file system.\n# The default value is: NO.\n\nCREATE_SUBDIRS         = NO\n\n# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII\n# characters to appear in the names of generated files. If set to NO, non-ASCII\n# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode\n# U+3044.\n# The default value is: NO.\n\nALLOW_UNICODE_NAMES    = NO\n\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all\n# documentation generated by doxygen is written. Doxygen will use this\n# information to generate all constant output in the proper language.\n# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,\n# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),\n# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,\n# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),\n# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,\n# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,\n# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,\n# Ukrainian and Vietnamese.\n# The default value is: English.\n\nOUTPUT_LANGUAGE        = English\n\n# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member\n# descriptions after the members that are listed in the file and class\n# documentation (similar to Javadoc). Set to NO to disable this.\n# The default value is: YES.\n\nBRIEF_MEMBER_DESC      = YES\n\n# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief\n# description of a member or function before the detailed description\n#\n# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the\n# brief descriptions will be completely suppressed.\n# The default value is: YES.\n\nREPEAT_BRIEF           = YES\n\n# This tag implements a quasi-intelligent brief description abbreviator that is\n# used to form the text in various listings. Each string in this list, if found\n# as the leading text of the brief description, will be stripped from the text\n# and the result, after processing the whole list, is used as the annotated\n# text. Otherwise, the brief description is used as-is. If left blank, the\n# following values are used ($name is automatically replaced with the name of\n# the entity):The $name class, The $name widget, The $name file, is, provides,\n# specifies, contains, represents, a, an and the.\n\nABBREVIATE_BRIEF       = \"The $name class\" \\\n                         \"The $name widget\" \\\n                         \"The $name file\" \\\n                         is \\\n                         provides \\\n                         specifies \\\n                         contains \\\n                         represents \\\n                         a \\\n                         an \\\n                         the\n\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then\n# doxygen will generate a detailed section even if there is only a brief\n# description.\n# The default value is: NO.\n\nALWAYS_DETAILED_SEC    = NO\n\n# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all\n# inherited members of a class in the documentation of that class as if those\n# members were ordinary class members. Constructors, destructors and assignment\n# operators of the base classes will not be shown.\n# The default value is: NO.\n\nINLINE_INHERITED_MEMB  = NO\n\n# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path\n# before files name in the file list and in the header files. If set to NO the\n# shortest path that makes the file name unique will be used\n# The default value is: YES.\n\nFULL_PATH_NAMES        = NO\n\n# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.\n# Stripping is only done if one of the specified strings matches the left-hand\n# part of the path. The tag can be used to show relative paths in the file list.\n# If left blank the directory from which doxygen is run is used as the path to\n# strip.\n#\n# Note that you can specify absolute paths here, but also relative paths, which\n# will be relative from the directory where doxygen is started.\n# This tag requires that the tag FULL_PATH_NAMES is set to YES.\n\nSTRIP_FROM_PATH        = .\n\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the\n# path mentioned in the documentation of a class, which tells the reader which\n# header file to include in order to use a class. If left blank only the name of\n# the header file containing the class definition is used. Otherwise one should\n# specify the list of include paths that are normally passed to the compiler\n# using the -I flag.\n\nSTRIP_FROM_INC_PATH    =\n\n# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but\n# less readable) file names. This can be useful is your file systems doesn't\n# support long names like on DOS, Mac, or CD-ROM.\n# The default value is: NO.\n\nSHORT_NAMES            = NO\n\n# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the\n# first line (until the first dot) of a Javadoc-style comment as the brief\n# description. If set to NO, the Javadoc-style will behave just like regular Qt-\n# style comments (thus requiring an explicit @brief command for a brief\n# description.)\n# The default value is: NO.\n\nJAVADOC_AUTOBRIEF      = NO\n\n# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first\n# line (until the first dot) of a Qt-style comment as the brief description. If\n# set to NO, the Qt-style will behave just like regular Qt-style comments (thus\n# requiring an explicit \\brief command for a brief description.)\n# The default value is: NO.\n\nQT_AUTOBRIEF           = NO\n\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a\n# multi-line C++ special comment block (i.e. a block of //! or /// comments) as\n# a brief description. This used to be the default behavior. The new default is\n# to treat a multi-line C++ comment block as a detailed description. Set this\n# tag to YES if you prefer the old behavior instead.\n#\n# Note that setting this tag to YES also means that rational rose comments are\n# not recognized any more.\n# The default value is: NO.\n\nMULTILINE_CPP_IS_BRIEF = NO\n\n# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the\n# documentation from any documented member that it re-implements.\n# The default value is: YES.\n\nINHERIT_DOCS           = YES\n\n# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new\n# page for each member. If set to NO, the documentation of a member will be part\n# of the file/class/namespace that contains it.\n# The default value is: NO.\n\nSEPARATE_MEMBER_PAGES  = NO\n\n# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen\n# uses this value to replace tabs by spaces in code fragments.\n# Minimum value: 1, maximum value: 16, default value: 4.\n\nTAB_SIZE               = 4\n\n# This tag can be used to specify a number of aliases that act as commands in\n# the documentation. An alias has the form:\n# name=value\n# For example adding\n# \"sideeffect=@par Side Effects:\\n\"\n# will allow you to put the command \\sideeffect (or @sideeffect) in the\n# documentation, which will result in a user-defined paragraph with heading\n# \"Side Effects:\". You can put \\n's in the value part of an alias to insert\n# newlines.\n\nALIASES                =\n\n# This tag can be used to specify a number of word-keyword mappings (TCL only).\n# A mapping has the form \"name=value\". For example adding \"class=itcl::class\"\n# will allow you to use the command class in the itcl::class meaning.\n\nTCL_SUBST              =\n\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources\n# only. Doxygen will then generate output that is more tailored for C. For\n# instance, some of the names that are used will be different. The list of all\n# members will be omitted, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_FOR_C  = NO\n\n# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or\n# Python sources only. Doxygen will then generate output that is more tailored\n# for that language. For instance, namespaces will be presented as packages,\n# qualified scopes will look different, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_JAVA   = NO\n\n# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran\n# sources. Doxygen will then generate output that is tailored for Fortran.\n# The default value is: NO.\n\nOPTIMIZE_FOR_FORTRAN   = NO\n\n# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL\n# sources. Doxygen will then generate output that is tailored for VHDL.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_VHDL   = NO\n\n# Doxygen selects the parser to use depending on the extension of the files it\n# parses. With this tag you can assign which parser to use for a given\n# extension. Doxygen has a built-in mapping, but you can override or extend it\n# using this tag. The format is ext=language, where ext is a file extension, and\n# language is one of the parsers supported by doxygen: IDL, Java, Javascript,\n# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:\n# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:\n# Fortran. In the later case the parser tries to guess whether the code is fixed\n# or free formatted code, this is the default for Fortran type files), VHDL. For\n# instance to make doxygen treat .inc files as Fortran files (default is PHP),\n# and .f files as C (default is Fortran), use: inc=Fortran f=C.\n#\n# Note: For files without extension you can use no_extension as a placeholder.\n#\n# Note that for custom extensions you also need to set FILE_PATTERNS otherwise\n# the files are not read by doxygen.\n\nEXTENSION_MAPPING      =\n\n# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments\n# according to the Markdown format, which allows for more readable\n# documentation. See http://daringfireball.net/projects/markdown/ for details.\n# The output of markdown processing is further processed by doxygen, so you can\n# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in\n# case of backward compatibilities issues.\n# The default value is: YES.\n\nMARKDOWN_SUPPORT       = YES\n\nTOC_INCLUDE_HEADINGS   = 4\n\n\n# When enabled doxygen tries to link words that correspond to documented\n# classes, or namespaces to their corresponding documentation. Such a link can\n# be prevented in individual cases by putting a % sign in front of the word or\n# globally by setting AUTOLINK_SUPPORT to NO.\n# The default value is: YES.\n\nAUTOLINK_SUPPORT       = YES\n\n# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want\n# to include (a tag file for) the STL sources as input, then you should set this\n# tag to YES in order to let doxygen match functions declarations and\n# definitions whose arguments contain STL classes (e.g. func(std::string);\n# versus func(std::string) {}). This also make the inheritance and collaboration\n# diagrams that involve STL classes more complete and accurate.\n# The default value is: NO.\n\nBUILTIN_STL_SUPPORT    = NO\n\n# If you use Microsoft's C++/CLI language, you should set this option to YES to\n# enable parsing support.\n# The default value is: NO.\n\nCPP_CLI_SUPPORT        = NO\n\n# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:\n# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen\n# will parse them like normal C++ but will assume all classes use public instead\n# of private inheritance when no explicit protection keyword is present.\n# The default value is: NO.\n\nSIP_SUPPORT            = NO\n\n# For Microsoft's IDL there are propget and propput attributes to indicate\n# getter and setter methods for a property. Setting this option to YES will make\n# doxygen to replace the get and set methods by a property in the documentation.\n# This will only work if the methods are indeed getting or setting a simple\n# type. If this is not the case, or you want to show the methods anyway, you\n# should set this option to NO.\n# The default value is: YES.\n\nIDL_PROPERTY_SUPPORT   = YES\n\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC\n# tag is set to YES then doxygen will reuse the documentation of the first\n# member in the group (if any) for the other members of the group. By default\n# all members of a group must be documented explicitly.\n# The default value is: NO.\n\nDISTRIBUTE_GROUP_DOC   = NO\n\n# If one adds a struct or class to a group and this option is enabled, then also\n# any nested class or struct is added to the same group. By default this option\n# is disabled and one has to add nested compounds explicitly via \\ingroup.\n# The default value is: NO.\n\nGROUP_NESTED_COMPOUNDS = NO\n\n# Set the SUBGROUPING tag to YES to allow class member groups of the same type\n# (for instance a group of public functions) to be put as a subgroup of that\n# type (e.g. under the Public Functions section). Set it to NO to prevent\n# subgrouping. Alternatively, this can be done per class using the\n# \\nosubgrouping command.\n# The default value is: YES.\n\nSUBGROUPING            = YES\n\n# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions\n# are shown inside the group in which they are included (e.g. using \\ingroup)\n# instead of on a separate page (for HTML and Man pages) or section (for LaTeX\n# and RTF).\n#\n# Note that this feature does not work in combination with\n# SEPARATE_MEMBER_PAGES.\n# The default value is: NO.\n\nINLINE_GROUPED_CLASSES = NO\n\n# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions\n# with only public data fields or simple typedef fields will be shown inline in\n# the documentation of the scope in which they are defined (i.e. file,\n# namespace, or group documentation), provided this scope is documented. If set\n# to NO, structs, classes, and unions are shown on a separate page (for HTML and\n# Man pages) or section (for LaTeX and RTF).\n# The default value is: NO.\n\nINLINE_SIMPLE_STRUCTS  = NO\n\n# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or\n# enum is documented as struct, union, or enum with the name of the typedef. So\n# typedef struct TypeS {} TypeT, will appear in the documentation as a struct\n# with name TypeT. When disabled the typedef will appear as a member of a file,\n# namespace, or class. And the struct will be named TypeS. This can typically be\n# useful for C code in case the coding convention dictates that all compound\n# types are typedef'ed and only the typedef is referenced, never the tag name.\n# The default value is: NO.\n\nTYPEDEF_HIDES_STRUCT   = YES\n\n# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This\n# cache is used to resolve symbols given their name and scope. Since this can be\n# an expensive process and often the same symbol appears multiple times in the\n# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small\n# doxygen will become slower. If the cache is too large, memory is wasted. The\n# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range\n# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536\n# symbols. At the end of a run doxygen will report the cache usage and suggest\n# the optimal cache size from a speed point of view.\n# Minimum value: 0, maximum value: 9, default value: 0.\n\nLOOKUP_CACHE_SIZE      = 0\n\n#---------------------------------------------------------------------------\n# Build related configuration options\n#---------------------------------------------------------------------------\n\n# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in\n# documentation are documented, even if no documentation was available. Private\n# class members and static file members will be hidden unless the\n# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.\n# Note: This will also disable the warnings about undocumented members that are\n# normally produced when WARNINGS is set to YES.\n# The default value is: NO.\n\nEXTRACT_ALL            = YES\n\n# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will\n# be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PRIVATE        = NO\n\n# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal\n# scope will be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PACKAGE        = NO\n\n# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be\n# included in the documentation.\n# The default value is: NO.\n\nEXTRACT_STATIC         = NO\n\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined\n# locally in source files will be included in the documentation. If set to NO,\n# only classes defined in header files are included. Does not have any effect\n# for Java sources.\n# The default value is: YES.\n\nEXTRACT_LOCAL_CLASSES  = YES\n\n# This flag is only useful for Objective-C code. If set to YES, local methods,\n# which are defined in the implementation section but not in the interface are\n# included in the documentation. If set to NO, only methods in the interface are\n# included.\n# The default value is: NO.\n\nEXTRACT_LOCAL_METHODS  = NO\n\n# If this flag is set to YES, the members of anonymous namespaces will be\n# extracted and appear in the documentation as a namespace called\n# 'anonymous_namespace{file}', where file will be replaced with the base name of\n# the file that contains the anonymous namespace. By default anonymous namespace\n# are hidden.\n# The default value is: NO.\n\nEXTRACT_ANON_NSPACES   = YES\n\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all\n# undocumented members inside documented classes or files. If set to NO these\n# members will be included in the various overviews, but no documentation\n# section is generated. This option has no effect if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_MEMBERS     = NO\n\n# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all\n# undocumented classes that are normally visible in the class hierarchy. If set\n# to NO, these classes will be included in the various overviews. This option\n# has no effect if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_CLASSES     = NO\n\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend\n# (class|struct|union) declarations. If set to NO, these declarations will be\n# included in the documentation.\n# The default value is: NO.\n\nHIDE_FRIEND_COMPOUNDS  = NO\n\n# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any\n# documentation blocks found inside the body of a function. If set to NO, these\n# blocks will be appended to the function's detailed documentation block.\n# The default value is: NO.\n\nHIDE_IN_BODY_DOCS      = NO\n\n# The INTERNAL_DOCS tag determines if documentation that is typed after a\n# \\internal command is included. If the tag is set to NO then the documentation\n# will be excluded. Set it to YES to include the internal documentation.\n# The default value is: NO.\n\nINTERNAL_DOCS          = NO\n\n# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file\n# names in lower-case letters. If set to YES, upper-case letters are also\n# allowed. This is useful if you have classes or files whose names only differ\n# in case and if your file system supports case sensitive file names. Windows\n# and Mac users are advised to set this option to NO.\n# The default value is: system dependent.\n\nCASE_SENSE_NAMES       = NO\n\n# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with\n# their full class and namespace scopes in the documentation. If set to YES, the\n# scope will be hidden.\n# The default value is: NO.\n\nHIDE_SCOPE_NAMES       = NO\n\n# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will\n# append additional text to a page's title, such as Class Reference. If set to\n# YES the compound reference will be hidden.\n# The default value is: NO.\n\nHIDE_COMPOUND_REFERENCE= NO\n\n# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of\n# the files that are included by a file in the documentation of that file.\n# The default value is: YES.\n\nSHOW_INCLUDE_FILES     = YES\n\n# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each\n# grouped member an include statement to the documentation, telling the reader\n# which file to include in order to use the member.\n# The default value is: NO.\n\nSHOW_GROUPED_MEMB_INC  = YES\n\n# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include\n# files with double quotes in the documentation rather than with sharp brackets.\n# The default value is: NO.\n\nFORCE_LOCAL_INCLUDES   = NO\n\n# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the\n# documentation for inline members.\n# The default value is: YES.\n\nINLINE_INFO            = YES\n\n# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the\n# (detailed) documentation of file and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order.\n# The default value is: YES.\n\nSORT_MEMBER_DOCS       = YES\n\n# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief\n# descriptions of file, namespace and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order. Note that\n# this will also influence the order of the classes in the class list.\n# The default value is: NO.\n\nSORT_BRIEF_DOCS        = YES\n\n# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the\n# (brief and detailed) documentation of class members so that constructors and\n# destructors are listed first. If set to NO the constructors will appear in the\n# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.\n# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief\n# member documentation.\n# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting\n# detailed member documentation.\n# The default value is: NO.\n\nSORT_MEMBERS_CTORS_1ST = YES\n\n# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy\n# of group names into alphabetical order. If set to NO the group names will\n# appear in their defined order.\n# The default value is: NO.\n\nSORT_GROUP_NAMES       = YES\n\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by\n# fully-qualified names, including namespaces. If set to NO, the class list will\n# be sorted only by class name, not including the namespace part.\n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n# Note: This option applies only to the class list, not to the alphabetical\n# list.\n# The default value is: NO.\n\nSORT_BY_SCOPE_NAME     = NO\n\n# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper\n# type resolution of all parameters of a function it will reject a match between\n# the prototype and the implementation of a member function even if there is\n# only one candidate or it is obvious which candidate to choose by doing a\n# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still\n# accept a match between prototype and implementation in such cases.\n# The default value is: NO.\n\nSTRICT_PROTO_MATCHING  = NO\n\n# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo\n# list. This list is created by putting \\todo commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TODOLIST      = YES\n\n# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test\n# list. This list is created by putting \\test commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TESTLIST      = YES\n\n# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug\n# list. This list is created by putting \\bug commands in the documentation.\n# The default value is: YES.\n\nGENERATE_BUGLIST       = YES\n\n# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)\n# the deprecated list. This list is created by putting \\deprecated commands in\n# the documentation.\n# The default value is: YES.\n\nGENERATE_DEPRECATEDLIST= YES\n\n# The ENABLED_SECTIONS tag can be used to enable conditional documentation\n# sections, marked by \\if <section_label> ... \\endif and \\cond <section_label>\n# ... \\endcond blocks.\n\nENABLED_SECTIONS       = @CPP_DOX_ENABLED@ @CL_DOX_ENABLED@ @PY_DOX_ENABLED@\n\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the\n# initial value of a variable or macro / define can have for it to appear in the\n# documentation. If the initializer consists of more lines than specified here\n# it will be hidden. Use a value of 0 to hide initializers completely. The\n# appearance of the value of individual variables and macros / defines can be\n# controlled using \\showinitializer or \\hideinitializer command in the\n# documentation regardless of this setting.\n# Minimum value: 0, maximum value: 10000, default value: 30.\n\nMAX_INITIALIZER_LINES  = 30\n\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at\n# the bottom of the documentation of classes and structs. If set to YES, the\n# list will mention the files that were used to generate the documentation.\n# The default value is: YES.\n\nSHOW_USED_FILES        = YES\n\n# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This\n# will remove the Files entry from the Quick Index and from the Folder Tree View\n# (if specified).\n# The default value is: YES.\n\nSHOW_FILES             = YES\n\n# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces\n# page. This will remove the Namespaces entry from the Quick Index and from the\n# Folder Tree View (if specified).\n# The default value is: YES.\n\nSHOW_NAMESPACES        = YES\n\n# The FILE_VERSION_FILTER tag can be used to specify a program or script that\n# doxygen should invoke to get the current version for each file (typically from\n# the version control system). Doxygen will invoke the program by executing (via\n# popen()) the command command input-file, where command is the value of the\n# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided\n# by doxygen. Whatever the program writes to standard output is used as the file\n# version. For an example see the documentation.\n\nFILE_VERSION_FILTER    =\n\n# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed\n# by doxygen. The layout file controls the global structure of the generated\n# output files in an output format independent way. To create the layout file\n# that represents doxygen's defaults, run doxygen with the -l option. You can\n# optionally specify a file name after the option, if omitted DoxygenLayout.xml\n# will be used as the name of the layout file.\n#\n# Note that if you run doxygen from a directory containing a file called\n# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE\n# tag is left empty.\n\nLAYOUT_FILE            =\n\n# The CITE_BIB_FILES tag can be used to specify one or more bib files containing\n# the reference definitions. This must be a list of .bib files. The .bib\n# extension is automatically appended if omitted. This requires the bibtex tool\n# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.\n# For LaTeX the style of the bibliography can be controlled using\n# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the\n# search path. See also \\cite for info how to create references.\n\nCITE_BIB_FILES         =\n\n#---------------------------------------------------------------------------\n# Configuration options related to warning and progress messages\n#---------------------------------------------------------------------------\n\n# The QUIET tag can be used to turn on/off the messages that are generated to\n# standard output by doxygen. If QUIET is set to YES this implies that the\n# messages are off.\n# The default value is: NO.\n\nQUIET                  = NO\n\n# The WARNINGS tag can be used to turn on/off the warning messages that are\n# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES\n# this implies that the warnings are on.\n#\n# Tip: Turn warnings on while writing the documentation.\n# The default value is: YES.\n\nWARNINGS               = YES\n\n# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate\n# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag\n# will automatically be disabled.\n# The default value is: YES.\n\nWARN_IF_UNDOCUMENTED   = YES\n\n# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for\n# potential errors in the documentation, such as not documenting some parameters\n# in a documented function, or documenting parameters that don't exist or using\n# markup commands wrongly.\n# The default value is: YES.\n\nWARN_IF_DOC_ERROR      = YES\n\n# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that\n# are documented, but have no documentation for their parameters or return\n# value. If set to NO, doxygen will only warn about wrong or incomplete\n# parameter documentation, but not about the absence of documentation.\n# The default value is: NO.\n\nWARN_NO_PARAMDOC       = NO\n\n# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when\n# a warning is encountered.\n# The default value is: NO.\n\nWARN_AS_ERROR          = NO\n\n# The WARN_FORMAT tag determines the format of the warning messages that doxygen\n# can produce. The string should contain the $file, $line, and $text tags, which\n# will be replaced by the file and line number from which the warning originated\n# and the warning text. Optionally the format may contain $version, which will\n# be replaced by the version of the file (if it could be obtained via\n# FILE_VERSION_FILTER)\n# The default value is: $file:$line: $text.\n\nWARN_FORMAT            = \"$file:$line: $text\"\n\n# The WARN_LOGFILE tag can be used to specify a file to which warning and error\n# messages should be written. If left blank the output is written to standard\n# error (stderr).\n\nWARN_LOGFILE           = doxygen_warnings.txt\n\n#---------------------------------------------------------------------------\n# Configuration options related to the input files\n#---------------------------------------------------------------------------\n\n# The INPUT tag is used to specify the files and/or directories that contain\n# documented source files. You may enter file names like myfile.cpp or\n# directories like /usr/src/myproject. Separate the files or directories with\n# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING\n# Note: If this tag is empty the current directory is searched.\n\n# Explicitly naming the .md files allows us to force an order in the\n# TOC (otherwise it will be alphabetical)\n\nINPUT   += README.md FAQ.md PROTOBUF.md CFG-Edges.md AuxData.md CONTRIBUTING.md\nINPUT   += AuxDataContainer.md Block.md ByteBlock.md ByteInterval.md\nINPUT   += CFG.md CfgEdge.md CfgEdgeLabel.md CfgNode.md CodeBlock.md\nINPUT   += COMPONENTS.md DataBlock.md IR.md Module.md Node.md ProxyBlock.md\nINPUT   += Section.md Symbol.md SymbolicExpression.md SymAddrAddr.md\nINPUT   += SymAddrConst.md Version.md stack-stamp.md\nINPUT   += binary-representation.md\nINPUT   += examples.dox\nINPUT   += images.dox\n\n\n# This tag can be used to specify the character encoding of the source files\n# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses\n# libiconv (or the iconv built into libc) for the transcoding. See the libiconv\n# documentation (see: http://www.gnu.org/software/libiconv) for the list of\n# possible encodings.\n# The default value is: UTF-8.\n\nINPUT_ENCODING         = UTF-8\n\n# If the value of the INPUT tag contains directories, you can use the\n# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and\n# *.h) to filter out the source-files in the directories.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# read by doxygen.\n#\n# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,\n# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,\n# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,\n# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,\n# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.\n\nFILE_PATTERNS          = *.c \\\n                         *.cc \\\n                         *.cxx \\\n                         *.cpp \\\n                         *.c++ \\\n                         *.java \\\n                         *.ii \\\n                         *.ixx \\\n                         *.ipp \\\n                         *.i++ \\\n                         *.inl \\\n                         *.idl \\\n                         *.ddl \\\n                         *.odl \\\n                         *.h \\\n                         *.hh \\\n                         *.hxx \\\n                         *.hpp \\\n                         *.h++ \\\n                         *.cs \\\n                         *.d \\\n                         *.php \\\n                         *.php4 \\\n                         *.php5 \\\n                         *.phtml \\\n                         *.inc \\\n                         *.m \\\n                         *.markdown \\\n                         *.md \\\n                         *.mm \\\n                         *.dox \\\n                         *.py \\\n                         *.pyw \\\n                         *.f90 \\\n                         *.f \\\n                         *.for \\\n                         *.tcl \\\n                         *.vhd \\\n                         *.vhdl \\\n                         *.ucf \\\n                         *.qsf \\\n                         *.as \\\n                         *.js\n\n# The RECURSIVE tag can be used to specify whether or not subdirectories should\n# be searched for input files as well.\n# The default value is: NO.\n\nRECURSIVE              = YES\n\n# The EXCLUDE tag can be used to specify files and/or directories that should be\n# excluded from the INPUT source files. This way you can easily exclude a\n# subdirectory from a directory tree whose root is specified with the INPUT tag.\n#\n# Note that relative paths are relative to the directory from which doxygen is\n# run.\n\nEXCLUDE                =\n\n# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or\n# directories that are symbolic links (a Unix file system feature) are excluded\n# from the input.\n# The default value is: NO.\n\nEXCLUDE_SYMLINKS       = NO\n\n# If the value of the INPUT tag contains directories, you can use the\n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude\n# certain files from those directories.\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories for example use the pattern */test/*\n\nEXCLUDE_PATTERNS       = */include/proto/*.h\n\n# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names\n# (namespaces, classes, functions, etc.) that should be excluded from the\n# output. The symbol name can be a fully qualified name, a word, or if the\n# wildcard * is used, a substring. Examples: ANamespace, AClass,\n# AClass::ANamespace, ANamespace::*Test\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories use the pattern */test/*\n\nEXCLUDE_SYMBOLS        = proto\n\n# The EXAMPLE_PATH tag can be used to specify one or more files or directories\n# that contain example code fragments that are included (see the \\include\n# command).\n\nEXAMPLE_PATH           = @CMAKE_CURRENT_SOURCE_DIR@/../examples\n\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the\n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and\n# *.h) to filter out the source-files in the directories. If left blank all\n# files are included.\n\nEXAMPLE_PATTERNS       = *\n\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be\n# searched for input files to be used with the \\include or \\dontinclude commands\n# irrespective of the value of the RECURSIVE tag.\n# The default value is: NO.\n\nEXAMPLE_RECURSIVE      = NO\n\n# The IMAGE_PATH tag can be used to specify one or more files or directories\n# that contain images that are to be included in the documentation (see the\n# \\image command).\n\nIMAGE_PATH             = @CMAKE_CURRENT_SOURCE_DIR@/../../\n\n# The INPUT_FILTER tag can be used to specify a program that doxygen should\n# invoke to filter for each input file. Doxygen will invoke the filter program\n# by executing (via popen()) the command:\n#\n# <filter> <input-file>\n#\n# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the\n# name of an input file. Doxygen will then use the output that the filter\n# program writes to standard output. If FILTER_PATTERNS is specified, this tag\n# will be ignored.\n#\n# Note that the filter must not add or remove lines; it is applied before the\n# code is scanned, but not when the output code is generated. If lines are added\n# or removed, the anchors will not be placed correctly.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by doxygen.\n\nINPUT_FILTER           =\n\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern\n# basis. Doxygen will compare the file name with each pattern and apply the\n# filter if there is a match. The filters are a list of the form: pattern=filter\n# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how\n# filters are used. If the FILTER_PATTERNS tag is empty or if none of the\n# patterns match the file name, INPUT_FILTER is applied.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by doxygen.\n\nFILTER_PATTERNS        =\n\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using\n# INPUT_FILTER) will also be used to filter the input files that are used for\n# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).\n# The default value is: NO.\n\nFILTER_SOURCE_FILES    = NO\n\n# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file\n# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and\n# it is also possible to disable source filtering for a specific pattern using\n# *.ext= (so without naming a filter).\n# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.\n\nFILTER_SOURCE_PATTERNS =\n\n# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that\n# is part of the input, its contents will be placed on the main page\n# (index.html). This can be useful if you have a project on for instance GitHub\n# and want to reuse the introduction page also for the doxygen output.\n\nUSE_MDFILE_AS_MAINPAGE = README.md\n\n#---------------------------------------------------------------------------\n# Configuration options related to source browsing\n#---------------------------------------------------------------------------\n\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will be\n# generated. Documented entities will be cross-referenced with these sources.\n#\n# Note: To get rid of all source code in the generated output, make sure that\n# also VERBATIM_HEADERS is set to NO.\n# The default value is: NO.\n\nSOURCE_BROWSER         = NO\n\n# Setting the INLINE_SOURCES tag to YES will include the body of functions,\n# classes and enums directly into the documentation.\n# The default value is: NO.\n\nINLINE_SOURCES         = NO\n\n# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any\n# special comment blocks from generated source code fragments. Normal C, C++ and\n# Fortran comments will always remain visible.\n# The default value is: YES.\n\nSTRIP_CODE_COMMENTS    = YES\n\n# If the REFERENCED_BY_RELATION tag is set to YES then for each documented\n# function all documented functions referencing it will be listed.\n# The default value is: NO.\n\nREFERENCED_BY_RELATION = NO\n\n# If the REFERENCES_RELATION tag is set to YES then for each documented function\n# all documented entities called/used by that function will be listed.\n# The default value is: NO.\n\nREFERENCES_RELATION    = NO\n\n# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set\n# to YES then the hyperlinks from functions in REFERENCES_RELATION and\n# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will\n# link to the documentation.\n# The default value is: YES.\n\nREFERENCES_LINK_SOURCE = YES\n\n# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the\n# source code will show a tooltip with additional information such as prototype,\n# brief description and links to the definition and documentation. Since this\n# will make the HTML file larger and loading of large files a bit slower, you\n# can opt to disable this feature.\n# The default value is: YES.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nSOURCE_TOOLTIPS        = YES\n\n# If the USE_HTAGS tag is set to YES then the references to source code will\n# point to the HTML generated by the htags(1) tool instead of doxygen built-in\n# source browser. The htags tool is part of GNU's global source tagging system\n# (see http://www.gnu.org/software/global/global.html). You will need version\n# 4.8.6 or higher.\n#\n# To use it do the following:\n# - Install the latest version of global\n# - Enable SOURCE_BROWSER and USE_HTAGS in the config file\n# - Make sure the INPUT points to the root of the source tree\n# - Run doxygen as normal\n#\n# Doxygen will invoke htags (and that will in turn invoke gtags), so these\n# tools must be available from the command line (i.e. in the search path).\n#\n# The result: instead of the source browser generated by doxygen, the links to\n# source code will now point to the output of htags.\n# The default value is: NO.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nUSE_HTAGS              = NO\n\n# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a\n# verbatim copy of the header file for each class for which an include is\n# specified. Set to NO to disable this.\n# See also: Section \\class.\n# The default value is: YES.\n\nVERBATIM_HEADERS       = YES\n\n# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the\n# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the\n# cost of reduced performance. This can be particularly helpful with template\n# rich C++ code for which doxygen's built-in parser lacks the necessary type\n# information.\n# Note: The availability of this option depends on whether or not doxygen was\n# generated with the -Duse-libclang=ON option for CMake.\n# The default value is: NO.\n\nCLANG_ASSISTED_PARSING = NO\n\n# If clang assisted parsing is enabled you can provide the compiler with command\n# line options that you would normally use when invoking the compiler. Note that\n# the include paths will already be set by doxygen for the files and directories\n# specified with INPUT and INCLUDE_PATH.\n# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.\n\nCLANG_OPTIONS          =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the alphabetical class index\n#---------------------------------------------------------------------------\n\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all\n# compounds will be generated. Enable this if the project contains a lot of\n# classes, structs, unions or interfaces.\n# The default value is: YES.\n\nALPHABETICAL_INDEX     = YES\n\n# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in\n# which the alphabetical index list will be split.\n# Minimum value: 1, maximum value: 20, default value: 5.\n# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.\n\nCOLS_IN_ALPHA_INDEX    = 5\n\n# In case all classes in a project start with a common prefix, all classes will\n# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag\n# can be used to specify a prefix (or a list of prefixes) that should be ignored\n# while generating the index headers.\n# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.\n\nIGNORE_PREFIX          =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the HTML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output\n# The default value is: YES.\n\nGENERATE_HTML          = YES\n\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_OUTPUT            = html\n\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each\n# generated HTML page (for example: .htm, .php, .asp).\n# The default value is: .html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FILE_EXTENSION    = .html\n\n# The HTML_HEADER tag can be used to specify a user-defined HTML header file for\n# each generated HTML page. If the tag is left blank doxygen will generate a\n# standard header.\n#\n# To get valid HTML the header file that includes any scripts and style sheets\n# that doxygen needs, which is dependent on the configuration options used (e.g.\n# the setting GENERATE_TREEVIEW). It is highly recommended to start with a\n# default header using\n# doxygen -w html new_header.html new_footer.html new_stylesheet.css\n# YourConfigFile\n# and then modify the file new_header.html. See also section \"Doxygen usage\"\n# for information on how to generate the default header that doxygen normally\n# uses.\n# Note: The header is subject to change so you typically have to regenerate the\n# default header when upgrading to a newer version of doxygen. For a description\n# of the possible markers and block names see the documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_HEADER            =\n\n# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each\n# generated HTML page. If the tag is left blank doxygen will generate a standard\n# footer. See HTML_HEADER for more information on how to generate a default\n# footer and what special commands can be used inside the footer. See also\n# section \"Doxygen usage\" for information on how to generate the default footer\n# that doxygen normally uses.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FOOTER            =\n\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style\n# sheet that is used by each HTML page. It can be used to fine-tune the look of\n# the HTML output. If left blank doxygen will generate a default style sheet.\n# See also section \"Doxygen usage\" for information on how to generate the style\n# sheet that doxygen normally uses.\n# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as\n# it is more robust and this tag (HTML_STYLESHEET) will in the future become\n# obsolete.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_STYLESHEET        =\n\n# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# cascading style sheets that are included after the standard style sheets\n# created by doxygen. Using this option one can overrule certain style aspects.\n# This is preferred over using HTML_STYLESHEET since it does not replace the\n# standard style sheet and is therefore more robust against future updates.\n# Doxygen will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list). For an example see the documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_STYLESHEET  =\n\n# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the HTML output directory. Note\n# that these files will be copied to the base HTML output directory. Use the\n# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these\n# files. In the HTML_STYLESHEET file, use the file name only. Also note that the\n# files will be copied as-is; there are no commands or markers available.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_FILES       =\n\n# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen\n# will adjust the colors in the style sheet and background images according to\n# this color. Hue is specified as an angle on a colorwheel, see\n# http://en.wikipedia.org/wiki/Hue for more information. For instance the value\n# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300\n# purple, and 360 is red again.\n# Minimum value: 0, maximum value: 359, default value: 220.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_HUE    = 220\n\n# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors\n# in the HTML output. For a value of 0 the output will use grayscales only. A\n# value of 255 will produce the most vivid colors.\n# Minimum value: 0, maximum value: 255, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_SAT    = 100\n\n# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the\n# luminance component of the colors in the HTML output. Values below 100\n# gradually make the output lighter, whereas values above 100 make the output\n# darker. The value divided by 100 is the actual gamma applied, so 80 represents\n# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not\n# change the gamma.\n# Minimum value: 40, maximum value: 240, default value: 80.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_GAMMA  = 80\n\n# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML\n# page will contain the date and time when the page was generated. Setting this\n# to YES can help to show when doxygen was last run and thus if the\n# documentation is up to date.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_TIMESTAMP         = NO\n\n# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML\n# documentation will contain sections that can be hidden and shown after the\n# page has loaded.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_DYNAMIC_SECTIONS  = NO\n\n# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries\n# shown in the various tree structured indices initially; the user can expand\n# and collapse entries dynamically later on. Doxygen will expand the tree to\n# such a level that at most the specified number of entries are visible (unless\n# a fully collapsed tree already exceeds this amount). So setting the number of\n# entries 1 will produce a full collapsed tree by default. 0 is a special value\n# representing an infinite number of entries and will result in a full expanded\n# tree by default.\n# Minimum value: 0, maximum value: 9999, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_INDEX_NUM_ENTRIES = 100\n\n# If the GENERATE_DOCSET tag is set to YES, additional index files will be\n# generated that can be used as input for Apple's Xcode 3 integrated development\n# environment (see: http://developer.apple.com/tools/xcode/), introduced with\n# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a\n# Makefile in the HTML output directory. Running make will produce the docset in\n# that directory and running make install will install the docset in\n# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at\n# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html\n# for more information.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_DOCSET        = NO\n\n# This tag determines the name of the docset feed. A documentation feed provides\n# an umbrella under which multiple documentation sets from a single provider\n# (such as a company or product suite) can be grouped.\n# The default value is: Doxygen generated docs.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_FEEDNAME        = \"Doxygen generated docs\"\n\n# This tag specifies a string that should uniquely identify the documentation\n# set bundle. This should be a reverse domain-name style string, e.g.\n# com.mycompany.MyDocSet. Doxygen will append .docset to the name.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_BUNDLE_ID       = org.doxygen.Project\n\n# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify\n# the documentation publisher. This should be a reverse domain-name style\n# string, e.g. com.mycompany.MyDocSet.documentation.\n# The default value is: org.doxygen.Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_ID    = org.doxygen.Publisher\n\n# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.\n# The default value is: Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_NAME  = Publisher\n\n# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three\n# additional HTML index files: index.hhp, index.hhc, and index.hhk. The\n# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop\n# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on\n# Windows.\n#\n# The HTML Help Workshop contains a compiler that can convert all HTML output\n# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML\n# files are now used as the Windows 98 help format, and will replace the old\n# Windows help format (.hlp) on all Windows platforms in the future. Compressed\n# HTML files also contain an index, a table of contents, and you can search for\n# words in the documentation. The HTML workshop also contains a viewer for\n# compressed HTML files.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_HTMLHELP      = NO\n\n# The CHM_FILE tag can be used to specify the file name of the resulting .chm\n# file. You can add a path in front of the file if the result should not be\n# written to the html output directory.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_FILE               =\n\n# The HHC_LOCATION tag can be used to specify the location (absolute path\n# including file name) of the HTML help compiler (hhc.exe). If non-empty,\n# doxygen will try to run the HTML help compiler on the generated index.hhp.\n# The file has to be specified with full path.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nHHC_LOCATION           =\n\n# The GENERATE_CHI flag controls if a separate .chi index file is generated\n# (YES) or that it should be included in the master .chm file (NO).\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nGENERATE_CHI           = NO\n\n# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)\n# and project file content.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_INDEX_ENCODING     =\n\n# The BINARY_TOC flag controls whether a binary table of contents is generated\n# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it\n# enables the Previous and Next buttons.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nBINARY_TOC             = NO\n\n# The TOC_EXPAND flag can be set to YES to add extra items for group members to\n# the table of contents of the HTML help documentation and to the tree view.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nTOC_EXPAND             = NO\n\n# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and\n# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that\n# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help\n# (.qch) of the generated HTML documentation.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_QHP           = NO\n\n# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify\n# the file name of the resulting .qch file. The path specified is relative to\n# the HTML output folder.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQCH_FILE               =\n\n# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help\n# Project output. For more information please see Qt Help Project / Namespace\n# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_NAMESPACE          = org.doxygen.Project\n\n# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt\n# Help Project output. For more information please see Qt Help Project / Virtual\n# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-\n# folders).\n# The default value is: doc.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_VIRTUAL_FOLDER     = doc\n\n# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom\n# filter to add. For more information please see Qt Help Project / Custom\n# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-\n# filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_NAME   =\n\n# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the\n# custom filter to add. For more information please see Qt Help Project / Custom\n# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-\n# filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_ATTRS  =\n\n# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this\n# project's filter section matches. Qt Help Project / Filter Attributes (see:\n# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_SECT_FILTER_ATTRS  =\n\n# The QHG_LOCATION tag can be used to specify the location of Qt's\n# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the\n# generated .qhp file.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHG_LOCATION           =\n\n# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be\n# generated, together with the HTML files, they form an Eclipse help plugin. To\n# install this plugin and make it available under the help contents menu in\n# Eclipse, the contents of the directory containing the HTML and XML files needs\n# to be copied into the plugins directory of eclipse. The name of the directory\n# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.\n# After copying Eclipse needs to be restarted before the help appears.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_ECLIPSEHELP   = NO\n\n# A unique identifier for the Eclipse help plugin. When installing the plugin\n# the directory name containing the HTML and XML files should also have this\n# name. Each documentation set should have its own identifier.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.\n\nECLIPSE_DOC_ID         = org.doxygen.Project\n\n# If you want full control over the layout of the generated HTML pages it might\n# be necessary to disable the index and replace it with your own. The\n# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top\n# of each HTML page. A value of NO enables the index and the value YES disables\n# it. Since the tabs in the index contain the same information as the navigation\n# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nDISABLE_INDEX          = NO\n\n# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index\n# structure should be generated to display hierarchical information. If the tag\n# value is set to YES, a side panel will be generated containing a tree-like\n# index structure (just like the one that is generated for HTML Help). For this\n# to work a browser that supports JavaScript, DHTML, CSS and frames is required\n# (i.e. any modern browser). Windows users are probably better off using the\n# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can\n# further fine-tune the look of the index. As an example, the default style\n# sheet generated by doxygen has an example that shows how to put an image at\n# the root of the tree instead of the PROJECT_NAME. Since the tree basically has\n# the same information as the tab index, you could consider setting\n# DISABLE_INDEX to YES when enabling this option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_TREEVIEW      = NO\n\n# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that\n# doxygen will group on one line in the generated HTML documentation.\n#\n# Note that a value of 0 will completely suppress the enum values from appearing\n# in the overview section.\n# Minimum value: 0, maximum value: 20, default value: 4.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nENUM_VALUES_PER_LINE   = 4\n\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used\n# to set the initial width (in pixels) of the frame in which the tree is shown.\n# Minimum value: 0, maximum value: 1500, default value: 250.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nTREEVIEW_WIDTH         = 250\n\n# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to\n# external symbols imported via tag files in a separate window.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nEXT_LINKS_IN_WINDOW    = NO\n\n# Use this tag to change the font size of LaTeX formulas included as images in\n# the HTML documentation. When you change the font size after a successful\n# doxygen run you need to manually remove any form_*.png images from the HTML\n# output directory to force them to be regenerated.\n# Minimum value: 8, maximum value: 50, default value: 10.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFORMULA_FONTSIZE       = 10\n\n# Use the FORMULA_TRANPARENT tag to determine whether or not the images\n# generated for formulas are transparent PNGs. Transparent PNGs are not\n# supported properly for IE 6.0, but are supported on all modern browsers.\n#\n# Note that when changing this option you need to delete any form_*.png files in\n# the HTML output directory before the changes have effect.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFORMULA_TRANSPARENT    = YES\n\n# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see\n# http://www.mathjax.org) which uses client side Javascript for the rendering\n# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX\n# installed or if you want to formulas look prettier in the HTML output. When\n# enabled you may also need to install MathJax separately and configure the path\n# to it using the MATHJAX_RELPATH option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nUSE_MATHJAX            = NO\n\n# When MathJax is enabled you can set the default output format to be used for\n# the MathJax output. See the MathJax site (see:\n# http://docs.mathjax.org/en/latest/output.html) for more details.\n# Possible values are: HTML-CSS (which is slower, but has the best\n# compatibility), NativeMML (i.e. MathML) and SVG.\n# The default value is: HTML-CSS.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_FORMAT         = HTML-CSS\n\n# When MathJax is enabled you need to specify the location relative to the HTML\n# output directory using the MATHJAX_RELPATH option. The destination directory\n# should contain the MathJax.js script. For instance, if the mathjax directory\n# is located at the same level as the HTML output directory, then\n# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax\n# Content Delivery Network so you can quickly see the result without installing\n# MathJax. However, it is strongly recommended to install a local copy of\n# MathJax from http://www.mathjax.org before deployment.\n# The default value is: http://cdn.mathjax.org/mathjax/latest.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest\n\n# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax\n# extension names that should be enabled during MathJax rendering. For example\n# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_EXTENSIONS     =\n\n# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces\n# of code that will be used on startup of the MathJax code. See the MathJax site\n# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an\n# example see the documentation.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_CODEFILE       =\n\n# When the SEARCHENGINE tag is enabled doxygen will generate a search box for\n# the HTML output. The underlying search engine uses javascript and DHTML and\n# should work on any modern browser. Note that when using HTML help\n# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)\n# there is already a search function so this one should typically be disabled.\n# For large projects the javascript based search engine can be slow, then\n# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to\n# search using the keyboard; to jump to the search box use <access key> + S\n# (what the <access key> is depends on the OS and browser, but it is typically\n# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down\n# key> to jump into the search results window, the results can be navigated\n# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel\n# the search. The filter options can be selected when the cursor is inside the\n# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>\n# to select a filter and <Enter> or <escape> to activate or cancel the filter\n# option.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nSEARCHENGINE           = YES\n\n# When the SERVER_BASED_SEARCH tag is enabled the search engine will be\n# implemented using a web server instead of a web client using Javascript. There\n# are two flavors of web server based searching depending on the EXTERNAL_SEARCH\n# setting. When disabled, doxygen will generate a PHP script for searching and\n# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing\n# and searching needs to be provided by external tools. See the section\n# \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSERVER_BASED_SEARCH    = NO\n\n# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP\n# script for searching. Instead the search results are written to an XML file\n# which needs to be processed by an external indexer. Doxygen will invoke an\n# external search engine pointed to by the SEARCHENGINE_URL option to obtain the\n# search results.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see: http://xapian.org/).\n#\n# See the section \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH        = NO\n\n# The SEARCHENGINE_URL should point to a search engine hosted by a web server\n# which will return the search results when EXTERNAL_SEARCH is enabled.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see: http://xapian.org/). See the section \"External Indexing and\n# Searching\" for details.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHENGINE_URL       =\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed\n# search data is written to a file for indexing by an external tool. With the\n# SEARCHDATA_FILE tag the name of this file can be specified.\n# The default file is: searchdata.xml.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHDATA_FILE        = searchdata.xml\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the\n# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is\n# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple\n# projects and redirect the results back to the right project.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH_ID     =\n\n# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen\n# projects other than the one defined by this configuration file, but that are\n# all added to the same external search index. Each project needs to have a\n# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of\n# to a relative location where the documentation can be found. The format is:\n# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTRA_SEARCH_MAPPINGS  =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the LaTeX output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.\n# The default value is: YES.\n\nGENERATE_LATEX         = NO\n\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: latex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_OUTPUT           = latex\n\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be\n# invoked.\n#\n# Note that when enabling USE_PDFLATEX this option is only used for generating\n# bitmaps for formulas in the HTML output, but not in the Makefile that is\n# written to the output directory.\n# The default file is: latex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_CMD_NAME         = latex\n\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate\n# index for LaTeX.\n# The default file is: makeindex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nMAKEINDEX_CMD_NAME     = makeindex\n\n# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nCOMPACT_LATEX          = NO\n\n# The PAPER_TYPE tag can be used to set the paper type that is used by the\n# printer.\n# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x\n# 14 inches) and executive (7.25 x 10.5 inches).\n# The default value is: a4.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPAPER_TYPE             = a4\n\n# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names\n# that should be included in the LaTeX output. The package can be specified just\n# by its name or with the correct syntax as to be used with the LaTeX\n# \\usepackage command. To get the times font for instance you can specify :\n# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}\n# To use the option intlimits with the amsmath package you can specify:\n# EXTRA_PACKAGES=[intlimits]{amsmath}\n# If left blank no extra packages will be included.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nEXTRA_PACKAGES         =\n\n# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the\n# generated LaTeX document. The header should contain everything until the first\n# chapter. If it is left blank doxygen will generate a standard header. See\n# section \"Doxygen usage\" for information on how to let doxygen write the\n# default header to a separate file.\n#\n# Note: Only use a user-defined header if you know what you are doing! The\n# following commands have a special meaning inside the header: $title,\n# $datetime, $date, $doxygenversion, $projectname, $projectnumber,\n# $projectbrief, $projectlogo. Doxygen will replace $title with the empty\n# string, for the replacement values of the other commands the user is referred\n# to HTML_HEADER.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HEADER           =\n\n# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the\n# generated LaTeX document. The footer should contain everything after the last\n# chapter. If it is left blank doxygen will generate a standard footer. See\n# LATEX_HEADER for more information on how to generate a default footer and what\n# special commands can be used inside the footer.\n#\n# Note: Only use a user-defined footer if you know what you are doing!\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_FOOTER           =\n\n# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# LaTeX style sheets that are included after the standard style sheets created\n# by doxygen. Using this option one can overrule certain style aspects. Doxygen\n# will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list).\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_STYLESHEET =\n\n# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the LATEX_OUTPUT output\n# directory. Note that the files will be copied as-is; there are no commands or\n# markers available.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_FILES      =\n\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is\n# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will\n# contain links (just like the HTML output) instead of page references. This\n# makes the output suitable for online browsing using a PDF viewer.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPDF_HYPERLINKS         = YES\n\n# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate\n# the PDF file directly from the LaTeX files. Set this option to YES, to get a\n# higher quality PDF documentation.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nUSE_PDFLATEX           = YES\n\n# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode\n# command to the generated LaTeX files. This will instruct LaTeX to keep running\n# if errors occur, instead of asking the user for help. This option is also used\n# when generating formulas in HTML.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BATCHMODE        = NO\n\n# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the\n# index chapters (such as File Index, Compound Index, etc.) in the output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HIDE_INDICES     = NO\n\n# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source\n# code with syntax highlighting in the LaTeX output.\n#\n# Note that which sources are shown also depends on other settings such as\n# SOURCE_BROWSER.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_SOURCE_CODE      = NO\n\n# The LATEX_BIB_STYLE tag can be used to specify the style to use for the\n# bibliography, e.g. plainnat, or ieeetr. See\n# http://en.wikipedia.org/wiki/BibTeX and \\cite for more info.\n# The default value is: plain.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BIB_STYLE        = plain\n\n# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated\n# page will contain the date and time when the page was generated. Setting this\n# to NO can help when comparing the output of multiple runs.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_TIMESTAMP        = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the RTF output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The\n# RTF output is optimized for Word 97 and may not look too pretty with other RTF\n# readers/editors.\n# The default value is: NO.\n\nGENERATE_RTF           = NO\n\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: rtf.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_OUTPUT             = rtf\n\n# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nCOMPACT_RTF            = NO\n\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will\n# contain hyperlink fields. The RTF file will contain links (just like the HTML\n# output) instead of page references. This makes the output suitable for online\n# browsing using Word or some other Word compatible readers that support those\n# fields.\n#\n# Note: WordPad (write) and others do not support links.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_HYPERLINKS         = NO\n\n# Load stylesheet definitions from file. Syntax is similar to doxygen's config\n# file, i.e. a series of assignments. You only have to provide replacements,\n# missing definitions are set to their default value.\n#\n# See also section \"Doxygen usage\" for information on how to generate the\n# default style sheet that doxygen normally uses.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_STYLESHEET_FILE    =\n\n# Set optional variables used in the generation of an RTF document. Syntax is\n# similar to doxygen's config file. A template extensions file can be generated\n# using doxygen -e rtf extensionFile.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_EXTENSIONS_FILE    =\n\n# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code\n# with syntax highlighting in the RTF output.\n#\n# Note that which sources are shown also depends on other settings such as\n# SOURCE_BROWSER.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_SOURCE_CODE        = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the man page output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for\n# classes and files.\n# The default value is: NO.\n\nGENERATE_MAN           = NO\n\n# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it. A directory man3 will be created inside the directory specified by\n# MAN_OUTPUT.\n# The default directory is: man.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_OUTPUT             = man\n\n# The MAN_EXTENSION tag determines the extension that is added to the generated\n# man pages. In case the manual section does not start with a number, the number\n# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is\n# optional.\n# The default value is: .3.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_EXTENSION          = .3\n\n# The MAN_SUBDIR tag determines the name of the directory created within\n# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by\n# MAN_EXTENSION with the initial . removed.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_SUBDIR             =\n\n# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it\n# will generate one additional man file for each entity documented in the real\n# man page(s). These additional files only source the real man page, but without\n# them the man command would be unable to find the correct page.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_LINKS              = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the XML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that\n# captures the structure of the code including all documentation.\n# The default value is: NO.\n\nGENERATE_XML           = NO\n\n# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: xml.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_OUTPUT             = xml\n\n# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program\n# listings (including syntax highlighting and cross-referencing information) to\n# the XML output. Note that enabling this will significantly increase the size\n# of the XML output.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_PROGRAMLISTING     = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to the DOCBOOK output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files\n# that can be used to generate PDF.\n# The default value is: NO.\n\nGENERATE_DOCBOOK       = NO\n\n# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in\n# front of it.\n# The default directory is: docbook.\n# This tag requires that the tag GENERATE_DOCBOOK is set to YES.\n\nDOCBOOK_OUTPUT         = docbook\n\n# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the\n# program listings (including syntax highlighting and cross-referencing\n# information) to the DOCBOOK output. Note that enabling this will significantly\n# increase the size of the DOCBOOK output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_DOCBOOK is set to YES.\n\nDOCBOOK_PROGRAMLISTING = NO\n\n#---------------------------------------------------------------------------\n# Configuration options for the AutoGen Definitions output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an\n# AutoGen Definitions (see http://autogen.sf.net) file that captures the\n# structure of the code including all documentation. Note that this feature is\n# still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_AUTOGEN_DEF   = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the Perl module output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module\n# file that captures the structure of the code including all documentation.\n#\n# Note that this feature is still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_PERLMOD       = NO\n\n# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary\n# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI\n# output from the Perl module output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_LATEX          = NO\n\n# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely\n# formatted so it can be parsed by a human reader. This is useful if you want to\n# understand what is going on. On the other hand, if this tag is set to NO, the\n# size of the Perl module output will be much smaller and Perl will parse it\n# just the same.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_PRETTY         = YES\n\n# The names of the make variables in the generated doxyrules.make file are\n# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful\n# so different doxyrules.make files included by the same Makefile don't\n# overwrite each other's variables.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_MAKEVAR_PREFIX =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the preprocessor\n#---------------------------------------------------------------------------\n\n# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all\n# C-preprocessor directives found in the sources and include files.\n# The default value is: YES.\n\nENABLE_PREPROCESSING   = YES\n\n# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names\n# in the source code. If set to NO, only conditional compilation will be\n# performed. Macro expansion can be done in a controlled way by setting\n# EXPAND_ONLY_PREDEF to YES.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nMACRO_EXPANSION        = NO\n\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then\n# the macro expansion is limited to the macros specified with the PREDEFINED and\n# EXPAND_AS_DEFINED tags.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_ONLY_PREDEF     = NO\n\n# If the SEARCH_INCLUDES tag is set to YES, the include files in the\n# INCLUDE_PATH will be searched if a #include is found.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSEARCH_INCLUDES        = YES\n\n# The INCLUDE_PATH tag can be used to specify one or more directories that\n# contain include files that are not input files but should be processed by the\n# preprocessor.\n# This tag requires that the tag SEARCH_INCLUDES is set to YES.\n\nINCLUDE_PATH           =\n\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard\n# patterns (like *.h and *.hpp) to filter out the header-files in the\n# directories. If left blank, the patterns specified with FILE_PATTERNS will be\n# used.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nINCLUDE_FILE_PATTERNS  =\n\n# The PREDEFINED tag can be used to specify one or more macro names that are\n# defined before the preprocessor is started (similar to the -D option of e.g.\n# gcc). The argument of the tag is a list of macros of the form: name or\n# name=definition (no spaces). If the definition and the \"=\" are omitted, \"=1\"\n# is assumed. To prevent a macro definition from being undefined via #undef or\n# recursively expanded use the := operator instead of the = operator.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nPREDEFINED             =\n\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this\n# tag can be used to specify a list of macro names that should be expanded. The\n# macro definition that is found in the sources will be used. Use the PREDEFINED\n# tag if you want to use a different macro definition that overrules the\n# definition found in the source code.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_AS_DEFINED      =\n\n# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will\n# remove all references to function-like macros that are alone on a line, have\n# an all uppercase name, and do not end with a semicolon. Such function macros\n# are typically used for boiler-plate code, and will confuse the parser if not\n# removed.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSKIP_FUNCTION_MACROS   = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to external references\n#---------------------------------------------------------------------------\n\n# The TAGFILES tag can be used to specify one or more tag files. For each tag\n# file the location of the external documentation should be added. The format of\n# a tag file without this location is as follows:\n# TAGFILES = file1 file2 ...\n# Adding location for the tag files is done as follows:\n# TAGFILES = file1=loc1 \"file2 = loc2\" ...\n# where loc1 and loc2 can be relative or absolute paths or URLs. See the\n# section \"Linking to external documentation\" for more information about the use\n# of tag files.\n# Note: Each tag file must have a unique name (where the name does NOT include\n# the path). If a tag file is not located in the directory in which doxygen is\n# run, you must also specify the path to the tagfile here.\n\nTAGFILES               =  @CPP_TAGFILE_RULE@\n\n# When a file name is specified after GENERATE_TAGFILE, doxygen will create a\n# tag file that is based on the input files it reads. See section \"Linking to\n# external documentation\" for more information about the usage of tag files.\n\nGENERATE_TAGFILE       =\n\n# If the ALLEXTERNALS tag is set to YES, all external class will be listed in\n# the class index. If set to NO, only the inherited external classes will be\n# listed.\n# The default value is: NO.\n\nALLEXTERNALS           = NO\n\n# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed\n# in the modules index. If set to NO, only the current project's groups will be\n# listed.\n# The default value is: YES.\n\nEXTERNAL_GROUPS        = YES\n\n# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in\n# the related pages index. If set to NO, only the current project's pages will\n# be listed.\n# The default value is: YES.\n\nEXTERNAL_PAGES         = YES\n\n# The PERL_PATH should be the absolute path and name of the perl script\n# interpreter (i.e. the result of 'which perl').\n# The default file (with absolute path) is: /usr/bin/perl.\n\nPERL_PATH              = /usr/bin/perl\n\n#---------------------------------------------------------------------------\n# Configuration options related to the dot tool\n#---------------------------------------------------------------------------\n\n# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram\n# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to\n# NO turns the diagrams off. Note that this option also works with HAVE_DOT\n# disabled, but it is recommended to install and use dot, since it yields more\n# powerful graphs.\n# The default value is: YES.\n\nCLASS_DIAGRAMS         = YES\n\n# You can define message sequence charts within doxygen comments using the \\msc\n# command. Doxygen will then run the mscgen tool (see:\n# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the\n# documentation. The MSCGEN_PATH tag allows you to specify the directory where\n# the mscgen tool resides. If left empty the tool is assumed to be found in the\n# default search path.\n\nMSCGEN_PATH            =\n\n# You can include diagrams made with dia in doxygen documentation. Doxygen will\n# then run dia to produce the diagram and insert it in the documentation. The\n# DIA_PATH tag allows you to specify the directory where the dia binary resides.\n# If left empty dia is assumed to be found in the default search path.\n\nDIA_PATH               =\n\n# If set to YES the inheritance and collaboration graphs will hide inheritance\n# and usage relations if the target is undocumented or is not a class.\n# The default value is: YES.\n\nHIDE_UNDOC_RELATIONS   = YES\n\n# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is\n# available from the path. This tool is part of Graphviz (see:\n# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent\n# Bell Labs. The other options in this section have no effect if this option is\n# set to NO\n# The default value is: YES.\n\nHAVE_DOT               = YES\n\n# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed\n# to run in parallel. When set to 0 doxygen will base this on the number of\n# processors available in the system. You can set it explicitly to a value\n# larger than 0 to get control over the balance between CPU load and processing\n# speed.\n# Minimum value: 0, maximum value: 32, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_NUM_THREADS        = 0\n\n# When you want a differently looking font in the dot files that doxygen\n# generates you can specify the font name using DOT_FONTNAME. You need to make\n# sure dot is able to find the font, which can be done by putting it in a\n# standard location or by setting the DOTFONTPATH environment variable or by\n# setting DOT_FONTPATH to the directory containing the font.\n# The default value is: Helvetica.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTNAME           = Helvetica\n\n# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of\n# dot graphs.\n# Minimum value: 4, maximum value: 24, default value: 10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTSIZE           = 10\n\n# By default doxygen will tell dot to use the default font as specified with\n# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set\n# the path where dot can find it using this tag.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTPATH           =\n\n# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for\n# each documented class showing the direct and indirect inheritance relations.\n# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCLASS_GRAPH            = YES\n\n# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a\n# graph for each documented class showing the direct and indirect implementation\n# dependencies (inheritance, containment, and class references variables) of the\n# class with other documented classes.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCOLLABORATION_GRAPH    = YES\n\n# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for\n# groups, showing the direct groups dependencies.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGROUP_GRAPHS           = YES\n\n# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and\n# collaboration diagrams in a style similar to the OMG's Unified Modeling\n# Language.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nUML_LOOK               = NO\n\n# If the UML_LOOK tag is enabled, the fields and methods are shown inside the\n# class node. If there are many fields or methods and many nodes the graph may\n# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the\n# number of items for each type to make the size more manageable. Set this to 0\n# for no limit. Note that the threshold may be exceeded by 50% before the limit\n# is enforced. So when you set the threshold to 10, up to 15 fields may appear,\n# but if the number exceeds 15, the total amount of fields shown is limited to\n# 10.\n# Minimum value: 0, maximum value: 100, default value: 10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nUML_LIMIT_NUM_FIELDS   = 10\n\n# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and\n# collaboration graphs will show the relations between templates and their\n# instances.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nTEMPLATE_RELATIONS     = NO\n\n# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to\n# YES then doxygen will generate a graph for each documented file showing the\n# direct and indirect include dependencies of the file with other documented\n# files.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDE_GRAPH          = YES\n\n# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are\n# set to YES then doxygen will generate a graph for each documented file showing\n# the direct and indirect include dependencies of the file with other documented\n# files.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDED_BY_GRAPH      = YES\n\n# If the CALL_GRAPH tag is set to YES then doxygen will generate a call\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable call graphs for selected\n# functions only using the \\callgraph command. Disabling a call graph can be\n# accomplished by means of the command \\hidecallgraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALL_GRAPH             = NO\n\n# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable caller graphs for selected\n# functions only using the \\callergraph command. Disabling a caller graph can be\n# accomplished by means of the command \\hidecallergraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALLER_GRAPH           = NO\n\n# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical\n# hierarchy of all classes instead of a textual one.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGRAPHICAL_HIERARCHY    = YES\n\n# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the\n# dependencies a directory has on other directories in a graphical way. The\n# dependency relations are determined by the #include relations between the\n# files in the directories.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDIRECTORY_GRAPH        = YES\n\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images\n# generated by dot. For an explanation of the image formats see the section\n# output formats in the documentation of the dot tool (Graphviz (see:\n# http://www.graphviz.org/)).\n# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order\n# to make the SVG files visible in IE 9+ (other browsers do not have this\n# requirement).\n# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,\n# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,\n# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,\n# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and\n# png:gdiplus:gdiplus.\n# The default value is: png.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_IMAGE_FORMAT       = png\n\n# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to\n# enable generation of interactive SVG images that allow zooming and panning.\n#\n# Note that this requires a modern browser other than Internet Explorer. Tested\n# and working are Firefox, Chrome, Safari, and Opera.\n# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make\n# the SVG files visible. Older versions of IE do not have SVG support.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINTERACTIVE_SVG        = NO\n\n# The DOT_PATH tag can be used to specify the path where the dot tool can be\n# found. If left blank, it is assumed the dot tool can be found in the path.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_PATH               =\n\n# The DOTFILE_DIRS tag can be used to specify one or more directories that\n# contain dot files that are included in the documentation (see the \\dotfile\n# command).\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOTFILE_DIRS           =\n\n# The MSCFILE_DIRS tag can be used to specify one or more directories that\n# contain msc files that are included in the documentation (see the \\mscfile\n# command).\n\nMSCFILE_DIRS           =\n\n# The DIAFILE_DIRS tag can be used to specify one or more directories that\n# contain dia files that are included in the documentation (see the \\diafile\n# command).\n\nDIAFILE_DIRS           =\n\n# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the\n# path where java can find the plantuml.jar file. If left blank, it is assumed\n# PlantUML is not used or called during a preprocessing step. Doxygen will\n# generate a warning when it encounters a \\startuml command in this case and\n# will not generate output for the diagram.\n\nPLANTUML_JAR_PATH      =\n\n# When using plantuml, the specified paths are searched for files specified by\n# the !include statement in a plantuml block.\n\nPLANTUML_INCLUDE_PATH  =\n\n# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes\n# that will be shown in the graph. If the number of nodes in a graph becomes\n# larger than this value, doxygen will truncate the graph, which is visualized\n# by representing a node as a red box. Note that doxygen if the number of direct\n# children of the root node in a graph is already larger than\n# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that\n# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.\n# Minimum value: 0, maximum value: 10000, default value: 50.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_GRAPH_MAX_NODES    = 50\n\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs\n# generated by dot. A depth value of 3 means that only nodes reachable from the\n# root by following a path via at most 3 edges will be shown. Nodes that lay\n# further from the root node will be omitted. Note that setting this option to 1\n# or 2 may greatly reduce the computation time needed for large code bases. Also\n# note that the size of a graph can be further restricted by\n# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.\n# Minimum value: 0, maximum value: 1000, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nMAX_DOT_GRAPH_DEPTH    = 0\n\n# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent\n# background. This is disabled by default, because dot on Windows does not seem\n# to support this out of the box.\n#\n# Warning: Depending on the platform used, enabling this option may lead to\n# badly anti-aliased labels on the edges of a graph (i.e. they become hard to\n# read).\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_TRANSPARENT        = NO\n\n# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output\n# files in one run (i.e. multiple -o and -T options on the command line). This\n# makes dot run faster, but since only newer versions of dot (>1.8.10) support\n# this, this feature is disabled by default.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_MULTI_TARGETS      = NO\n\n# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page\n# explaining the meaning of the various boxes and arrows in the dot generated\n# graphs.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGENERATE_LEGEND        = YES\n\n# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot\n# files that are used to generate the various graphs.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_CLEANUP            = YES\n"
  },
  {
    "path": "doc/general/DoxygenLayout.xml",
    "content": "<doxygenlayout version=\"1.0\">\n  <!-- Customized for gtirb main based on doxygen 1.8.14 -->\n  <!-- Navigation index tabs for HTML output -->\n  <navindex>\n    <tab type=\"mainpage\" visible=\"yes\" title=\"\"/>\n    <tab type=\"pages\" visible=\"no\"/>\n    <tab type=\"usergroup\" visible=\"yes\" title=\"More Information\" url=\"\">\n      <tab type=\"user\" visible=\"yes\" title=\"Frequently Asked Questions\" url=\"@ref md_FAQ\"/>\n      <tab type=\"user\" visible=\"yes\" title=\"Binary Representation with GTIRB\" url=\"@ref md_binary-representation\"/>\n      <tab type=\"user\" visible=\"yes\" title=\"Using Serialized GTIRB Data\" url=\"@ref md_PROTOBUF\"/>\n      <tab type=\"user\" visible=\"yes\" title=\"Advice on when to Place ICFG Edges\" url=\"@ref md_CFG-Edges\"/>\n      <tab type=\"user\" visible=\"yes\" title=\"Standard AuxData Schemata\" url=\"@ref md_AuxData\"/>\n      <tab type=\"user\" visible=\"yes\" title=\"Contributing\" url=\"@ref md_CONTRIBUTING\"/>\n      <tab type=\"user\" visible=\"yes\" title=\"Tutorial: Stack Stamping\" url=\"@ref md_stack-stamp\"/>\n    </tab>\n\n    <tab type=\"usergroup\" visible=\"yes\" title=\"GTIRB Tools\">\n      <tab type=\"user\" visible=\"yes\" title=\"Disassembler (ddisasm)\" url=\"https://github.com/GrammaTech/ddisasm\">\n      </tab>\n      <tab type=\"user\" visible=\"yes\" title=\"Ghidra Plugin (gtirb-ghidra-plugin)\" url=\"https://github.com/GrammaTech/gtirb-ghidra-plugin\">\n      </tab>\n      <tab type=\"user\" visible=\"yes\" title=\"Pretty Printer (gtirb-pprinter)\" url=\"https://github.com/GrammaTech/gtirb-pprinter\">\n      </tab>\n    </tab>\n\n    <tab type=\"user\" visible=\"yes\" title=\"API Components\" url=\"@ref md_COMPONENTS\"/>\n\n    <tab type=\"usergroup\" visible=\"yes\" title=\"API Implementations\">\n       <tab type=\"user\" visible=\"@CPP_API_VISIBLE@\" title=\"C++ API\" url=\"cpp/index.html\"/>\n       <tab type=\"user\" visible=\"@PY_API_VISIBLE@\" title=\"Python API\" url=\"python/index.html\"/>\n       <tab type=\"user\" visible=\"@CL_API_VISIBLE@\" title=\"Common Lisp API\" url=\"cl/index.html\"/>\n       <tab type=\"user\" visible=\"@JAVA_API_VISIBLE@\" title=\"Java API\" url=\"java/index.html\"/>\n    </tab>\n\n    <tab type=\"examples\" visible=\"yes\" title=\"\" intro=\"\"/>\n  </navindex>\n\n  <!-- Layout definition for a class page -->\n  <class>\n    <briefdescription visible=\"yes\"/>\n    <includes visible=\"$SHOW_INCLUDE_FILES\"/>\n    <inheritancegraph visible=\"$CLASS_GRAPH\"/>\n    <collaborationgraph visible=\"$COLLABORATION_GRAPH\"/>\n    <memberdecl>\n      <nestedclasses visible=\"yes\" title=\"\"/>\n      <publictypes title=\"\"/>\n      <services title=\"\"/>\n      <interfaces title=\"\"/>\n      <publicslots title=\"\"/>\n      <signals title=\"\"/>\n      <publicmethods title=\"\"/>\n      <publicstaticmethods title=\"\"/>\n      <publicattributes title=\"\"/>\n      <publicstaticattributes title=\"\"/>\n      <protectedtypes title=\"\"/>\n      <protectedslots title=\"\"/>\n      <protectedmethods title=\"\"/>\n      <protectedstaticmethods title=\"\"/>\n      <protectedattributes title=\"\"/>\n      <protectedstaticattributes title=\"\"/>\n      <packagetypes title=\"\"/>\n      <packagemethods title=\"\"/>\n      <packagestaticmethods title=\"\"/>\n      <packageattributes title=\"\"/>\n      <packagestaticattributes title=\"\"/>\n      <properties title=\"\"/>\n      <events title=\"\"/>\n      <privatetypes title=\"\"/>\n      <privateslots title=\"\"/>\n      <privatemethods title=\"\"/>\n      <privatestaticmethods title=\"\"/>\n      <privateattributes title=\"\"/>\n      <privatestaticattributes title=\"\"/>\n      <friends title=\"\"/>\n      <related title=\"\" subtitle=\"\"/>\n      <membergroups visible=\"yes\"/>\n    </memberdecl>\n    <detaileddescription title=\"\"/>\n    <memberdef>\n      <inlineclasses title=\"\"/>\n      <typedefs title=\"\"/>\n      <enums title=\"\"/>\n      <services title=\"\"/>\n      <interfaces title=\"\"/>\n      <constructors title=\"\"/>\n      <functions title=\"\"/>\n      <related title=\"\"/>\n      <variables title=\"\"/>\n      <properties title=\"\"/>\n      <events title=\"\"/>\n    </memberdef>\n    <allmemberslink visible=\"yes\"/>\n    <usedfiles visible=\"$SHOW_USED_FILES\"/>\n    <authorsection visible=\"yes\"/>\n  </class>\n\n  <!-- Layout definition for a namespace page -->\n  <namespace>\n    <briefdescription visible=\"yes\"/>\n    <memberdecl>\n      <nestednamespaces visible=\"yes\" title=\"\"/>\n      <constantgroups visible=\"yes\" title=\"\"/>\n      <classes visible=\"yes\" title=\"\"/>\n      <typedefs title=\"\"/>\n      <enums title=\"\"/>\n      <functions title=\"\"/>\n      <variables title=\"\"/>\n      <membergroups visible=\"yes\"/>\n    </memberdecl>\n    <detaileddescription title=\"\"/>\n    <memberdef>\n      <inlineclasses title=\"\"/>\n      <typedefs title=\"\"/>\n      <enums title=\"\"/>\n      <functions title=\"\"/>\n      <variables title=\"\"/>\n    </memberdef>\n    <authorsection visible=\"yes\"/>\n  </namespace>\n\n  <!-- Layout definition for a file page -->\n  <file>\n    <briefdescription visible=\"yes\"/>\n    <includes visible=\"$SHOW_INCLUDE_FILES\"/>\n    <includegraph visible=\"$INCLUDE_GRAPH\"/>\n    <includedbygraph visible=\"$INCLUDED_BY_GRAPH\"/>\n    <sourcelink visible=\"yes\"/>\n    <memberdecl>\n      <classes visible=\"yes\" title=\"\"/>\n      <namespaces visible=\"yes\" title=\"\"/>\n      <constantgroups visible=\"yes\" title=\"\"/>\n      <defines title=\"\"/>\n      <typedefs title=\"\"/>\n      <enums title=\"\"/>\n      <functions title=\"\"/>\n      <variables title=\"\"/>\n      <membergroups visible=\"yes\"/>\n    </memberdecl>\n    <detaileddescription title=\"\"/>\n    <memberdef>\n      <inlineclasses title=\"\"/>\n      <defines title=\"\"/>\n      <typedefs title=\"\"/>\n      <enums title=\"\"/>\n      <functions title=\"\"/>\n      <variables title=\"\"/>\n    </memberdef>\n    <authorsection/>\n  </file>\n\n  <!-- Layout definition for a group page -->\n  <group>\n    <briefdescription visible=\"yes\"/>\n    <groupgraph visible=\"$GROUP_GRAPHS\"/>\n    <memberdecl>\n      <nestedgroups visible=\"yes\" title=\"\"/>\n      <dirs visible=\"yes\" title=\"\"/>\n      <files visible=\"yes\" title=\"\"/>\n      <namespaces visible=\"yes\" title=\"\"/>\n      <classes visible=\"yes\" title=\"\"/>\n      <defines title=\"\"/>\n      <typedefs title=\"\"/>\n      <enums title=\"\"/>\n      <enumvalues title=\"\"/>\n      <functions title=\"\"/>\n      <variables title=\"\"/>\n      <signals title=\"\"/>\n      <publicslots title=\"\"/>\n      <protectedslots title=\"\"/>\n      <privateslots title=\"\"/>\n      <events title=\"\"/>\n      <properties title=\"\"/>\n      <friends title=\"\"/>\n      <membergroups visible=\"yes\"/>\n    </memberdecl>\n    <detaileddescription title=\"\"/>\n    <memberdef>\n      <pagedocs/>\n      <inlineclasses title=\"\"/>\n      <defines title=\"\"/>\n      <typedefs title=\"\"/>\n      <enums title=\"\"/>\n      <enumvalues title=\"\"/>\n      <functions title=\"\"/>\n      <variables title=\"\"/>\n      <signals title=\"\"/>\n      <publicslots title=\"\"/>\n      <protectedslots title=\"\"/>\n      <privateslots title=\"\"/>\n      <events title=\"\"/>\n      <properties title=\"\"/>\n      <friends title=\"\"/>\n    </memberdef>\n    <authorsection visible=\"yes\"/>\n  </group>\n\n  <!-- Layout definition for a directory page -->\n  <directory>\n    <briefdescription visible=\"yes\"/>\n    <directorygraph visible=\"yes\"/>\n    <memberdecl>\n      <dirs visible=\"yes\"/>\n      <files visible=\"yes\"/>\n    </memberdecl>\n    <detaileddescription title=\"\"/>\n  </directory>\n</doxygenlayout>\n"
  },
  {
    "path": "doc/general/IR.md",
    "content": "IR\n==========\n\n**IR** describes the *internal representation* of a software artifact.\n\nThe corresponding Protobuf message type is `IR`.\n\n\nGuaranteed Properties\n---------------------\n\n- An **IR** is a [Node](Node.md).\n\n- Each **IR** object must be an [AuxDataContainer](AuxDataContainer.md).\n\n- There must be functionality to save an **IR** object to a file, and\n  to load an **IR** object from a file. This functionality is allowed\n  to fail if the object's **version** does not match the [GTIRB\n  Protobuf version for the API as a whole](Version.md).\n\n- Each **IR** object must have the following information, and the API\n  must provide functionality for getting and setting each.\n  - The applicable Protobuf **version**.\n    The default value for new **IR** objects should match the\n    [GTIRB Protobuf version for the API as a whole](Version.md).\n  - The **modules** in the representation, as a collection of\n    [Module](Module.md) objects. The collection order will depend on\n    the API language.\n  - The **control flow graph** [(CFG)](CFG.md).\n\n\nAPI Implementations\n--------------------\n\nThe guaranteed functionality is provided as follows.\n\n### IR Classes and AuxDataContainer functionality\n\n| Language    | IR Class  | [AuxDataContainer](AuxDataContainer.md) functionality              |\n|:------------|:----------|:-------------------------------------------------------------------|\n| C++         | gtirb::IR | by inheritance: gtirb::IR is a subclass of gtirb::AuxDataContainer |\n| Python      | gtirb.IR  | by inheritance: gtirb.IR is a subclass of gtirb.AuxDataContainer   |\n| Common Lisp | **gtirb** | via **aux-data** class and specializations **aux-data** (*object* *gtirb*) => *result*, (setf (**aux-data** (*object* *gtirb*)) *new-value*) |\n\n\n### GTIRB Protobuf API Version\n\n\n| Language    | Get Version             | Set Version             |\n|:------------|:------------------------|:------------------------|\n| C++         | gtirb::IR::getVersion() | gtirb::IR::setVersion() |\n| Python      | read gtirb.IR.version   | write gtirb.IR.version  |\n| Common Lisp | **version** (*obj* *gtirb*) => *result* | (setf (**version** (*obj* *gtirb*)) *new*) |\n\n\n### File Save/Load\n\n| Language    | Save IR to file         | Load IR from file            |\n|:------------|:------------------------|:------------------------|\n| C++         | gtirb::IR::save(), gtirb::IR::saveJSON() | gtirb::IR::load(), gtirb::IR::loadJSON() |\n| Python      | gtirb.IR.save_protobuf(), gtirb.IR.save_protobuf_file() | gtirb.IR.load_protobuf(), gtirb.IR.load_protobuf_file() |\n| Common Lisp |  **write-gtirb** *gtirb* *path* => *result* | **read-gtirb** *path* => *result* |\n\n\n\n\n### Get and Set Modules\n\n| Language    | Get Modules                          | Set Modules            |\n|-------------|:-------------------------------------|:-----------------------|\n| C++         | gtirb::IR::modules()                 | gtirb::IR:: gtirb::IR::addModule(), gtirb::IR::removeModule() |\n| Python      | read gtirb.IR.modules                | write gtirb.IR.modules |\n| Common Lisp | **modules** (*object* *gtirb*) => result | (setf (**modules** (*object* *gtirb*)) *new-value*) |\n\n\n\n\n\n\n### CFG\n\n\n| Language    | Get CFG                  | Set CFG                   |\n|:------------|:-------------------------|:--------------------------|\n| C++         | read gtirb::IR::getCFG() | write gtirb::IR::getCFG() |\n| Python      | read gtirb.IR.cfg        | write gtirb.IR.cfg        |\n| Common Lisp | **cfg** (*object* *gtirb*) => *result* | (setf (**cfg** (*object* *gtirb*)) *new-value*) |\n\n\nLinks\n--------------------\n\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/Module.md",
    "content": "Module\n=======\n\nA **Module** represents a single binary (library or executable).\n\nThe corresponding Protobuf message type is `Module`.\n\n\nGuaranteed Properties\n---------------------\n\n- A **Module** is a [Node](Node.md).\n\n- Each **Module** object must be an\n  [AuxDataContainer](AuxDataContainer.md).\n\n- Each **Module** object must have the following information, and the\n  API must provide functionality for getting and setting each.\n  - **binary_path**\n  - **preferred_addr**\n  - **rebase_delta**\n  - **file_format**\n  - **isa**\n  - **name** (as a non-empty string)\n  - **sections** (as a collection of [Section](Section.md), order\n      defined by target language)\n  - **symbols** (as a collection of [Symbol](Symbol.md), order defined\n      by target language)\n  - **proxy_blocks** (as a collection of [ProxyBlock](ProxyBlock.md),\n      order defined by target language)\n  - **entry_point** (as a [CodeBlock](CodeBlock.md), or null if empty)\n\n- Functionality for conversion to and from a Protobuf message of type\n  `Module` must be provided, and must account for the required fields\n  listed above.\n\n- Each **Module** must belong to either zero (0) or one (1)\n  [IR](IR.md) objects. The owning **IR** must be stored as a\n  reference.\n  - This reference may be null, in which case the **Module**\n    is freestanding and does not belong to any **IR**.\n  - The reference must be readable.\n  - If the reference is writable, setting it must automatically update\n    the module sets for the affected **IR** object or objects (there\n    will be at most two).\n\n- The following operations must be available for the set of\n  [Section](Section.md) objects in the **Module**.\n  - Find all **Section** objects that intersect a given address or\n    range of addresses.\n  - Find all **Section** objects that begin at a given address or\n    range of addresses. This operation must complete in O(log n) time,\n    where m is the size of the returned set and n is the number of\n    **Section** objects in the **Module**.\n\n\n\n## API Implementations\n\nThe guaranteed functionality is provided as follows.\n\n\n### Module Classes and AuxDataContainer functionality\n\n| Language    | Module Class  | [AuxDataContainer](AuxDataContainer.md) functionality |\n|:------------|:--------------|:-------------------------------|\n| C++         | gtirb::Module | by inheritance: gtirb::Module is a subclass of gtirb::AuxDataContainer |\n| Python      | gtirb.Module  | by inheritance: gtirb.Module is a subclass of gtirb.AuxDataContainer |\n| Common Lisp | **module**    | via **aux-data** class and specializations **aux-data** (*object* *module*) => *result*, (setf (**aux-data** (*object* *module*)) *new-value*) |\n\n\n### Required Field Getters/Setters\n\n\n#### binary_path\n\n| Language    | Get binary_path | Set binary_path |\n|:------------|:----------------|:----------------|\n| C++         | gtirb::Module::getBinaryPath() | gtirb::Module::setBinaryPath() |\n| Python      | read gtirb.Module.binary_path  | write gtirb.Module.binary_path |\n| Common Lisp | **binary-path** (*obj* *module*) => *result* | (setf (**binary-path** (*obj* *module*)) *new*) |\n\n\n#### preferred_addr\n\n| Language    | Get preferred_addr | Set preferred_addr  |\n|:------------|:-------------------|:--------------------|\n| C++         | gtirb::Module::getPreferredAddr() | gtirb::Module::setPreferredAddr() |\n| Python      | read gtirb.Module.isa  | write gtirb.Module.isa |\n| Common Lisp | **preferred-addr** (*obj* *module*) => *result* | (setf (**preferred-addr** (*obj* *module*)) *new*) |\n\n\n\n#### rebase_delta\n\n| Language    | Get rebase_delta | Set rebase_delta |\n|:------------|:-----------------|:-----------------|\n| C++         | gtirb::Module::getRebaseDelta() | gtirb::Module::setRebaseDelta() |\n| Python      | read gtirb.Module.rebase_delta  | write gtirb.Module.rebase_delta |\n| Common Lisp | **rebase-delta** (*obj* *module*) => *result* | (setf (**rebase-delta** (*obj* *module*)) *new*) |\n\n#### file_format\n\n| Language    | Get file_format | Set file_format |\n|:------------|:----------------|:----------------|\n| C++         | gtirb::Module::getFileFormat() | gtirb::Module::setFileFormat() |\n| Python      | read gtirb.Module.file_format  | write gtirb.Module.file_format  |\n| Common Lisp | **file-format** (*obj* *module*) => *result* | (setf (**file-format** (*obj* *module*)) *new*) |\n\n#### isa\n\n| Language    | Get isa                 | Set isa                  |\n|:------------|:------------------------|:-------------------------|\n| C++         | gtirb::Module::getISA() | gtirb::Module::setISA()  |\n| Python      | read gtirb.Module.isa   | write gtirb.Module.isa   |\n| Common Lisp | **isa** (*obj* *module*) => *result* | (setf (**isa** (*obj* *module*)) *new*) |\n\n#### name\n\n| Language    | Get name                 | Set name                 |\n|:------------|:-------------------------|:-------------------------|\n| C++         | gtirb::Module::getName() | gtirb::Module::setName() |\n| Python      | read gtirb.Module.name   | write gtirb.Module.name  |\n| Common Lisp | **name** (*obj* *module*) => *result* | (setf (**name** (*obj* *module*)) *new*) |\n\n#### sections\n\n| Language    | Get sections               | Set sections                  |\n|:------------|:---------------------------|:------------------------------|\n| C++         | gtirb::Module::sections()  | gtirb::Module::addSection(), gtirb::Module::removeSection() |\n| Python      | read gtirb.Module.sections | write gtirb.Module.sections |\n| Common Lisp | **sections** (*object* *module*) => *result* | (setf (**sections** (*object* *module*)) *new-value*) |\n\n\n\n#### symbols\n\n| Language    | Get symbols               | Set symbols                |\n|:------------|:--------------------------|:---------------------------|\n| C++         | gtirb::Module::symbols()  | gtirb::Module::addSymbol(), gtirb::Module::removeSymbol |\n| Python      | read gtirb.Module.symbols | write gtirb.Module.symbols |\n| Common Lisp | **symbols** (*object* *module*) => *result* | (setf (**symbols** (*object* *module*)) *new-value*) |\n\n\n#### proxy_blocks\n\n| Language    | Get proxy_blocks              | Set proxy_blocks           |\n|:------------|:------------------------------|:---------------------------|\n| C++         | gtirb::Module::proxy_blocks() | gtirb::Module::addProxyBlock(), gtirb::Module::removeProxyBlock() |\n| Python      | read gtirb.Module.proxies     | write gtirb.Module.proxies |\n| Common Lisp | **proxies** (*object* *module*) => *result* | (setf (**proxies** (*object* *module*)) *new-value*)  |\n\n#### entry_point\n\n| Language    | Get entry_point | Set entry_point |\n|:------------|:----------------|:----------------|\n| C++         | gtirb::Module::getEntryPoint() | gtirb::Module::setEntryPoint() |\n| Python      | read gtirb.Module.entry_point  | write gtirb.Module.entry_point  |\n| Common Lisp | **entry-point** (*obj* *module*) => *result* | setf (**entry-point** (*obj* *module*)) *new-value*) |\n\n\n\n\n\n### Associated IR\n\n\n| Language    | Associated IR                             |\n|:------------|:------------------------------------------|\n| C++         | gtirb::Module::getIR()                    |\n| Python      | gtirb.Module.ir                           |\n| Common Lisp | **gtirb** (*object* *module*) => *result* |\n\n\n\n### Find Section Objects...\n\n| Language    | ...that intersect an address/range | ...that begin at an address/range\n|:------------|:---------------------------|:---------------------------|\n| C++         | gtirb::Module::findSectionsOn() | gtirb::Module::findSectionsAt() |\n| Python      | gtirb.Module.sections_in() | gtirb.Module.sections_at() |\n| Common Lisp | **in-address** *object* *start-address* &optional *end-address* => *result*, then filter *result* to extract the **section** objects | **at-address** *object* *address* => *result*, then filter *result* to extract the **section** objects. [*] |\n\n[*] Address range checking is not yet implemented for Common Lisp\n**at-address**\n\n\nLinks\n--------------------\n\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/Node.md",
    "content": "Node\n==========\n\n**Node** is the root class for many [GTIRB components](COMPONENTS.md).\n\n\nGuaranteed Properties\n---------------------\n\n- A unique identifier, **UUID**\n   - The UUID is readable.\n\n- A facility to look up Node objects by UUID.\n   - Any node still reachable in memory must be retrievable by UUID.\n\n- All APIs must implement a notion of **Node**.\n\n\n\nAPI Implementations\n--------------------\n\nThe guaranteed functionality is provided as follows.\n\n| Language    | Node Class  | Retrieve UUID for Node        | Retrieve Node by UUID                    |\n|-------------|-------------|-------------------------------|------------------------------------------|\n| C++         | gtirb::Node | gtirb::Node::getUUID()        | gtirb::Node::getByUUID()                 |\n| Python      | gtirb.Node  | gtirb.Node.uuid               | gtirb.Node.from_uuid()                   |\n| Common Lisp | -           | **uuid** *object* => *result* | **get-uuid** *uuid* *object* => *result* |\n\n\nLinks\n--------------------\n\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/ProxyBlock.md",
    "content": "ProxyBlock\n====================\n\nA **ProxyBlock** is a placeholder that serves as the endpoint (source\nor target) of a [CfgEdge](CfgEdge.md).\n\n**ProxyBlock** objects allow the construction of CFG edges to or from\nanother node. For example, a call to a function in another module may\nbe represented by an edge that originates at the calling\n[CodeBlock](CodeBlock.md) and targets a **ProxyBlock**. Another\nexample would be an edge that represents an indirect jump whose target\nis not known.\n\nA **ProxyBlock** does not represent any instructions and so has\nneither an address nor a size.\n\nThe corresponding Protobuf message type is `ProxyBlock`.\n\n\nGuaranteed Properties\n---------------------\n\n- A **ProxyBlock** is a [CfgNode](CfgNode.md).\n\n\n- Each **ProxyBlock** must belong to either zero (0) or one (1)\n  [Module](Module.md) objects. The owning **Module** must be stored as\n  a reference.\n  - This reference may be null, in which case the **ProxyBlock** is\n    freestanding and does not belong to any **Module**.\n  - The reference must be readable.\n  - If the reference is writable, setting it must automatically update\n    the **proxy_blocks** sets for the affected **Module** object or objects\n    (there will be at most two).\n\n\nAPI Implementations\n--------------------\n\nThe guaranteed functionality is provided as follows.\n\n### ProxyBlock Classes\n\n| Language    | ProxyBlock Class  |\n|:------------|:------------------|\n| C++         | gtirb::ProxyBlock |\n| Python      | gtirb.ProxyBlock  |\n| Common Lisp | **proxy-block**   |\n\n\n\n### Associated Module\n\n\n| Language    | Associated Module                               |\n|:------------|:------------------------------------------------|\n| C++         | gtirb::ProxyBlock::getModule()                  |\n| Python      | gtirb.ProxyBlock.module                         |\n| Common Lisp | **module** (*object* *proxy-block*) => *result* |\n\n\nLinks\n--------------------\n\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/Section.md",
    "content": "Section\n==========\n\nA **Section** represents a named section of a binary.\n\nThe corresponding Protobuf message type is `Section`.\n\n\nGuaranteed Properties\n---------------------\n\n- A **Section** is a [Node](Node.md).\n\n- Each **Section** object must have the following information, and the API\n  must provide functionality for getting and setting each.\n  - **name**\n  - **section_flags** (as a bitset or enumeration set)\n  - **byte_intervals** (as a collection of\n    [ByteInterval](ByteInterval.md), order defined by target language)\n\n- Each **Section** must belong to either zero (0) or one (1)\n  [Module](Module.md) objects. The owning **Module** must be stored as\n  a reference.\n  - This reference may be null, in which case the **Section** is\n    freestanding and does not belong to any Module.\n\n- The following operations must be available for the set of\n  [ByteInterval](ByteInterval.md) objects in the **Section**.\n  - Find all **ByteInterval** objects that intersect a given address or\n    range of addresses.\n  - Find all **ByteInterval** objects that begin at a given address or\n    range of addresses. This operation must complete in O(M + log n) time\n    where m is the size of the returned set and n is the number of\n    **ByteInterval** objects in the **Section**.\n\n\nAPI Implementations\n--------------------\n\nThe guaranteed functionality is provided as follows.\n\n### Section Classes\n\n| Language    | Section Class  |\n|:------------|:---------------|\n| C++         | gtirb::Section |\n| Python      | gtirb.Section  |\n| Common Lisp | **section**    |\n\n\n\n### Required Field Getters/Setters\n\n#### name\n\n| Language    | Get name                  | Set name                  |\n|:------------|:--------------------------|:--------------------------|\n| C++         | gtirb::Section::getName() | gtirb::Section::setName() |\n| Python      | read gtirb.Section.name   | write gtirb.Section.name  |\n| Common Lisp | **name** (*obj* *section*) => *result* | (setf (**name** (*obj* *section*)) *new*) |\n\n\n#### section_flags\n\n\n| Language    | Get section_flags        | Set section_flags         |\n|:------------|:-------------------------|:--------------------------|\n| C++         | gtirb::Section::flags()  | gtirb::Section::addFlag(), gtirb::Section::addFlags(), gtirb::Section::removeFlag() |\n| Python      | read gtirb.Section.flags | write gtirb.Section.flags |\n| Common Lisp | **flags** (*obj* *section*) => *result* | (setf (**flags** (*obj* *section*)) *new*)  |\n\n\n#### byte_intervals\n\n\n| Language    | Get byte_intervals                | Set byte_intervals |\n|:------------|:----------------------------------|:-------------------|\n| C++         | gtirb::Section::byte_intervals()  | gtirb::Section::addByteInterval(), gtirb::Section::removeByteInterval() |\n| Python      | read gtirb.Section.byte_intervals | write gtirb.Section.byte_intervals  |\n| Common Lisp | **byte-intervals** (*object* *section*) => *result* | (setf (**byte-intervals** (*object* *section*)) *new-value)* |\n\n\n\n\n### Find ByteInterval Objects...\n\n| Language    | ...that intersect an address/range | ...that begin at an address/range\n|:------------|:---------------------------|:---------------------------|\n| C++         | gtirb::Section::findByteIntervalsOn() | gtirb::Section::findByteIntervalsAt() |\n| Python      | gtirb.Section.byte_intervals_in() | gtirb.Section.byte_intervals_at() |\n| Common Lisp |  **in-address** *object* *start-address* &optional *end-address* => *result*, then filter *result* to extract the **byte-interval** objects | **at-address** *object* *address* => *result*, then filter *result* to extract the **byte-interval** objects. [*] |\n\n[*] Address range checking is not yet implemented for Common Lisp\n**at-address**\n\n\n\n\n### Associated Module\n\n\n| Language    | Associated Module                           |\n|:------------|:--------------------------------------------|\n| C++         | gtirb::Section::getModule()                 |\n| Python      | gtirb.Section.module                        |\n| Common Lisp | **module** (*object* *section*) => *result* |\n\n\nLinks\n--------------------\n\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/SymAddrAddr.md",
    "content": "SymAddrAddr\n====================\n\nA **SymAddrAddr** represents a symbolic operand of the form \"(Sym1 -\nSym2) / Scale + Offset\".\n\nThe corresponding Protobuf message type is `SymAddrAddr`.\n\n\nGuaranteed Properties\n---------------------\n\n- **SymAddrAddr** is one of the permissible types for a\n  [SymbolicExpression](SymbolicExpression.md).\n\n- Each **SymAddrAddr** object must have the following information,\n  and the API must provide functionality for getting and setting each.\n  - **scale**\n  - **offset**\n  - **symbol1_uuid** (as a [Symbol](Symbol.md))\n  - **symbol2_uuid** (as a [Symbol](Symbol.md))\n\n\n\nAPI Implementations\n--------------------\n\nThe guaranteed functionality is provided as follows.\n\n### SymAddrAddr Classes\n\n| Language    | SymAddrAddr Class  |\n|:------------|:-------------------|\n| C++         | gtirb::SymAddrAddr |\n| Python      | gtirb.SymAddrAddr  |\n| Common Lisp | **sym-addr-addr**  |\n\n\n\n### Required Field Getters/Setters\n\n#### scale\n\n| Language    | Get scale       | Set scale             |\n|:------------|:----------------|:----------------------|\n| C++         | read gtirb::SymAddrAddr::Scale | write gtirb::SymAddrAddr::Scale |\n| Python      | read gtirb.SymAddrAddr.scale | write gtirb.SymAddrAddr.scale |\n| Common Lisp | **scale** (*obj* *sym-addr-addr*) => *result* | (setf (**scale** (*obj* *sym-addr-addr*)) *new*) |\n\n\n\n#### offset\n\n| Language    | Get offset         | Set offset    |\n|:------------|:-------------------|:--------------|\n| C++         | read gtirb::SymAddrAddr::Offset | write gtirb::SymAddrAddr::Offset |\n| Python      | read gtirb.SymAddrAddr.offset | write gtirb.SymAddrAddr.offset |\n| Common Lisp | **offset** (*obj* *sym-addr-addr*) => *result* | (setf (**offset** (*obj* *sym-addr-addr*)) *new*) |\n\n\n\n\n#### symbol1_uuid\n\n| Language    | Get symbol1_uuid    | Set symbol1_uuid   |\n|:------------|:--------------------|:-----------------------|\n| C++         | read gtirb::SymAddrAddr::Sym1 | write gtirb::SymAddrAddr::Sym1 |\n| Python      | read gtirb.SymAddrAddr.symbol1 | write gtirb.SymAddrAddr.symbol1 |\n| Common Lisp | **symbols** (*object* *symbolic-expression*) => *result*, first **symbol** in *result* | (setf (**symbols** (*object* *symbolic-expression*)) *new-value*), first **symbol** in *new-value* |\n\n\n\n#### symbol2_uuid\n\n\n| Language    | Get symbol2_uuid     | Set symbol2_uuid    |\n|:------------|:---------------------|:--------------------|\n| C++         | read gtirb::SymAddrAddr::Sym2  | read/write gtirb::SymAddrAddr::Sym2  |\n| Python      | read gtirb.SymAddrAddr.symbol2 | read/write gtirb.SymAddrAddr.symbol2 |\n| Common Lisp | **symbols** (*object* *symbolic-expression*) => *result*, second **symbol** in *result* | (setf (**symbols** (*object* *symbolic-expression*)) *new-value*), second **symbol** in *new-value* |\n\nLinks\n--------------------\n\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/SymAddrConst.md",
    "content": "SymAddrConst\n====================\n\nA **SymAddrConst** represents a symbolic operand of the form \"Sym +\nOffset\".\n\nThe corresponding Protobuf message type is `SymAddrConst`.\n\n\nGuaranteed Properties\n---------------------\n\n- **SymAddrConst** is one of the permissible types for a\n  [SymbolicExpression](SymbolicExpression.md).\n\n- Each **SymAddrConst** object must have the following information,\n  and the API must provide functionality for getting and setting each.\n  - **offset**\n  - **symbol_uuid** (as a [Symbol](Symbol.md))\n\n\n\nAPI Implementations\n--------------------\n\nThe guaranteed functionality is provided as follows.\n\n### SymAddrConst Classes\n\n| Language    | SymAddrConst Class  |\n|:------------|:--------------------|\n| C++         | gtirb::SymAddrConst |\n| Python      | gtirb.SymAddrConst  |\n| Common Lisp | **sym-addr-const**  |\n\n\n\n### Required Field Getters/Setters\n\n#### offset\n\n| Language    | Get offset          | Set offset            |\n|:------------|:--------------------|:----------------------|\n| C++         | read gtirb::SymAddrConst::Offset | write gtirb::SymAddrConst::Offset |\n| Python      | read gtirb.SymAddrConst.offset | write gtirb.SymAddrConst.offset |\n| Common Lisp | **offset** (*obj* *sym-addr-const*) => *result* | (setf (**offset** (*obj* *sym-addr-const*)) *new*) |\n\n\n\n\n#### symbol_uuid\n\n| Language    | Get symbol_uuid   | Get/Set symbol_uuid   |\n|:------------|:------------------|:----------------------|\n| C++         | read gtirb::SymAddrConst::Sym  | write gtirb::SymAddrConst::Sym  |\n| Python      | read gtirb.SymAddrConst.symbol | read gtirb.SymAddrConst.symbol |\n| Common Lisp | **symbols** (*object* *symbolic-expression*) => *result* | (setf (**symbols** (*object* *symbolic-expression*)) *new-value*) |\n\n\nLinks\n--------------------\n\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/Symbol.md",
    "content": "Symbol\n====================\n\nA **Symbol** maps a name to an object in the [IR](IR.md).\n\nThe corresponding Protobuf message type is `Symbol`.\n\n\nGuaranteed Properties\n---------------------\n\n- A **Symbol** is a [Node](Node.md).\n\n- Each **Section** object must have the following information, and the API\n  must provide functionality for getting and setting each.\n  - **name**\n  - **optional_payload**: can be a [Block](Block.md) (sometimes called\n    the *referent*) or an integer or null value (sometimes called the\n    *value*)\n\n- Each **Symbol** must belong to either zero (0) or one (1)\n  [Module](Module.md) objects. The owning **Module** must be stored as\n  a reference.\n  - This reference may be null, in which case the **Symbol** is\n    freestanding and does not belong to any **Module**.\n  - The reference must be readable.\n  - If the reference is writable, setting it must automatically update\n    the **symbols** sets for the affected **Module** object or objects\n    (there will be at most two).\n\n\nAPI Implementations\n--------------------\n\nThe guaranteed functionality is provided as follows.\n\n### Symbol Classes\n\n| Language    | Symbol Class  |\n|:------------|:--------------|\n| C++         | gtirb::Symbol |\n| Python      | gtirb.Symbol  |\n| Common Lisp | **symbol**    |\n\n\n\n\n### Required Field Getters/Setters\n\n#### name\n\n| Language    | Get name                 | Set name                 |\n|:------------|:-------------------------|:-------------------------|\n| C++         | gtirb::Symbol::getName() | gtirb::Symbol::setName() |\n| Python      | read gtirb.Symbol.name   | write gtirb.Symbol.name  |\n| Common Lisp | **name** (*obj* *symbol*) => *result* | (setf (**name** (*obj* *symbol*)) *new*) |\n\n\n#### optional_payload (referent/value)\n\n| Language    | Get optional_payload     | Set optional_payload     |\n|:------------|:-------------------------|:-------------------------|\n| C++         | gtirb::Symbol::getAddress, gtirb::Symbol::getReferent() | gtirb::Symbol::setAddress(), gtirb::Symbol::setReferent() |\n| Python      | read gtirb.Symbol.referent or gtirb.Symbol.value | write gtirb.Symbol.referent or gtirb.Symbol.value |\n| Common Lisp | **payload** *symbol* => *result* | (setf (**payload** *symbol*) *new*) |\n\n\n### Associated Module\n\n\n| Language    | Associated Module                          |\n|:------------|:-------------------------------------------|\n| C++         | gtirb::Symbol::getModule()                 |\n| Python      | gtirb.Symbol.module                        |\n| Common Lisp | **module** (*object* *symbol*) => *result* |\n\n\nLinks\n--------------------\n\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/SymbolicExpression.md",
    "content": "SymbolicExpression\n====================\n\nA **SymbolicExpression** represents a data value or instruction\noperand which should be interpreted as referring to a symbol.\n\n\nGuaranteed Properties\n---------------------\n\n- A **SymbolicExpression** must be one of the following, implemented\n  as either an inheritance hierarchy or a tagged union.\n  - [SymStackConst](SymStackConst.md)\n  - [SymAddrConst](SymAddrConst.md)\n  - [SymAddrAddr](SymAddrAddr.md)\n\nSymbolic Expression Attributes\n------------------------------\n\nSymbolic expressions have a set of assignable labels (**SymAttribute**) for\narchitecture and ABI specific relocation types and reference modifiers.\n\n**SymAttribute** labels are organized by architecture with common labels,\nstems, and suffixes grouped into a common base set.\n\nFor example, a symbol of the form `symbol@GOT` should be assigned the attribute\n**gtirb::SymAttribute::GOT**, and a symbol of the form `symbol@GOTPAGE` assigned\nboth **gtirb::SymAttribute::GOT** and **gtirb::SymAttribute::PAGE**.\n\nNote that we do not generalize or otherwise unify relocation attributes across\narchitectures and instead prefer an explicit mapping of attribute names to\nrelocation types as they appear in the assembly for each architecture. As a\nresult, many labels have similar names (e.g.  `HI`, `HI16`, `H`), but are\nduplicated to provide an intuitive mapping.\n\n\n | Attribute  | Description                                                                                                                                                                                                                                                                                                                                                                                 |\n |------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n | **ELF**    |                                                                                                                                                                                                                                                                                                                                                                                             |\n | GOT        | Expression value is the offset of the GOT entry for a symbol from the base of the GOT.                                                                                                                                                                                                                                                                                                      |\n | GOTPC      | Expression value is the PC relative offset to GOT. Used for values referencing an implicit `_GLOBAL_OFFSET_TABLE_` symbol.                                                                                                                                                                                                                                                                  |\n | GOTOFF     | Expression value is the offset to a symbol location from the base of the GOT.                                                                                                                                                                                                                                                                                                               |\n | GOTREL     | Expression value is relative to the GOT.                                                                                                                                                                                                                                                                                                                                                    |\n | PLT        | Expression value is the offset to the PLT entry for a symbol from the current code location.                                                                                                                                                                                                                                                                                                |\n | PLTOFF     | Expression value is the offset to the PLT entry for a symbol from the base of the GOT.                                                                                                                                                                                                                                                                                                      |\n | PCREL      | Expression value is relative to the current code location.                                                                                                                                                                                                                                                                                                                                  |\n | SECREL     | Expression value is relative to the beginning of the section.                                                                                                                                                                                                                                                                                                                               |\n | TLS        | Expression value references Thead Local Storage.                                                                                                                                                                                                                                                                                                                                            |\n | TLSGD      | Expression value is the offset of the GOT entry for a `tls_index` structure. Used in Global Dynamic TLS access model (32 and 64-bit). See [ELF Handling for Thread-Local Storage](https://www.uclibc.org/docs/tls.pdf) for more details.                                                                                                                                                    |\n | TLSLD      | Expression value is the offset of the GOT entry for a `tls_index` structure. Used in Local Dynamic TLS access model (64-bit). See [ELF Handling for Thread-Local Storage](https://www.uclibc.org/docs/tls.pdf) for more details.                                                                                                                                                            |\n | TLSLDM     | Expression value is the offset of the GOT entry for a `tls_index` structure. Used in Local Dynamic TLS access model (32-bit). See [ELF Handling for Thread-Local Storage](https://www.uclibc.org/docs/tls.pdf) for more details.                                                                                                                                                            |\n | TPREL      | Expression value is the offset of a symbol relative to the TLS block. Used in the Local Executable TLS access model. Note that `TPREL` and `TPOFF` are descriptors for the same TLS access models. Use the attribute name equivalent to the syntax compatible with the target assembler. See [ELF Handling for Thread-Local Storage](https://www.uclibc.org/docs/tls.pdf) for more details. |\n | TPOFF      | Expression value is the offset of a symbol relative to the TLS block. Used in the Local Executable TLS access model. Note that `TPREL` and `TPOFF` are descriptors for the same TLS access models. Use the attribute name equivalent to the syntax compatible with the target assembler. See [ELF Handling for Thread-Local Storage](https://www.uclibc.org/docs/tls.pdf) for more details. |\n | DTPREL     | Expression value is the offset of a symbol relative to the TLS block. Used in the Local Dynamic TLS access model. Note that `DTPREL` and `DTPOFF` are descriptors for the same TLS access models. Use the attribute name equivalent to the syntax compatible with the target assembler. See [ELF Handling for Thread-Local Storage](https://www.uclibc.org/docs/tls.pdf) for more details.  |\n | DTPOFF     | Expression value is the offset of a symbol relative to the TLS block. Used in the Local Dynamic TLS access model. Note that `DTPREL` and `DTPOFF` are descriptors for the same TLS access models. Use the attribute name equivalent to the syntax compatible with the target assembler. See [ELF Handling for Thread-Local Storage](https://www.uclibc.org/docs/tls.pdf) for more details.  |\n | DTPMOD     | Expression value is an object identifier for the object containing a TLS symbol. See [ELF Handling for Thread-Local Storage](https://www.uclibc.org/docs/tls.pdf) for more details.                                                                                                                                                                                                         |\n | NTPOFF     | Expression value is a negative offset of a symbol relative to the TLS block. See [ELF Handling for Thread-Local Storage](https://www.uclibc.org/docs/tls.pdf) for more details.                                                                                                                                                                                                             |\n | TLSDESC    | Expression value is a pointer to the `tlsdesc` structure. See [RFC TLSDESC](https://www.fsfla.org/~lxoliva/writeups/TLS/RFC-TLSDESC-x86.txt)                                                                                                                                                                                                                                                |\n | TLSCALL    | Expression value is a call through the `tlsdesc` structure.                                                                                                                                                                                                                                                                                                                                 |\n | PAGE       | Expression value is a PC relative offset within a 4K page.                                                                                                                                                                                                                                                                                                                                  |\n | PAGEOFF    | Expression value is the offset within a 4K page, added to the page address to produce a complete address.                                                                                                                                                                                                                                                                                   |\n | CALL       | Specifies the expression value can only be present in a call instruction.                                                                                                                                                                                                                                                                                                                   |\n | LO         | Expression value is the low half word of an absolute symbol address; structured as [HI,LO] and [HIGHEST,HIGHER,HI,LO] for 32 and 64-bit addresses respectively.                                                                                                                                                                                                                             |\n | HI         | Expression value is the high half word of an absolute symbol address; structured as [HI,LO] and [HIGHEST,HIGHER,HI,LO] for 32 and 64-bit addresses respectively.                                                                                                                                                                                                                            |\n | HIGHER     | Expression value represents the higher half word of a symbol address; structured as [HI,LO] and [HIGHEST,HIGHER,HI,LO] for 32 and 64-bit addresses respectively.                                                                                                                                                                                                                            |\n | HIGHEST    | Expression value represents the highest word of a symbol address; structured as [HI,LO] and [HIGHEST,HIGHER,HI,LO] for 32 and 64-bit addresses respectively.                                                                                                                                                                                                                                |\n |            |                                                                                                                                                                                                                                                                                                                                                                                             |\n | **X86**    |                                                                                                                                                                                                                                                                                                                                                                                             |\n | GOTNTPOFF  | Expression value references a GOT entry with the negative offset relative to the thread-pointer (TLS block).                                                                                                                                                                                                                                                                                |\n | INDNTPOFF  | Position dependent variant of `GOTNTPOFF` (absolute address of GOT entry).                                                                                                                                                                                                                                                                                                                  |\n |            |                                                                                                                                                                                                                                                                                                                                                                                             |\n | **ARM**    |                                                                                                                                                                                                                                                                                                                                                                                             |\n | G0         | Expression value represents bits 0-15 of a 64-bit address.                                                                                                                                                                                                                                                                                                                                  |\n | G1         | Expression value represents bits 16-31 of a 64-bit address.                                                                                                                                                                                                                                                                                                                                 |\n | G2         | Expression value represents bits 32-47 of a 64-bit address.                                                                                                                                                                                                                                                                                                                                 |\n | G3         | Expression value represents bits 48-63 of a 64-bit address.                                                                                                                                                                                                                                                                                                                                 |\n | UPPER16    | Expression value represents upper 16 bits of an address.                                                                                                                                                                                                                                                                                                                                    |\n | LOWER16    | Expression value represents lower 16 bits of an address.                                                                                                                                                                                                                                                                                                                                    |\n | LO12       | Expression value represents bits 0-11 of an address.                                                                                                                                                                                                                                                                                                                                        |\n | LO14       | Expression value represents bits 0-13 of an address.                                                                                                                                                                                                                                                                                                                                        |\n | LO15       | Expression value represents bits 0-14 of an address.                                                                                                                                                                                                                                                                                                                                        |\n | HI12       | Expression value represents bits 13-24 of a 64-bit address.                                                                                                                                                                                                                                                                                                                                 |\n | HI21       | Expression value represents bits 11-31 of an address.                                                                                                                                                                                                                                                                                                                                       |\n | S          | Indicates the expression value is signed.                                                                                                                                                                                                                                                                                                                                                   |\n | PG         | Functionally identical to `PAGE`, but should be used for ARM relocations such as `:pg_hi21:symbol`.                                                                                                                                                                                                                                                                                         |\n | NC         | Indicates the linker should not check for overflow, \"no check\".                                                                                                                                                                                                                                                                                                                             |\n | ABS        | Indicates the expression value is an absolute address.                                                                                                                                                                                                                                                                                                                                      |\n | PREL       | Indicates the expression value is PC relative.                                                                                                                                                                                                                                                                                                                                              |\n | PREL31     | Expression value represents a 31-bit PC relative offset.                                                                                                                                                                                                                                                                                                                                    |\n | TARGET1    | Target specific relocation interpreted as either `R_ARM_ABS32` or `R_ARM_REL32`. Linker switches `--target1-rel` and `--target1-abs` switches override the default definition.                                                                                                                                                                                                              |\n | TARGET2    | Target specific relocation interpreted as either `R_ARM_ABS32` or `R_ARM_REL32` or `R_ARM_GOT_PREL`. Linker switch `--target2={rel,abs,got-rel}` overrides the default definition.                                                                                                                                                                                                          |\n | SBREL      | Expression value is a static-base-relative offset.                                                                                                                                                                                                                                                                                                                                          |\n | TLSLDO     | Debug relocation for a TLS variable.                                                                                                                                                                                                                                                                                                                                                        |\n |            |                                                                                                                                                                                                                                                                                                                                                                                             |\n | **MIPS**   |                                                                                                                                                                                                                                                                                                                                                                                             |\n | HI16       | Expression value represents the upper 16 bits of a symbol.                                                                                                                                                                                                                                                                                                                                  |\n | LO16       | Expression value represents the lower 16 bits of a symbol.                                                                                                                                                                                                                                                                                                                                  |\n | GPREL      | Expression value represents the offset from the current GP value.                                                                                                                                                                                                                                                                                                                           |\n | DISP       | Composes with `GOT` attribute for `%got_disp` relocation. GOT entry as displacement into the global data section.                                                                                                                                                                                                                                                                           |\n | OFST       | Composes with `GOT` attribute for `%got_ofst` relocation. GOT entry as offset from a page pointer.                                                                                                                                                                                                                                                                                          |\n |            |                                                                                                                                                                                                                                                                                                                                                                                             |\n | **PPC**    |                                                                                                                                                                                                                                                                                                                                                                                             |\n | H          | Expression value represents the high 16 bits of a symbol.                                                                                                                                                                                                                                                                                                                                   |\n | L          | Expression value represents the low 16 bits of a symbol.                                                                                                                                                                                                                                                                                                                                    |\n | HA         | Expression value represents the high 16 bits, _adjusted_ for corresponding signed `symbol@l` relocation.                                                                                                                                                                                                                                                                                    |\n | HIGH       | Expression value represents the high 16 bits of a symbol, with overflow check (PPC64).                                                                                                                                                                                                                                                                                                      |\n | HIGHA      | Expression value represents the hight 16 bits of a symbol, with overflow check (PPC64), _adjusted_ for corresponding signed `symbol@l` relocation.                                                                                                                                                                                                                                          |\n | HIGHERA    | Expression value represents bits 32-47 of an address, _adjusted_ for corresponding signed `symbol@l` relocation.                                                                                                                                                                                                                                                                            |\n | HIGHESTA   | Expression value represents 48-63 of an address, _adjusted_ for corresponding signed `symbol@l` relocation.                                                                                                                                                                                                                                                                                 |\n | TOCBASE    | Expression value represents the TOC base for the current object.                                                                                                                                                                                                                                                                                                                            |\n | TOC        | Expression value is the offset of the TOC entry from the base of the TOC.                                                                                                                                                                                                                                                                                                                   |\n | NOTOC      | Indicates callee clobbers the TOC register.                                                                                                                                                                                                                                                                                                                                                 |\n\n\nAPI Implementations\n--------------------\n\nThe guaranteed functionality is provided as follows.\n\n| Language    | SymbolicExpression Implementation |\n|:------------|:----------------------------------|\n| C++         | gtirb::SymbolicExpression         |\n| Python      | gtirb.SymbolicExpression          |\n| Common Lisp | **symbolic-expression**           |\n\n\nLinks\n--------------------\n\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/Version.md",
    "content": "Version Information\n===================\n\nAll APIs must provide functionality for retrieving the following\nversion information.\n\n- The GTIRB version corresponding to the API, as a string.\n- The Protobuf version supported by the API, as an integer.  This must\n  match the value of the CMake `GTIRB_PROTOBUF_VERSION` variable.\n\n\nAPI Implementations\n-------------------\n\nThe required functionality is provided as follows.\n\n| Language    | GTIRB version               | Protobuf version               |\n|:------------|:----------------------------|:-------------------------------|\n| C++         | macro GTIRB_VERSION_STRING  | macro GTIRB_PROTOBUF_VERSION   |\n| Python      | gtirb.version.API_VERSION   | gtirb.version.PROTOBUF_VERSION |\n| Common Lisp | constant **gtirb-version**  | constant **protobuf-version**  |\n\n\nLinks\n--------------------\n\n- [GTIRB Components](COMPONENTS.md)\n- [Using Serialized GTIRB Data](../../PROTOBUF.md)\n"
  },
  {
    "path": "doc/general/examples.dox",
    "content": "\n///@if CPPONLY\n\n/// \\example api-walkthrough.cpp\n/// Demonstrate many different elements of the GTIRB API.\n\n/// \\example data-symbols.cpp\n/// Open an IR and print every symbol pointing to data.\n\n/// \\example cfg-paths.cpp\n/// Open an IR and print every path from some point to some other point.\n\n/// \\example functions.cpp\n/// Open an IR with function information in an auxiliary data store and print\n/// every function along with the number of other functions it calls.\n\n/// \\example jumps.cpp\n/// Open an IR and print the Address of every jump instruction,\n/// along with the jump targets (if known).\n\n///@endif\n\n\n/// @if PY_ONLY\n\n/// \\example data-symbols.py\n/// Open an IR and print every symbol pointing to data.\n\n/// \\example cfg-paths.py\n/// Open an IR and print every path from some point to some other point.\n\n/// \\example show-cfg.py\n/// Open an IR and draw the CFG to the screen.\n\n/// @endif\n\n/// @if CL_ONLY\n\n/// \\example data-symbols.lisp\n/// Open an IR and print every symbol pointing to data.\n\n/// \\example cfg-paths.lisp\n/// Open an IR and print every path from some point to some other point.\n\n/// \\example show-cfg.lisp\n/// Open an IR and draw the CFG to a png.\n\n/// @endif\n\n/// \\example datasymbols.java\n/// Open an IR via protobuf and print every symbol pointing to data.\n"
  },
  {
    "path": "doc/general/images.dox",
    "content": "/// \\image .gtirb.svg\n"
  },
  {
    "path": "doc/java/CMakeLists.txt",
    "content": "if(GTIRB_JAVA_API)\n  include(UseJava)\n\n  # ---------------------------------------------------------------------------\n  # Running javadoc requires all dependencies including jar files, so generate\n  # the jar file names with complete paths. What follows is identical to what is\n  # in the java/CMakeLists.txt, where the names are originally generated.\n  # ---------------------------------------------------------------------------\n\n  # Use only minor version, patch versions might not be available\n  string(REGEX MATCH \"([^\\.]+)\\.([^\\.]+)\\.([^\\.]+)\" PROTOBUF_VERSION_MATCH\n               ${Protobuf_VERSION}\n  )\n  set(PROTOBUF_MAJOR_VERSION ${CMAKE_MATCH_1})\n  set(PROTOBUF_MINOR_VERSION ${CMAKE_MATCH_2})\n  set(JAVA_PROTOBUF_VERSION\n      \"${PROTOBUF_MAJOR_VERSION}.${PROTOBUF_MINOR_VERSION}.0\"\n  )\n\n  # Full path to the two needed jar files\n  set(PROTOBUF_JARFILE\n      \"${CMAKE_BINARY_DIR}/java/protobuf-java-${JAVA_PROTOBUF_VERSION}.jar\"\n  )\n  set(GTIRB_API_JARFILE\n      \"${CMAKE_BINARY_DIR}/java/gtirb_api-${GTIRB_MAJOR_VERSION}.${GTIRB_MINOR_VERSION}.${GTIRB_PATCH_VERSION}.jar\"\n  )\n\n  if(WIN32)\n    set(CP_SEP \"\\;\")\n  else()\n    set(CP_SEP \":\")\n  endif()\n\n  set(JAR_FILE_LIST \"${GTIRB_API_JARFILE}${CP_SEP}${PROTOBUF_JARFILE}\")\n\n  # Set the directory that generated HTML will go into\n  set(JAVADOC_DIR \"${CMAKE_BINARY_DIR}/doc/html/java\")\n\n  # The javadoc command line\n  add_custom_target(\n    javadoc\n    DEPENDS gtirb-java-api\n    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}\n    COMMAND ${CMAKE_COMMAND} -E copy_directory ${GTIRB_JAVA_APIDOCS_DIR}\n            ${JAVADOC_DIR}\n    VERBATIM\n  )\n\n  # With this, \"make doc\" will also run javadoc\n  add_dependencies(doc javadoc)\n\nelse()\n  message(\n    WARNING\n      \"java is not enabled. HTML documentation for the Java API will not be generated.\"\n  )\nendif()\n"
  },
  {
    "path": "doc/preprocmd.py",
    "content": "# doxygen is annoying about certain .md things so we have to\n# preprocess before doxygenating\nimport os\nimport re\nimport sys\nfrom functools import reduce\n\n# Doxygen doesn't make heading anchors like it should.\n#\n# We can't insert them as a straight re substitution because we also\n# need to make sure we're not accidentally matching something inside a\n# codeblock.\n\n\ndef anchor_page_headings(pagetxt):\n    def heading_to_anchor(headtxt):\n        anchortxt = reduce(\n            lambda intxt, rep: intxt.replace(rep[0], rep[1]),\n            [headtxt.strip().lower()]\n            + [(ch, \"\") for ch in (\",\", \"/\", \"'\", '\"')]\n            + [(\" \", \"-\")],\n        )\n        return '<a name=\"{0}\" id=\"{0}\"></a>\\n'.format(anchortxt)\n\n    def incomment(txt):\n        return txt.count(\"```\") % 2 == 1\n\n    return reduce(\n        lambda intxt, rep_gp: re.sub(\n            rep_gp[0],\n            lambda m: (\n                m.group(0)\n                + (\n                    \"\"\n                    if incomment(pagetxt[: m.start()])\n                    else heading_to_anchor(m.group(rep_gp[1]))\n                )\n            ),\n            intxt,\n        ),\n        [\n            pagetxt,\n            (r\"(?:(^|\\n)\\#+\\s+)(.*?)(?:\\{.*?)?\\n\", 2),\n            (r\"((?:^|\\n)\\S.*?)(?:\\{\\#.*?\\}|)\\n(?:(\\=\\=\\=+|\\-\\-\\-+)\\n)\", 1),\n        ],\n    )\n\n\n# Given a Python-looking token, compute its location in the Python API\n# documentation and return an HTML link.\ndef makePyApiLink(pymatch):\n    parens = pymatch.group(\"parens\")\n    parens = parens if parens is not None else \"\"\n\n    pytoken = pymatch.group(\"pytoken\")\n    basename = \".\".join((pytoken.split(\".\")[:-1]))\n    # heuristic to determine whether it's 'really' a submodule reference\n    basename = \"gtirb\" if not basename.islower() else basename\n\n    href = '<a href=\"python/{0}.html#{1}\">{1}{2}</a>'.format(\n        basename, pytoken, parens\n    )\n    return href\n\n\n# Make an HTML link to an example file\ndef makeDoxyExampleLink(exname, linktext, pathadj):\n    fname = exname.replace(\".\", \"_8\") + \"-example.html\"\n    return '<a href=\"{0}{1}\">{2}</a>'.format(pathadj, fname, linktext)\n\n\n(infile, outfile) = sys.argv[1:3]\n\n# This controls some of the substitutions\noutdir = os.path.basename(os.path.dirname(os.path.abspath(outfile)))\nindir = os.path.basename(os.path.dirname(os.path.abspath(infile)))\n\nsubstitutions = [\n    # .md file links to /doc/examples/*\n    # become Doxygen \\ref links with adjusted path component\n    # (from main section) or finalized Doxygen links (otherwise)\n    (\n        r\"\\[([^]\\n]*)\\]\\s*\\(doc/examples/(.*?)\\)\",\n        (\n            lambda m: (\n                '\\\\ref {} \"{}\"'.format(m.group(2), m.group(1))\n                if outdir == \"general\"\n                else makeDoxyExampleLink(m.group(2), m.group(1), \"../\")\n            )\n        ),\n    ),\n    # Simplify links within same directory\n    (\n        r\"\\[([^]\\n]*)\\]\\s*\\(doc/{0}/(.*?).md\\)\".format(outdir),\n        r'\\\\ref md_\\2 \"\\1\"',\n    ),\n    (r\"\\[([^]\\n]*)\\]\\s*\\(doc/{0}/(.*?)\\)\".format(outdir), r'\\\\ref \\2 \"\\1\"'),\n    # C++ has to be converted to doxygen \\code ... \\endcode\n    # to get linking\n    (r\"```c\\+\\+(\\n(.*\\n)*?)```\", r\"\\\\code{.cpp}\\1\\\\endcode\"),\n    (r\"```cpp(\\n(.*\\n)*?)```\", r\"\\\\code{.cpp}\\1\\\\endcode\"),\n    # doxygen is specifically annoying about fenced code.\n    (\n        r\"```.*\\n((?:.*\\n)*?) *```\",\n        lambda m: \"\\n    \" + m.group(1).replace(\"\\n\", \"\\n    \"),\n    ),\n]\n\n# adjust relative links from gtirb/doc/general/*.md to gtirb/doc/*.md\n# and gtirb/*.md\n\nif indir == \"general\":\n    substitutions += [(r\"(?<=\\()\\.\\.\\/(?:\\.\\.\\/)?([\\w-]+\\.md)(?=\\))\", r\"\\1\")]\n\n\npytoken_re = r\"(?P<pytoken>gtirb(\\.[a-zA-Z]\\w*)+)(?P<parens>\\([^]\\n]*?\\))?\"\nif outdir == \"general\":\n    substitutions += [\n        # Heuristic recognition of links to Python API elements\n        # where a 'Python-looking token' has the form\n        # described by pytoken_re\n        #   heuristic 1: Python-looking token occurs in a table row\n        #   whose first cell contains \"Python\"\n        (\n            r\"(^|\\n)\\| +[^|]*?Python.*? {0} .*?\\n\".format(pytoken_re),\n            lambda m: re.sub(pytoken_re, makePyApiLink, m.group(0)),\n        ),\n        #   heuristic 2: Python-looking token - optionally followed by\n        #   paretheses with arbitrary contents - is link text of a link\n        #   whose target is python/README.md\n        (\n            r\"\\[\\s*{0}\\s*\\]\".format(pytoken_re)\n            + r\"\\([\\w\\./]*(?<=[\\(\\/])python\\/README.md\\)\",\n            makePyApiLink,\n        ),\n        # Links to other language APIs, iff those APIs are present\n        # (conditional managed by Doxygen)\n        (\n            r\"\\[([^]\\n]*)\\]\\s*\\(doc/cpp/README.md\\)\",\n            r' \\\\if CPP_ONLY <a href=\"cpp/index.html\">\\1</a> '\n            r\"\\\\else \\1 (not available) \\\\endif \\n\",\n        ),\n        (\n            r\"\\[([^]\\n]*)\\]\\s*\\((python|cl)/README.md\\)\",\n            lambda m: (\n                ' \\\\if {0}_ONLY  <a href=\"{1}/index.html\">{2}</a> '\n                \"\\\\else {2} (not available) \\\\endif \\n\"\n            ).format(\n                \"PY\" if m.group(2) == \"python\" else \"CL\",\n                m.group(2),\n                m.group(1),\n            ),\n        ),\n    ] + substitutions\n\n\nwith open(infile, \"r\") as infh:\n    contents = infh.read()\n    contents = anchor_page_headings(contents)\n    contents = reduce(\n        lambda intxt, rep: re.sub(rep[0], rep[1], intxt),\n        [contents] + substitutions,\n    )\n\n    with open(outfile, \"w\") as outfh:\n        outfh.write(\"[TOC]\\n\")  # insert page TOC\n        outfh.write(contents)\n"
  },
  {
    "path": "doc/python/CMakeLists.txt",
    "content": "if(PYTHON)\n  find_program(SPHINX_APIDOC sphinx-apidoc)\n\n  if(WIN32)\n    set(SPHINX_MAKE_CMD \"./make.bat\")\n  else()\n    set(SPHINX_MAKE_CMD \"make\")\n  endif()\n\n  if(SPHINX_APIDOC)\n    add_custom_target(\n      sphinx\n      DEPENDS pygtirb\n      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}\n      COMMAND\n        ${SPHINX_APIDOC} ${CMAKE_BINARY_DIR}/python/gtirb --output-dir\n        ${CMAKE_CURRENT_BINARY_DIR} --force --full --separate\n      COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/conf.py\n              ${CMAKE_CURRENT_BINARY_DIR}/\n      COMMAND ${SPHINX_MAKE_CMD} html\n      COMMAND ${CMAKE_COMMAND} -E remove_directory\n              ${CMAKE_BINARY_DIR}/doc/html/python\n      COMMAND ${CMAKE_COMMAND} -E rename ${CMAKE_CURRENT_BINARY_DIR}/_build/html\n              ${CMAKE_BINARY_DIR}/doc/html/python\n      COMMENT \"Generating API documentation with Sphinx\"\n      VERBATIM\n    )\n    add_dependencies(doc sphinx)\n  else()\n    message(\n      WARNING\n        \"sphinx-apidoc was not found. HTML documentation for the Python API will not be generated.\"\n    )\n  endif()\nendif()\n"
  },
  {
    "path": "doc/python/conf.py",
    "content": "# Configuration file for the Sphinx documentation builder.\n#\n# This file only contains a selection of the most common options. For a full\n# list see the documentation:\n# https://www.sphinx-doc.org/en/master/usage/configuration.html\n\n# -- Path setup --------------------------------------------------------------\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n\nimport os\nimport sys\n\nsys.path.insert(0, os.path.abspath(\"../../python\"))\n\n\n# -- Project information -----------------------------------------------------\n\nproject = \"gtirb\"\nauthor = \"Grammatech, Inc\"\ncopyright = \"2020, \" + author\n\n\n# -- General configuration ---------------------------------------------------\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n# ones.\nextensions = [\n    \"sphinx.ext.autodoc\",\n    \"sphinx.ext.viewcode\",\n    \"sphinx.ext.todo\",\n    \"sphinx_autodoc_typehints\",\n]\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = [\"_templates\"]\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n#\n# This is also used if you do content translation via gettext catalogs.\n# Usually you set \"language\" from the command line for these cases.\nlanguage = \"en\"\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\n# This pattern also affects html_static_path and html_extra_path.\nexclude_patterns = [\"_build\", \"Thumbs.db\", \"**/.*\"]\n\n\n# -- Options for HTML output -------------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\n#\nhtml_theme = \"alabaster\"\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = [\"_static\"]\n\n\n# -- Extension configuration -------------------------------------------------\n\n# -- Options for todo extension ----------------------------------------------\n\n# If true, `todo` and `todoList` produce output, else they produce nothing.\ntodo_include_todos = True\n\n# -- Options for autodoc extension -------------------------------------------\n\nautoclass_content = \"class\"\nautodoc_default_options = {\n    \"special-members\": True,\n    \"exclude-members\": (\n        \"__weakref__,\"\n        \"__dict__,\"\n        \"__module__,\"\n        \"__repr__,\"\n        \"__str__,\"\n        \"__annotations__,\"\n        \"__abstractmethods__,\"\n        \"__args__,\"\n        \"__extra__,\"\n        \"__next_in_mro__,\"\n        \"__orig_bases__,\"\n        \"__origin__,\"\n        \"__tree_hash__,\"\n        \"__parameters__,\"\n        \"__subclasshook__,\"\n    ),\n}\n\n# -- Options for typehints extension -----------------------------------------\n\nset_type_checking_flag = False\ntypehints_fully_qualified = True\nalways_document_param_types = False\n"
  },
  {
    "path": "gtirbConfig.cmake.in",
    "content": "function(check_gtirb_branch GTIRB_BRANCH_NAME)\n  if(NOT \"${GTIRB_BRANCH_NAME}\" STREQUAL \"@PACKAGE_BRANCH@\")\n    message(\n      SEND_ERROR\n        \"The requested gtirb branch ${GTIRB_BRANCH_NAME} is not the branch which was used in the gtirb build.  Gtirb's package branch was: @PACKAGE_BRANCH@.\"\n    )\n  endif()\nendfunction()\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/gtirbTargets.cmake\")\n"
  },
  {
    "path": "include/gtirb/Addr.hpp",
    "content": "//===- Addr.hpp -------------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_ADDR_H\n#define GTIRB_ADDR_H\n\n#include <gtirb/Export.hpp>\n#include <cstddef>\n#include <cstdint>\n#include <iomanip>\n#include <iosfwd>\n#include <optional>\n\n/// \\file Addr.hpp\n/// \\brief Class gtirb::Addr and related functions.\n\nnamespace gtirb {\n/// \\brief A special class to store an Effective Address.\n///\n/// It is a thin wrapper around a uint64_t for 64-bit address storage. Its\n/// semantics in overflow situations are the same as semantics for unsigned\n/// integers.\n///\n/// An Addr cannot store a relative address as it cannot contain a negative\n/// number.\nclass GTIRB_EXPORT_API Addr {\npublic:\n  /// \\brief The underlying type used to represent an Addr object.\n  typedef uint64_t value_type;\n  /// \\brief The type used to represent a difference between two Addr objects.\n  typedef int64_t difference_type;\n\n  /// \\brief Default constructor.\n  constexpr Addr() noexcept : Address{0} {}\n\n  /// \\brief Explicit conversion from \\c value_type to \\ref Addr.\n  ///\n  /// \\param X The address.\n  constexpr explicit Addr(value_type X) noexcept : Address(X) {}\n\n  /// \\brief Explicitly convert \\ref Addr to \\c value_type.\n  ///\n  /// \\return An integer representation of the \\ref Addr.\n  constexpr explicit operator value_type() const noexcept { return Address; }\n\n  /// \\brief Unary plus for \\ref Addr. This is a noop because Addr objects\n  /// represent an unsigned address value.\n  ///\n  /// \\return A copy of the implicit \\ref Addr.\n  constexpr Addr operator+() const noexcept { return Addr(+Address); }\n\n  /// \\brief Unary complement for \\ref Addr. Flips the value of all bits in\n  /// the address.\n  ///\n  /// \\return A copy of the implicit \\ref Addr object, with all bits flipped.\n  constexpr Addr operator~() const noexcept { return Addr(~Address); }\n\n  /// \\brief Preincrement for \\ref Addr.\n  ///\n  /// \\return The incremented \\ref Addr.\n  constexpr Addr& operator++() noexcept {\n    ++Address;\n    return *this;\n  }\n\n  /// \\brief Postincrement for \\ref Addr.\n  ///\n  /// \\return A new \\ref Addr representing the address prior to being\n  /// incremented.\n  constexpr Addr operator++(int) noexcept {\n    Addr R(*this);\n    ++Address;\n    return R;\n  }\n\n  /// \\brief Predecrement for \\ref Addr.\n  ///\n  /// \\return The decremented \\ref Addr.\n  constexpr Addr& operator--() noexcept {\n    --Address;\n    return *this;\n  }\n\n  /// \\brief Postdecrement for \\ref Addr.\n  ///\n  /// \\return A new \\ref Addr representing the address prior to being\n  /// decremented.\n  constexpr Addr operator--(int) noexcept {\n    Addr R(*this);\n    --Address;\n    return R;\n  }\n\n  /// \\brief Binary + operator for \\ref Addr + integral offset.\n  ///\n  /// \\param A        The \\ref Addr operand to +.\n  /// \\param Offset   The offset to add to \\p A.\n  ///\n  /// \\return A new \\ref Addr representing \\p A + \\p Offset.\n  friend constexpr Addr operator+(const Addr& A, value_type Offset) noexcept {\n    return Addr(A.Address + Offset);\n  }\n\n  /// \\brief Binary + operator for integral offset + \\ref Addr.\n  ///\n  /// \\param Offset   The offset to add to \\p A.\n  /// \\param A        The \\ref Addr operand to +.\n  ///\n  /// \\return A new \\ref Addr representing \\p A + \\p Offset.\n  friend constexpr Addr operator+(value_type Offset, const Addr& A) noexcept {\n    return A + Offset;\n  }\n\n  /// \\brief Add-assign for \\ref Addr.\n  ///\n  /// \\param Offset   The offset to add to the represented address.\n  ///\n  /// \\return \\c *this\n  constexpr Addr& operator+=(value_type Offset) noexcept {\n    Address += Offset;\n    return *this;\n  }\n\n  /// \\brief Binary - operator for \\ref Addr - integral offset.\n  ///\n  /// \\param A        The \\ref Addr operand to -.\n  /// \\param Offset   The offset to subtract from \\p A.\n  ///\n  /// \\return A new \\ref Addr representing  \\p A - \\p Offset.\n  ///\n  /// NB: There is no overload for Offset - Addr like there is for Offset + Addr\n  /// because subtraction is not associative like addition is.\n  friend constexpr Addr operator-(const Addr& A, value_type Offset) noexcept {\n    return Addr(A.Address - Offset);\n  }\n\n  /// \\brief Subtract-assign for \\ref Addr.\n  ///\n  /// \\param Offset   The offset to subtract from the represented address.\n  ///\n  /// \\return \\c *this\n  constexpr Addr& operator-=(value_type Offset) noexcept {\n    Address -= Offset;\n    return *this;\n  }\n\n  /// \\brief Binary - operator for \\ref Addr - \\ref Addr.\n  ///\n  /// \\param A        The minuend.\n  /// \\param B        The subtrahend.\n  ///\n  /// \\return         The difference \\p A - \\p B. NB: this is a difference type\n  /// and not a valid address.\n  friend constexpr difference_type operator-(const Addr& A,\n                                             const Addr& B) noexcept {\n    return static_cast<difference_type>(A.Address - B.Address);\n  }\n\n  /// \\brief Equality operator for \\ref Addr.\n  friend constexpr bool operator==(const Addr& LHS, const Addr& RHS) noexcept {\n    return LHS.Address == RHS.Address;\n  }\n\n  /// \\brief Inquality operator for \\ref Addr.\n  friend constexpr bool operator!=(const Addr& LHS, const Addr& RHS) noexcept {\n    return !operator==(LHS, RHS);\n  }\n\n  /// \\brief Less-than operator for \\ref Addr.\n  friend constexpr bool operator<(const Addr& LHS, const Addr& RHS) noexcept {\n    return LHS.Address < RHS.Address;\n  }\n\n  /// \\brief Greater-than operator for \\ref Addr.\n  friend constexpr bool operator>(const Addr& LHS, const Addr& RHS) noexcept {\n    return operator<(RHS, LHS);\n  }\n\n  /// \\brief Less-than-or-equal operator for \\ref Addr.\n  friend constexpr bool operator<=(const Addr& LHS, const Addr& RHS) noexcept {\n    return !operator<(RHS, LHS);\n  }\n\n  /// \\brief Greater-than-or-equal operator for \\ref Addr.\n  friend constexpr bool operator>=(const Addr& LHS, const Addr& RHS) noexcept {\n    return !operator<(LHS, RHS);\n  }\n\nprivate:\n  value_type Address{0};\n};\n\n/// \\brief A range of addresses.\nclass GTIRB_EXPORT_API AddrRange {\npublic:\n  /// \\brief Construct a range starting at \\p Lower, extending up to, but not\n  /// including, \\p Upper.\n  ///\n  /// Ranges cannot have negative size, so `AddrRange(Addr(20), Addr(10))`\n  /// creates a range starting at `Addr(20)` with size 0.\n  ///\n  /// \\param Lower  first address in the range.\n  /// \\param Upper  address after the last address contained in the range.\n  constexpr explicit AddrRange(Addr Lower, Addr Upper) noexcept\n      : First(Lower), Size(Upper - (Lower < Upper ? Lower : Upper)) {}\n\n  /// \\brief Construct a range starting at \\p Lower and containing a total of\n  /// \\p Count addresses.\n  ///\n  /// \\param Lower  first address in the range.\n  /// \\param Count  number of addresses in the range.\n  constexpr explicit AddrRange(Addr Lower, uint64_t Count) noexcept\n      : First(Lower), Size(Count) {}\n\n  /// \\brief Equality operator for \\ref AddrRange.\n  constexpr bool operator==(const AddrRange& RHS) const noexcept {\n    return First == RHS.First && Size == RHS.Size;\n  }\n\n  /// \\brief Inequality operator for \\ref AddrRange.\n  constexpr bool operator!=(const AddrRange& RHS) const noexcept {\n    return First != RHS.First || Size != RHS.Size;\n  }\n\n  /// \\brief Inclusive lower bound of the address range.\n  constexpr Addr lower() const noexcept { return First; }\n\n  /// \\brief Exclusive upper bound of the address range.\n  constexpr Addr upper() const noexcept { return First + Size; }\n\n  /// \\brief Number of addresses in the range.\n  constexpr uint64_t size() const noexcept { return Size; }\n\nprivate:\n  /// \\brief The first address in the range.\n  Addr First;\n\n  /// \\brief The number of bytes in the range.\n  uint64_t Size;\n};\n\ntemplate <typename T> std::optional<uint64_t> asOptionalSize(T X);\n\ntemplate <> std::optional<uint64_t> inline asOptionalSize(uint64_t X) {\n  return X;\n}\n\ntemplate <>\nstd::optional<uint64_t> inline asOptionalSize(std::optional<uint64_t> X) {\n  return X;\n}\n\n/// \\relates Addr\n/// \\brief Address range of an object.\n///\n/// \\tparam T         Any type that specifies a range of addresses via\n/// getAddress() and getSize() methods (e.g., DataBlock).\n///\n/// \\param Object     The object to interrogate.\n///\n/// \\return An address range (\\ref AddrRange) [L, H) such that all and only the\n/// addresses L <= A < H are in \\p Object, or \\c std::nullopt if the object's\n/// addresses are not defined.\ntemplate <typename T> std::optional<AddrRange> addressRange(const T& Object) {\n  if (std::optional<Addr> A = Object.getAddress()) {\n    if (std::optional<uint64_t> S = Object.getSize()) {\n      return AddrRange{*A, *S};\n    }\n  }\n  return std::nullopt;\n}\n\n/// \\relates Addr\n/// \\brief Exclusive upper limit of an object's address range.\n///\n/// \\tparam T         Any type that specifies a range of addresses via\n/// getAddress() and getSize() methods (e.g. DataBlock).\n///\n/// \\param Object     The object to interrogate.\n///\n/// \\return An address (\\ref Addr) A such that A-1 is in \\p Object and\n/// A is not.\ntemplate <typename T> std::optional<Addr> addressLimit(const T& Object) {\n  auto A = Object.getAddress();\n  auto B = asOptionalSize(Object.getSize());\n  if (A && B) {\n    return *A + *B;\n  }\n  return std::nullopt;\n}\n\n/// \\relates Addr\n/// \\brief Check: Does the specified object contain the specified address?\n///\n/// \\tparam T      Any type that specifies a range of addresses via\n/// getAddress() and getSize() methods (e.g. DataBlock).\n///\n/// \\param Object  The object of interest.\n/// \\param Ea      The address of interest.\n///\n/// \\return \\c true if \\p Ea is in the address range of \\p Object, \\c\n/// false otherwise.\ntemplate <typename T> bool containsAddr(const T& Object, Addr Ea) {\n  return Object.getAddress() <= Ea && addressLimit(Object) > Ea;\n}\n\n/// \\relates Addr\n/// \\brief Writes an address to an output stream in hex.\n///\n/// This is a convenience, since this seems to be the format that is most\n/// commonly used. Note that other formats can be used by casting the address\n/// to a \\c uint64_t and setting the formatting explicilty.\n///\n/// \\param Stream  the stream to write to.\n/// \\param A       the address to write.\n///\n/// \\return Stream.\ntemplate <typename CharT, typename Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& Stream, Addr A) {\n  auto Flags = Stream.flags();\n  Stream << std::setbase(16) << std::showbase << static_cast<uint64_t>(A);\n  Stream.flags(Flags);\n  return Stream;\n}\n\n/// \\relates Addr\n/// \\brief Writes an optional address to an output stream in hex.\n///\n/// This is a convenience to unwrap an Addr stored in a std::optional. If the\n/// optional does not hold a valid Addr object, then <none> is printed to the\n/// stream.\n///\n/// \\param Stream  the stream to write to.\n/// \\param A       the optional address to write.\n///\n/// \\return Stream.\ntemplate <typename CharT, typename Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& Stream, std::optional<Addr> A) {\n  if (A)\n    return Stream << *A;\n  return Stream << \"<none>\";\n}\n\n} // namespace gtirb\n\nnamespace std {\n\n/// \\brief Hash operation for \\ref Addr.\ntemplate <> struct hash<gtirb::Addr> {\n  size_t operator()(const gtirb::Addr& A) const {\n    return std::hash<uint64_t>{}(static_cast<uint64_t>(A));\n  }\n};\n\n} // namespace std\n\n#endif // GTIRB_ADDR_H\n"
  },
  {
    "path": "include/gtirb/Allocator.hpp",
    "content": "//===- Allocator.hpp --------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===-Addition License Information-----------------------------------------===//\n//\n// This file was initially written for the LLVM Compiler Infrastructure\n// project where it is distributed under the University of Illinois Open Source\n// License. See the LICENSE file in the project root for license terms.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_ALLOCATOR_H\n#define GTIRB_ALLOCATOR_H\n\n#include <algorithm>\n#include <cassert>\n#include <cstddef>\n#include <cstdint>\n#include <cstdlib>\n#include <iterator>\n#include <utility>\n#include <vector>\n\n/// @cond INTERNAL\n#ifndef GTIRB_WRAP_UTILS_IN_NAMESPACE\n#define GTIRB_DEPRECATED_UTILS                                                 \\\n  [[deprecated(\"Define GTIRB_WRAP_UTILS_IN_NAMESPACE and access via the \"      \\\n               \"gtirb namespace to suppress this error.\")]]\n#else\n#define GTIRB_DEPRECATED_UTILS\n#endif\n/// @endcond\n\nnamespace gtirb {\n\n// We want clients to use the names in the gtirb namespace, so we exclude\n// the allocator namespace when generating documentation.\n/// @cond INTERNAL\nnamespace allocator {\n/// @endcond\n\n/// Returns the next power of two (in 64-bits) that is strictly greater than A.\n/// Returns zero on overflow.\n///\n/// (Deprecated) Available in the global namespace when\n/// GTIRB_WRAP_UTILS_IN_NAMESPACE is enabled.\nGTIRB_DEPRECATED_UTILS inline uint64_t NextPowerOf2(uint64_t A) {\n  A |= (A >> 1);\n  A |= (A >> 2);\n  A |= (A >> 4);\n  A |= (A >> 8);\n  A |= (A >> 16);\n  A |= (A >> 32);\n  return A + 1;\n}\n\n/// Return true if the argument is a power of two > 0 (64 bit edition.)\n///\n/// (Deprecated) Available in the global namespace when\n/// GTIRB_WRAP_UTILS_IN_NAMESPACE is enabled.\nGTIRB_DEPRECATED_UTILS constexpr inline bool isPowerOf2_64(uint64_t Value) {\n  return Value && !(Value & (Value - 1));\n}\n\n/// Aligns \\c Addr to \\c Alignment bytes, rounding up.\n///\n/// Alignment should be a power of two.  This method rounds up, so\n/// alignAddr(7, 4) == 8 and alignAddr(8, 4) == 8.\n///\n/// (Deprecated) Available in the global namespace when\n/// GTIRB_WRAP_UTILS_IN_NAMESPACE is enabled.\nGTIRB_DEPRECATED_UTILS inline uintptr_t alignAddr(const void* Addr,\n                                                  size_t Alignment) {\n  assert(Alignment && isPowerOf2_64((uint64_t)Alignment) &&\n         \"Alignment is not a power of two!\");\n\n  assert((uintptr_t)Addr + Alignment - 1 >= (uintptr_t)Addr);\n\n  return (((uintptr_t)Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1));\n}\n\n/// Returns the necessary adjustment for aligning \\c Ptr to \\c Alignment\n/// bytes, rounding up.\n///\n/// (Deprecated) Available in the global namespace when\n/// GTIRB_WRAP_UTILS_IN_NAMESPACE is enabled.\nGTIRB_DEPRECATED_UTILS inline size_t alignmentAdjustment(const void* Ptr,\n                                                         size_t Alignment) {\n  return alignAddr(Ptr, Alignment) - (uintptr_t)Ptr;\n}\n\n/// Allocate memory in an ever growing pool, as if by bump-pointer.\n///\n/// This isn't strictly a bump-pointer allocator as it uses backing slabs of\n/// memory rather than relying on a boundless contiguous heap. However, it has\n/// bump-pointer semantics in that it is a monotonically growing pool of memory\n/// where every allocation is found by merely allocating the next N bytes in\n/// the slab, or the next N bytes in the next slab.\n///\n/// Note that this also has a threshold for forcing allocations above a certain\n/// size into their own slab.\ntemplate <size_t SlabSize = 4096, size_t SizeThreshold = SlabSize>\nclass GTIRB_DEPRECATED_UTILS BumpPtrAllocatorImpl {\npublic:\n  static_assert(SizeThreshold <= SlabSize,\n                \"The SizeThreshold must be at most the SlabSize to ensure \"\n                \"that objects larger than a slab go into their own memory \"\n                \"allocation.\");\n\n  BumpPtrAllocatorImpl() = default;\n\n  // Manually implement a move constructor as we must clear the old allocator's\n  // slabs as a matter of correctness.\n  BumpPtrAllocatorImpl(BumpPtrAllocatorImpl&& Old)\n      : CurPtr(Old.CurPtr), End(Old.End), Slabs(std::move(Old.Slabs)),\n        CustomSizedSlabs(std::move(Old.CustomSizedSlabs)),\n        BytesAllocated(Old.BytesAllocated), RedZoneSize(Old.RedZoneSize) {\n    Old.CurPtr = Old.End = nullptr;\n    Old.BytesAllocated = 0;\n    Old.Slabs.clear();\n    Old.CustomSizedSlabs.clear();\n  }\n\n  ~BumpPtrAllocatorImpl() {\n    DeallocateSlabs(Slabs.begin(), Slabs.end());\n    DeallocateCustomSizedSlabs();\n  }\n\n  BumpPtrAllocatorImpl& operator=(BumpPtrAllocatorImpl&& RHS) {\n    DeallocateSlabs(Slabs.begin(), Slabs.end());\n    DeallocateCustomSizedSlabs();\n\n    CurPtr = RHS.CurPtr;\n    End = RHS.End;\n    BytesAllocated = RHS.BytesAllocated;\n    RedZoneSize = RHS.RedZoneSize;\n    Slabs = std::move(RHS.Slabs);\n    CustomSizedSlabs = std::move(RHS.CustomSizedSlabs);\n\n    RHS.CurPtr = RHS.End = nullptr;\n    RHS.BytesAllocated = 0;\n    RHS.Slabs.clear();\n    RHS.CustomSizedSlabs.clear();\n    return *this;\n  }\n\n  /// Allocate space at the specified alignment.\n  void* Allocate(size_t Size, size_t Alignment) {\n    assert(Alignment > 0 && \"0-byte alignnment is not allowed. Use 1 instead.\");\n\n    // Keep track of how many bytes we've allocated.\n    BytesAllocated += Size;\n\n    size_t Adjustment = alignmentAdjustment(CurPtr, Alignment);\n    assert(Adjustment + Size >= Size && \"Adjustment + Size must not overflow\");\n\n    size_t SizeToAllocate = Size;\n\n    // Check if we have enough space.\n    if (Adjustment + SizeToAllocate <= size_t(End - CurPtr)) {\n      char* AlignedPtr = CurPtr + Adjustment;\n      CurPtr = AlignedPtr + SizeToAllocate;\n      return AlignedPtr;\n    }\n\n    // If Size is really big, allocate a separate slab for it.\n    size_t PaddedSize = SizeToAllocate + Alignment - 1;\n    if (PaddedSize > SizeThreshold) {\n      void* NewSlab = std::malloc(PaddedSize);\n      CustomSizedSlabs.push_back(std::make_pair(NewSlab, PaddedSize));\n\n      uintptr_t AlignedAddr = alignAddr(NewSlab, Alignment);\n      assert(AlignedAddr + Size <= (uintptr_t)NewSlab + PaddedSize);\n      char* AlignedPtr = (char*)AlignedAddr;\n      return AlignedPtr;\n    }\n\n    // Otherwise, start a new slab and try again.\n    StartNewSlab();\n    uintptr_t AlignedAddr = alignAddr(CurPtr, Alignment);\n    assert(AlignedAddr + SizeToAllocate <= (uintptr_t)End &&\n           \"Unable to allocate memory!\");\n    char* AlignedPtr = (char*)AlignedAddr;\n    CurPtr = AlignedPtr + SizeToAllocate;\n    return AlignedPtr;\n  }\n\n  /// Allocate space for a sequence of objects without constructing them.\n  template <typename T> T* Allocate(size_t Num = 1) {\n    return static_cast<T*>(Allocate(Num * sizeof(T), alignof(T)));\n  }\n\n  // Bump pointer allocators are expected to never free their storage; and\n  // clients expect pointers to remain valid for non-dereferencing uses even\n  // after deallocation.\n  void Deallocate(const void*, size_t) {}\n\n  size_t GetNumSlabs() const { return Slabs.size() + CustomSizedSlabs.size(); }\n\n  size_t getTotalMemory() const {\n    size_t TotalMemory = 0;\n    for (auto I = Slabs.begin(), E = Slabs.end(); I != E; ++I)\n      TotalMemory += computeSlabSize(std::distance(Slabs.begin(), I));\n    for (auto& PtrAndSize : CustomSizedSlabs)\n      TotalMemory += PtrAndSize.second;\n    return TotalMemory;\n  }\n\n  size_t getBytesAllocated() const { return BytesAllocated; }\n\n  void setRedZoneSize(size_t NewSize) { RedZoneSize = NewSize; }\n\nprivate:\n  /// The current pointer into the current slab.\n  ///\n  /// This points to the next free byte in the slab.\n  char* CurPtr = nullptr;\n\n  /// The end of the current slab.\n  char* End = nullptr;\n\n  /// The slabs allocated so far.\n  std::vector<void*> Slabs;\n\n  /// Custom-sized slabs allocated for too-large allocation requests.\n  std::vector<std::pair<void*, size_t>> CustomSizedSlabs;\n\n  /// How many bytes we've allocated.\n  ///\n  /// Used so that we can compute how much space was wasted.\n  size_t BytesAllocated = 0;\n\n  /// The number of bytes to put between allocations when running under\n  /// a sanitizer.\n  size_t RedZoneSize = 1;\n\n  static size_t computeSlabSize(size_t SlabIdx) {\n    // Scale the actual allocated slab size based on the number of slabs\n    // allocated. Every 128 slabs allocated, we double the allocated size to\n    // reduce allocation frequency, but saturate at multiplying the slab size by\n    // 2^30.\n    return SlabSize * ((size_t)1 << std::min<size_t>(30, SlabIdx / 128));\n  }\n\n  /// Allocate a new slab and move the bump pointers over into the new\n  /// slab, modifying CurPtr and End.\n  void StartNewSlab() {\n    size_t AllocatedSlabSize = computeSlabSize(Slabs.size());\n\n    void* NewSlab = std::malloc(AllocatedSlabSize);\n\n    Slabs.push_back(NewSlab);\n    CurPtr = (char*)(NewSlab);\n    End = ((char*)NewSlab) + AllocatedSlabSize;\n  }\n\n  /// Deallocate a sequence of slabs.\n  void DeallocateSlabs(std::vector<void*>::iterator I,\n                       std::vector<void*>::iterator E) {\n    for (; I != E; ++I) {\n      std::free(*I);\n    }\n  }\n\n  /// Deallocate all memory for custom sized slabs.\n  void DeallocateCustomSizedSlabs() {\n    for (auto& PtrAndSize : CustomSizedSlabs) {\n      std::free(PtrAndSize.first);\n    }\n  }\n\n  template <typename T> friend class SpecificBumpPtrAllocator;\n};\n\n/// The standard BumpPtrAllocator which just uses the default template\n/// parameters.\n///\n/// (Deprecated) Available in the global namespace when\n/// GTIRB_WRAP_UTILS_IN_NAMESPACE is enabled.\ntypedef BumpPtrAllocatorImpl<> BumpPtrAllocator;\n\n/// A BumpPtrAllocator that allows only elements of a specific type to be\n/// allocated.\n///\n/// This allows calling the destructor in DestroyAll() and when the allocator is\n/// destroyed.\n///\n/// (Deprecated) Available in the global namespace when\n/// GTIRB_WRAP_UTILS_IN_NAMESPACE is enabled.\ntemplate <typename T> class GTIRB_DEPRECATED_UTILS SpecificBumpPtrAllocator {\n  BumpPtrAllocator Allocator;\n\npublic:\n  SpecificBumpPtrAllocator() {\n    // Because SpecificBumpPtrAllocator walks the memory to call destructors,\n    // it can't have red zones between allocations.\n    Allocator.setRedZoneSize(0);\n  }\n  SpecificBumpPtrAllocator(SpecificBumpPtrAllocator&& Old)\n      : Allocator(std::move(Old.Allocator)) {}\n  ~SpecificBumpPtrAllocator() { DestroyAll(); }\n\n  SpecificBumpPtrAllocator& operator=(SpecificBumpPtrAllocator&& RHS) {\n    Allocator = std::move(RHS.Allocator);\n    return *this;\n  }\n\n  /// Allocate space for an array of objects without constructing them.\n  T* Allocate(size_t num = 1) { return Allocator.Allocate<T>(num); }\n\n  /// Forgets all allocations from the underlying allocator, effectively\n  /// leaking the memory. This is useful when the allocator is no longer needed\n  /// and the operating system will be reclaiming the memory (such as at\n  // program shutdown time).\n  void ForgetAllocations() {\n    Allocator.Slabs.clear();\n    Allocator.CustomSizedSlabs.clear();\n  }\n\nprivate:\n  /// Call the destructor of each allocated object and deallocate all but the\n  /// current slab and reset the current pointer to the beginning of it, freeing\n  /// all memory allocated so far.\n  void DestroyAll() {\n    auto DestroyElements = [](char* Begin, char* End) {\n      assert(Begin == (char*)alignAddr(Begin, alignof(T)));\n      for (char* Ptr = Begin; Ptr + sizeof(T) <= End; Ptr += sizeof(T))\n        reinterpret_cast<T*>(Ptr)->~T();\n    };\n\n    for (auto I = Allocator.Slabs.begin(), E = Allocator.Slabs.end(); I != E;\n         ++I) {\n      size_t AllocatedSlabSize = BumpPtrAllocator::computeSlabSize(\n          std::distance(Allocator.Slabs.begin(), I));\n      char* Begin = (char*)alignAddr(*I, alignof(T));\n      char* End = *I == Allocator.Slabs.back() ? Allocator.CurPtr\n                                               : (char*)*I + AllocatedSlabSize;\n\n      DestroyElements(Begin, End);\n    }\n\n    for (auto& PtrAndSize : Allocator.CustomSizedSlabs) {\n      void* Ptr = PtrAndSize.first;\n      size_t Size = PtrAndSize.second;\n      DestroyElements((char*)alignAddr(Ptr, alignof(T)), (char*)Ptr + Size);\n    }\n  }\n};\n\n/// @cond INTERNAL\n} // namespace allocator\n/// @endcond\n\n#ifdef GTIRB_WRAP_UTILS_IN_NAMESPACE\n\nusing allocator::alignAddr;\nusing allocator::alignmentAdjustment;\nusing allocator::BumpPtrAllocator;\nusing allocator::isPowerOf2_64;\nusing allocator::NextPowerOf2;\nusing allocator::SpecificBumpPtrAllocator;\n\n#endif // GTIRB_WRAP_UTILS_IN_NAMESPACE\n\n} // namespace gtirb\n\n#ifndef GTIRB_WRAP_UTILS_IN_NAMESPACE\n\nusing gtirb::allocator::alignAddr;\nusing gtirb::allocator::alignmentAdjustment;\nusing gtirb::allocator::BumpPtrAllocator;\nusing gtirb::allocator::isPowerOf2_64;\nusing gtirb::allocator::NextPowerOf2;\nusing gtirb::allocator::SpecificBumpPtrAllocator;\n\n#endif // GTIRB_WRAP_UTILS_IN_NAMESPACE\n\ntemplate <size_t SlabSize, size_t SizeThreshold>\nvoid* operator new(size_t Size, gtirb::allocator::BumpPtrAllocatorImpl<\n                                    SlabSize, SizeThreshold>& Allocator) {\n  struct S {\n    char c;\n    union {\n      double D;\n      long double LD;\n      long long L;\n      void* P;\n    } x;\n  };\n  return Allocator.Allocate(\n      Size,\n      std::min((size_t)gtirb::allocator::NextPowerOf2(Size), offsetof(S, x)));\n}\n\ntemplate <size_t SlabSize, size_t SizeThreshold>\nvoid operator delete(\n    void*, gtirb::allocator::BumpPtrAllocatorImpl<SlabSize, SizeThreshold>&) {}\n\n#endif // GTIRB_ALLOCATOR_H\n"
  },
  {
    "path": "include/gtirb/AuxData.hpp",
    "content": "//===- AuxData.hpp -----------------------------------------------*- C++-*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_AUXDATA_H\n#define GTIRB_AUXDATA_H\n\n#include <gtirb/Addr.hpp>\n#include <gtirb/Node.hpp>\n#include <gtirb/Offset.hpp>\n#include <boost/endian/conversion.hpp>\n#include <deque>\n#include <iostream>\n#include <list>\n#include <map>\n#include <set>\n#include <string>\n#include <type_traits>\n#include <typeinfo>\n#include <unordered_map>\n#include <unordered_set>\n#include <variant>\n#include <vector>\n\n/// \\file AuxData.hpp\n/// \\ingroup AUXDATA_GROUP\n/// \\brief  Types and operations for auxiliary data.\n/// \\see AUXDATA_GROUP\n\nnamespace gtirb {\nnamespace proto {\nclass AuxData;\n} // namespace proto\nclass Context;\n\n/// \\defgroup AUXDATA_GROUP AuxData\n/// \\brief \\ref AuxData objects can be attached to the \\ref IR or individual\n/// \\ref Modules to store additional client-specific data in a portable way.\n///\n/// AuxData can store the following types:\n///   - all integral types\n///   - Addr\n///   - Offset\n///   - \\ref UUID\n///   - sequential containers\n///   - mapping containers\n///   - std::tuple\n///\n/// ### Supporting Additional Types\n///\n/// Support for additional containers can be added by specializing \\ref\n/// is_sequence or \\ref is_mapping. Once serialized, the data does not\n/// depend on any specific container type, and its contents can be\n/// deserialized into different containers of the same kind (e.g. \\c std::list\n/// to \\c std::vector).\n///\n/// Support for other types can be added by specializing \\ref auxdata_traits to\n/// provide serialization functions. However, \\ref AuxData containing these\n/// types will not be accessible to other clients which are not compiled with\n/// support for those types. It is preferable to store data using the basic\n/// types whenever possible, in order to maximize interoperability.\n///\n///\n/// ### 'Sanctioned' AuxData Tables\n///\n/// We specify a small number of standard AuxData table schemata to\n/// support interoperability. For details, see \\ref md_AuxData. C++\n/// schemata for the sanctioned tables are present in \\ref\n/// AuxDataSchema.hpp.\n///\n/// ### Adding Custom AuxData Tables\n///\n/// Clients may add their own AuxData tables in the C++ API by\n/// defining their own schemata. Schemata should be defined by\n/// extending the gtirb::schema namespace. Each schema should be a\n/// struct declaring public members for the type's name and its C++\n/// type. One can follow the model provided by the schemata in \\ref\n/// AuxDataSchema.hpp.\n///\n/// ### Serialization Format\n///\n/// AuxData is serialized by packing the contents into a byte array, which\n/// is stored in a protobuf message along with a string which identifies the\n/// type in a portable fashion.\n///\n/// Fixed-size types such as integers, Addr, etc are packed by swapping their\n/// bytes to little-endian order and writing them directly to the byte\n/// array. Containers first write out the number of elements (as a uint64_t),\n/// then write each element one after another. Tuples are similar but omit\n/// the size, since it can be inferred from the type.\n\n/// @{\n\n/// \\struct is_sequence\n///\n/// \\brief Trait class that identifies whether T is a sequential\n/// container type.\n///\n/// \\see AUXDATA_GROUP\ntemplate <class T> struct is_sequence : std::false_type {};\n\n/// @cond INTERNAL\ntemplate <class T> struct is_sequence<std::vector<T>> : std::true_type {};\ntemplate <class T> struct is_sequence<std::list<T>> : std::true_type {};\ntemplate <class T> struct is_sequence<std::deque<T>> : std::true_type {};\n/// @endcond\n\n/// \\struct is_mapping\n///\n/// \\brief Trait class that identifies whether T is a mapping container type.\n///\n/// \\see AUXDATA_GROUP\ntemplate <class T> struct is_mapping : std::false_type {};\n/// @cond INTERNAL\ntemplate <class T, class U>\nstruct is_mapping<std::map<T, U>> : std::true_type {};\ntemplate <class T, class U>\nstruct is_mapping<std::unordered_map<T, U>> : std::true_type {};\n// Explicitly disable multimaps. Because they can contain multiple values for\n// a given key, they can't be used interchangeably with maps.\ntemplate <class T, class U>\nstruct is_mapping<std::multimap<T, U>> : std::false_type {};\ntemplate <class T, class U>\nstruct is_mapping<std::unordered_multimap<T, U>> : std::false_type {};\n/// @endcond\n\n/// \\struct is_set\n///\n/// \\brief Trait class that identifies whether T is a set container type.\n///\n/// \\see AUXDATA_GROUP\ntemplate <class T> struct is_set : std::false_type {};\n/// @cond internal\ntemplate <class... Args> struct is_set<std::set<Args...>> : std::true_type {};\ntemplate <class... Args>\nstruct is_set<std::unordered_set<Args...>> : std::true_type {};\n// Explicitly disable multisets. Because they can contain multiple equivalent\n// values, they can't be used interchangeably with sets.\ntemplate <class... Args>\nstruct is_set<std::multiset<Args...>> : std::false_type {};\ntemplate <class... Args>\nstruct is_set<std::unordered_multiset<Args...>> : std::false_type {};\n/// @endcond\n\n/// \\struct is_tuple\n///\n/// \\brief Trait class that identifies whether T is tuple-like.\n///\n/// \\see AUXDATA_GROUP\ntemplate <class T> struct is_tuple : std::false_type {};\n/// @cond INTERNAL\ntemplate <class... Args>\nstruct is_tuple<std::tuple<Args...>> : std::true_type {};\n\ntemplate <class... Args>\nstruct is_tuple<std::pair<Args...>> : std::true_type {};\n\n// Utility class for serializing AuxData.\nclass ToByteRange {\npublic:\n  explicit ToByteRange(std::string& Bytes) : It(std::back_inserter(Bytes)) {}\n\n  void write(std::byte Byte) { *It = static_cast<char>(Byte); }\n\nprivate:\n  std::back_insert_iterator<std::string> It;\n};\n\n// Utility class for deserializing AuxData.\nclass FromByteRange {\npublic:\n  explicit FromByteRange(const std::string& Bytes)\n      : Curr(Bytes.begin()), End(Bytes.end()) {}\n\n  bool read(std::byte& Byte) {\n    if (Curr == End)\n      return false;\n\n    Byte = std::byte(*Curr);\n    ++Curr;\n    return true;\n  }\n\n  uint64_t remainingBytesToRead() const {\n    return static_cast<uint64_t>(std::distance(Curr, End));\n  }\n\nprivate:\n  std::string::const_iterator Curr;\n  std::string::const_iterator End;\n};\n\n///@endcond\n\n/// \\struct auxdata_traits\n///\n/// \\brief Provides type information and serialization functions\n/// for types which can be stored in \\ref AuxData.\n///\n/// \\see AUXDATA_GROUP\ntemplate <class T, class Enable = void> struct auxdata_traits {\n  /// \\brief  Serialize an object to a sequence of bytes.\n  ///\n  /// \\param Object  The object to serialize.\n  /// \\param TBR     Store byte sequence here.\n  static void toBytes(const T& Object, ToByteRange& TBR) = delete;\n\n  /// \\brief  Deserialize an object from a sequence of bytes.\n  ///\n  /// \\param Object  The object to deserialize.\n  /// \\param FBR     Read bytes from here.\n  /// \\return True/false dependending on if the bytes were deserialized\n  /// successfully.\n  static bool fromBytes(T& Object, FromByteRange& FBR) = delete;\n\n  /// \\brief String representation of the serialized type of T.\n  ///\n  /// This identifier is portable and independent of the specific container\n  /// types. Integral types are represented with an exact size (e.g.\n  /// \"uint32_t\"). Sequential containers are represented as \"sequence<...>\", and\n  /// mapping containers are represented as \"mapping<...>\".\n  static std::string type_name() = delete;\n};\n\n/// @cond INTERNAL\ntemplate <class... Ts> struct TypeId {};\n\ntemplate <class T>\nstruct is_endian_type\n    : std::integral_constant<bool, std::is_class_v<T> ||\n                                       (std::is_integral_v<T> &&\n                                        !std::is_same_v<T, bool>)> {};\n\ntemplate <typename T, typename Enable = void> struct default_serialization {};\n\n// Serialize and deserialize by copying the object representation directly.\ntemplate <typename T>\nstruct default_serialization<\n    T, typename std::enable_if_t<is_endian_type<T>::value ||\n                                 std::is_floating_point<T>::value ||\n                                 std::is_same<T, bool>::value>> {\n  static void toBytes(const T& object, ToByteRange& TBR) {\n    // Store as little-endian.\n    T ordered = object;\n\n    if constexpr (!std::is_floating_point<T>::value &&\n                  !std::is_same<T, bool>::value) {\n      // Do not reorder floating point or boolean values\n      boost::endian::conditional_reverse_inplace<boost::endian::order::little,\n                                                 boost::endian::order::native>(\n          ordered);\n    }\n    auto srcBytes_begin = reinterpret_cast<const std::byte*>(&ordered);\n    auto srcBytes_end = reinterpret_cast<const std::byte*>(&ordered + 1);\n    std::for_each(srcBytes_begin, srcBytes_end, [&](auto b) { TBR.write(b); });\n  }\n\n  static bool fromBytes(T& object, FromByteRange& FBR) {\n    auto dest_begin = reinterpret_cast<std::byte*>(&object);\n    auto dest_end = reinterpret_cast<std::byte*>(&object + 1);\n    bool Success = true;\n    std::for_each(dest_begin, dest_end, [&](auto& b) {\n      if (!FBR.read(b))\n        Success = false;\n    });\n    if (!Success) {\n      return false;\n    }\n\n    // Data stored as little-endian.\n    if constexpr (!std::is_floating_point<T>::value &&\n                  !std::is_same<T, bool>::value) {\n      boost::endian::conditional_reverse_inplace<boost::endian::order::little,\n                                                 boost::endian::order::native>(\n          object);\n    }\n\n    return true;\n  }\n};\n\ntemplate <>\nstruct auxdata_traits<std::byte> : default_serialization<std::byte> {\n  static std::string type_name() { return \"byte\"; }\n\n  static void toBytes(std::byte object, ToByteRange& TBR) { TBR.write(object); }\n\n  static bool fromBytes(std::byte& object, FromByteRange& FBR) {\n    return FBR.read(object);\n  }\n};\n\ntemplate <> struct auxdata_traits<Addr> : default_serialization<Addr> {\n  static std::string type_name() { return \"Addr\"; }\n};\n\ntemplate <> struct auxdata_traits<UUID> : default_serialization<UUID> {\n  static std::string type_name() { return \"UUID\"; }\n};\n\ntemplate <class T>\nstruct auxdata_traits<T, typename std::enable_if_t<std::is_integral<T>::value &&\n                                                   std::is_signed<T>::value>>\n    : default_serialization<T> {\n  static std::string type_name() {\n    return \"int\" + std::to_string(8 * sizeof(T)) + \"_t\";\n  }\n};\n\ntemplate <class T>\nstruct auxdata_traits<T, typename std::enable_if_t<std::is_integral<T>::value &&\n                                                   std::is_unsigned<T>::value>>\n    : default_serialization<T> {\n  static std::string type_name() {\n    return \"uint\" + std::to_string(8 * sizeof(T)) + \"_t\";\n  }\n};\n\ntemplate <> struct auxdata_traits<bool> : default_serialization<bool> {\n  static std::string type_name() { return \"bool\"; }\n};\n\ntemplate <> struct auxdata_traits<float> : default_serialization<float> {\n  static std::string type_name() { return \"float\"; }\n};\n\ntemplate <> struct auxdata_traits<double> : default_serialization<double> {\n  static std::string type_name() { return \"double\"; }\n};\n\ntemplate <> struct auxdata_traits<std::string> {\n  static std::string type_name() { return \"string\"; }\n\n  static void toBytes(const std::string& Object, ToByteRange& TBR) {\n    auxdata_traits<uint64_t>::toBytes(Object.size(), TBR);\n    std::for_each(Object.begin(), Object.end(),\n                  [&](auto& elt) { auxdata_traits<char>::toBytes(elt, TBR); });\n  }\n\n  static bool fromBytes(std::string& Object, FromByteRange& FBR) {\n    uint64_t Count;\n    if (!auxdata_traits<uint64_t>::fromBytes(Count, FBR))\n      return false;\n\n    if (Count > FBR.remainingBytesToRead())\n      return false;\n\n    Object.resize(Count);\n    bool Success = true;\n    std::for_each(Object.begin(), Object.end(), [&](auto& elt) {\n      if (!auxdata_traits<char>::fromBytes(elt, FBR))\n        Success = false;\n    });\n\n    return Success;\n  }\n};\n\ntemplate <> struct auxdata_traits<Offset> {\n  static std::string type_name() { return \"Offset\"; }\n\n  static void toBytes(const Offset& Object, ToByteRange& TBR) {\n    auxdata_traits<UUID>::toBytes(Object.ElementId, TBR);\n    auxdata_traits<uint64_t>::toBytes(Object.Displacement, TBR);\n  }\n\n  static bool fromBytes(Offset& Object, FromByteRange& FBR) {\n    if (!auxdata_traits<UUID>::fromBytes(Object.ElementId, FBR))\n      return false;\n    return auxdata_traits<uint64_t>::fromBytes(Object.Displacement, FBR);\n  }\n};\n\ntemplate <class T>\nstruct auxdata_traits<T, typename std::enable_if_t<is_sequence<T>::value>> {\n  static std::string type_name() {\n    return \"sequence<\" + TypeId<typename T::value_type>::value() + \">\";\n  }\n\n  static void toBytes(const T& Object, ToByteRange& TBR) {\n    auxdata_traits<uint64_t>::toBytes(Object.size(), TBR);\n    std::for_each(Object.begin(), Object.end(), [&](const auto& Elt) {\n      auxdata_traits<typename T::value_type>::toBytes(Elt, TBR);\n    });\n  }\n\n  static bool fromBytes(T& Object, FromByteRange& FBR) {\n    uint64_t Count;\n    if (!auxdata_traits<uint64_t>::fromBytes(Count, FBR))\n      return false;\n\n    if (Count > FBR.remainingBytesToRead())\n      return false;\n\n    Object.resize(Count);\n    bool Success = true;\n    std::for_each(Object.begin(), Object.end(), [&](auto& Elt) {\n      if (!auxdata_traits<typename T::value_type>::fromBytes(Elt, FBR))\n        Success = false;\n    });\n\n    return Success;\n  }\n};\n\ntemplate <class T>\nstruct auxdata_traits<T, typename std::enable_if_t<is_set<T>::value>> {\n  static std::string type_name() {\n    return \"set<\" + TypeId<typename T::value_type>::value() + \">\";\n  }\n\n  static void toBytes(const T& Object, ToByteRange& TBR) {\n    auxdata_traits<uint64_t>::toBytes(Object.size(), TBR);\n    for (const auto& Elt : Object)\n      auxdata_traits<typename T::value_type>::toBytes(Elt, TBR);\n  }\n\n  static bool fromBytes(T& Object, FromByteRange& FBR) {\n    uint64_t Count;\n    if (!auxdata_traits<uint64_t>::fromBytes(Count, FBR))\n      return false;\n\n    if (Count > FBR.remainingBytesToRead())\n      return false;\n\n    for (uint64_t i = 0; i < Count; i++) {\n      typename T::value_type V;\n      if (!auxdata_traits<decltype(V)>::fromBytes(V, FBR))\n        return false;\n      Object.emplace(std::move(V));\n    }\n\n    return true;\n  }\n};\n\ntemplate <class T>\nstruct auxdata_traits<T, typename std::enable_if_t<is_mapping<T>::value>> {\n  static std::string type_name() {\n    return \"mapping<\" +\n           TypeId<typename T::key_type, typename T::mapped_type>::value() + \">\";\n  }\n\n  static void toBytes(const T& Object, ToByteRange& TBR) {\n    auxdata_traits<uint64_t>::toBytes(Object.size(), TBR);\n    std::for_each(Object.begin(), Object.end(), [&](const auto& Elt) {\n      auxdata_traits<typename T::key_type>::toBytes(Elt.first, TBR);\n      auxdata_traits<typename T::mapped_type>::toBytes(Elt.second, TBR);\n    });\n  }\n\n  static bool fromBytes(T& Object, FromByteRange& FBR) {\n    uint64_t Count;\n    if (!auxdata_traits<uint64_t>::fromBytes(Count, FBR))\n      return false;\n\n    if (Count > FBR.remainingBytesToRead())\n      return false;\n\n    for (uint64_t i = 0; i < Count; i++) {\n      typename T::key_type K;\n      if (!auxdata_traits<decltype(K)>::fromBytes(K, FBR))\n        return false;\n      typename T::mapped_type V;\n      if (!auxdata_traits<decltype(V)>::fromBytes(V, FBR))\n        return false;\n      Object.emplace(std::move(K), std::move(V));\n    }\n    return true;\n  }\n};\n\n/// \\brief std::variant support\n///\n/// Warning!\n/// Members of the union (std::variant) should be default constructable.\ntemplate <class... Args> struct auxdata_traits<std::variant<Args...>> {\n  using T = std::variant<Args...>;\n\n  static std::string type_name() {\n    return \"variant<\" + TypeId<Args...>::value() + \">\";\n  }\n\n  template <uint64_t I = 0>\n  static std::optional<std::variant<Args...>> expand_type(uint64_t i) {\n    if constexpr (I >= sizeof...(Args)) {\n      return std::nullopt;\n    } else {\n      return i == 0 ? std::variant<Args...>{std::in_place_index<I>,\n                                            std::variant_alternative_t<I, T>{}}\n                    : expand_type<I + 1>(i - 1);\n    }\n  };\n\n  static void toBytes(const T& Object, ToByteRange& TBR) {\n    uint64_t Index = Object.index();\n    auxdata_traits<uint64_t>::toBytes(Index, TBR);\n    std::visit(\n        [TBR](auto&& arg) mutable {\n          auxdata_traits<typename std::remove_const<\n              typename std::remove_reference<decltype(arg)>::type>::type>::\n              toBytes(arg, TBR);\n        },\n        Object);\n  }\n\n  static bool fromBytes(T& Object, FromByteRange& FBR) {\n    uint64_t Index;\n    if (!auxdata_traits<uint64_t>::fromBytes(Index, FBR))\n      return false;\n    if (Index > FBR.remainingBytesToRead())\n      return false;\n\n    auto maybeV = expand_type(Index);\n    if (!maybeV) {\n      return false;\n    }\n    auto V = *maybeV;\n    bool res_code = false;\n    std::visit(\n        [&res_code, &FBR](auto&& arg) mutable {\n          typename std::remove_reference<decltype(arg)>::type Val;\n          res_code = auxdata_traits<typename std::remove_reference<decltype(\n              arg)>::type>::fromBytes(Val, FBR);\n          if (!res_code)\n            return;\n          arg = Val;\n        },\n        V);\n    if (!res_code)\n      return false;\n    Object = V;\n    return true;\n  }\n};\n/// @endcond\n\n/// @cond INTERNAL\ntemplate <class T> struct tuple_traits {};\ntemplate <class... Ts> struct tuple_traits<std::tuple<Ts...>> {\n  using Tuple = std::tuple<Ts...>;\n\n  static std::string type_name() {\n    return \"tuple<\" + TypeId<Ts...>::value() + \">\";\n  }\n};\n\ntemplate <class... Ts> struct tuple_traits<std::pair<Ts...>> {\n  using Tuple = std::tuple<Ts...>;\n\n  static std::string type_name() {\n    return \"tuple<\" + TypeId<Ts...>::value() + \">\";\n  }\n};\n\ntemplate <class Func, size_t... Is>\nconstexpr void static_for(Func&& f, std::integer_sequence<size_t, Is...>) {\n  (f(std::integral_constant<size_t, Is>{}), ...);\n}\n\ntemplate <class T>\nstruct auxdata_traits<T, typename std::enable_if_t<is_tuple<T>::value>>\n    : tuple_traits<T> {\n  static void toBytes(const T& Object, ToByteRange& TBR) {\n    static_for(\n        [&](auto i) {\n          const auto& F = std::get<i>(Object);\n          auxdata_traits<std::remove_cv_t<\n              std::remove_reference_t<decltype(F)>>>::toBytes(F, TBR);\n        },\n        std::make_index_sequence<std::tuple_size<T>::value>{});\n  }\n\n  static bool fromBytes(T& Object, FromByteRange& FBR) {\n    bool Success = true;\n    static_for(\n        [&](auto i) {\n          auto& F = std::get<i>(Object);\n          if (!auxdata_traits<std::remove_cv_t<\n                  std::remove_reference_t<decltype(F)>>>::fromBytes(F, FBR))\n            Success = false;\n        },\n        std::make_index_sequence<std::tuple_size<T>::value>{});\n\n    return Success;\n  }\n};\n/// @endcond\n\n/// @cond INTERNAL\ntemplate <class T> struct TypeId<T> {\n  static std::string value() { return auxdata_traits<T>::type_name(); }\n};\n\ntemplate <class T, class... Ts> struct TypeId<T, Ts...> {\n  static std::string value() {\n    return auxdata_traits<T>::type_name() + \",\" + TypeId<Ts...>::value();\n  }\n};\n/// @endcond\n\n/// @cond INTERNAL\nclass GTIRB_EXPORT_API AuxData {\npublic:\n  /// !brief Structure containing the serialized representation of an\n  /// !AuxData.\n  struct SerializedForm {\n    std::string RawBytes;\n    std::string ProtobufType;\n  };\n\n  /// \\brief Construct an empty table.\n  AuxData() = default;\n\n  virtual ~AuxData() = default;\n\n  /// \\brief Returns the serialized representation of this AuxData.\n  ///\n  /// If the object is newly constructed (and wasn't unserialized from\n  /// protobuf), the content present in the returned structure will be\n  /// empty.\n  ///\n  /// If the object has been modified since being unserialized, the\n  /// content returned here will not incorporate those modifications.\n  ///\n  /// This interface is provided primarily as a means for clients to\n  /// inspect the raw data of AuxData objects whose types have not\n  /// been registered.\n  const SerializedForm& rawData() const { return this->SF; }\n\n  /// !brief The degenerate api type id used for AuxData types that\n  /// haven't been registered.\n  static constexpr std::size_t UNREGISTERED_API_TYPE_ID = 0;\n\n  /// !brief Retrieve a type-trait-specific Id number.\n  virtual std::size_t getApiTypeId() const { return UNREGISTERED_API_TYPE_ID; }\n\nprotected:\n  /// \\brief The protobuf message type used for serializing AuxData.\n  using MessageType = proto::AuxData;\n\n  /// \\brief Initialize an AuxData from a protobuf message.\n  ///\n  /// \\param Message     The protobuf message from which to deserialize.\n  /// \\param[out] Result  The AuxData to initialize.\n  static void fromProtobuf(AuxData& Result, const MessageType& Message);\n\n  /// \\brief Serialize into a protobuf message.\n  ///\n  /// \\param[out] Message  A protobuf message representing the AuxData.\n  virtual void toProtobuf(MessageType* Message) const {\n    toProtobuf(Message, this->SF);\n  }\n\n  // This version of protobuf accepts a SerializedForm object to\n  // serialize rather than serializing AuxData's SerializedForm\n  // member. This is used by AuxDataImpl to serialize a typed AuxData\n  // object. We structure it this way to avoid having the AuxDataImpl\n  // template (which is instantiated in client code) access\n  // MessageType fields directly, which would introduce\n  // dllimport/dllexport issues on Windows.\n  void toProtobuf(MessageType* Message,\n                  const SerializedForm& SFToSerialize) const;\n\n  // Utility function for the AuxDataImpl template that allows us to\n  // check the embedded type name in the serialized protobuf against an\n  // expected typename without exposing the MessageType to clients.\n  static bool checkAuxDataMessageType(const AuxData::MessageType& Message,\n                                      const std::string& ExpectedName);\n\n  // Present for testing purposes only.\n  void save(std::ostream& Out) const;\n\n  // Present for testing purposes only.\n  static std::unique_ptr<AuxData>\n  load(std::istream& In, std::unique_ptr<AuxData> (*FPPtr)(const MessageType&));\n\nprivate:\n  SerializedForm SF;\n\n  friend class AuxDataContainer; // Friend to enable fromProtobuf.\n  // Enables serialization by AuxDataContainer via containerToProtobuf.\n  template <typename T> friend typename T::MessageType toProtobuf(const T&);\n  friend class SerializationTestHarness; // Testing support.\n};\n/// @endcond\n\n/// @cond INTERNAL\ntemplate <class Schema> class AuxDataImpl : public AuxData {\npublic:\n  AuxDataImpl() = default;\n  AuxDataImpl(typename Schema::Type&& Val) : Object(std::move(Val)){};\n\n  /// !brief Register/retrieve a type-trait-specific Id number.\n  static std::size_t staticGetApiTypeId() {\n    return typeid(typename Schema::Type).hash_code();\n  }\n\n  /// \\brief Retrieve a type-trait-specific Id number.\n  virtual std::size_t getApiTypeId() const override {\n    return staticGetApiTypeId();\n  }\n\n  const typename Schema::Type* get() const { return &Object; }\n\nprivate:\n  static std::unique_ptr<AuxData> fromProtobuf(const MessageType& Message) {\n    // Check if the serialized type isn't compatible with the type\n    // we're trying to deserialize to.\n    if (!checkAuxDataMessageType(\n            Message, auxdata_traits<typename Schema::Type>::type_name())) {\n      return nullptr;\n    }\n\n    // Note: Do not access Message's contents here. That would introduce\n    // dllexport/dllimport problems on Windows. Call the base class's\n    // fromProtobuf function and then unserialize from its\n    // SerializedForm structure.\n    auto TypedAuxData = std::make_unique<AuxDataImpl<Schema>>();\n    AuxData::fromProtobuf(*TypedAuxData, Message);\n    FromByteRange FBR(TypedAuxData->rawData().RawBytes);\n    if (!auxdata_traits<typename Schema::Type>::fromBytes(TypedAuxData->Object,\n                                                          FBR))\n      return nullptr;\n    return TypedAuxData;\n  }\n\n  /// \\brief Serialize into a protobuf message.\n  ///\n  /// \\param Message     The Message to serialize into.\n  virtual void toProtobuf(MessageType* Message) const override {\n    // Note: Do not edit Message's contents here. That would introduce\n    // dllexport/dllimport problems on Windows. Store to a\n    // SerializedForm, and then call the base class's toProtobuf\n    // function.\n    AuxData::SerializedForm TypedSF;\n    TypedSF.ProtobufType = auxdata_traits<typename Schema::Type>::type_name();\n    ToByteRange TBR(TypedSF.RawBytes);\n    auxdata_traits<typename Schema::Type>::toBytes(this->Object, TBR);\n    AuxData::toProtobuf(Message, TypedSF);\n  }\n\n  // Present for testing purposes only.\n  void save(std::ostream& Out) const { AuxData::save(Out); }\n\n  // Present for testing purposes only.\n  static std::unique_ptr<AuxDataImpl> load([[maybe_unused]] Context& C,\n                                           std::istream& In) {\n    return std::unique_ptr<AuxDataImpl>{\n        static_cast<AuxDataImpl*>(AuxData::load(In, fromProtobuf).release())};\n  }\n\n  typename Schema::Type Object;\n\n  friend class AuxDataContainer;         // Friend to enable to/fromProtobuf.\n  friend class SerializationTestHarness; // Testing support.\n};\n/// @endcond\n\n// (end \\defgroup AUXDATA_GROUP)\n\n} // namespace gtirb\n\n#endif // GTIRB_AUXDATA_H\n"
  },
  {
    "path": "include/gtirb/AuxDataContainer.hpp",
    "content": "//===- AuxDataContainer.hpp -------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n\n#ifndef GTIRB_AUXDATACONTAINER_H\n#define GTIRB_AUXDATACONTAINER_H\n\n#include <gtirb/AuxData.hpp>\n#include <gtirb/Node.hpp>\n#include <boost/iterator/transform_iterator.hpp>\n#include <boost/range/iterator_range.hpp>\n#include <type_traits>\n\n/// \\file AuxDataContainer.hpp\n/// \\brief Class gtirb::AuxDataContainer.\n\nnamespace gtirb {\n\nnamespace proto {\nclass IR;\nclass Module;\n} // namespace proto\n\n/// @cond INTERNAL\ntemplate <typename MessageType> struct message_has_aux_data_container {\n  static constexpr bool value = false;\n};\ntemplate <> struct message_has_aux_data_container<proto::IR> {\n  static constexpr bool value = true;\n};\ntemplate <> struct message_has_aux_data_container<proto::Module> {\n  static constexpr bool value = true;\n};\n\n/// \\brief True if MessageType is a message that holds a \\ref AuxDataContainer.\ntemplate <typename MessageType>\ninline constexpr bool message_has_aux_data_container_v =\n    message_has_aux_data_container<MessageType>::value;\n/// @endcond\n\n/// \\class AuxDataContainer\n///\n/// \\brief Contains the AuxData Tables and serves as a base class.\n\nclass GTIRB_EXPORT_API AuxDataContainer : public Node {\n  using AuxDataSet = std::map<std::string, std::unique_ptr<gtirb::AuxData>>;\n\npublic:\n  /// \\name AuxData Properties\n  /// @{\n\n  /// \\brief Register a type to be used with AuxData of the given name.\n  template <typename Schema> static void registerAuxDataType() {\n    registerAuxDataTypeInternal(Schema::Name,\n                                std::make_unique<AuxDataTypeImpl<Schema>>());\n  }\n\n  /// \\brief Add a new \\ref AuxData, transferring ownership.\n  ///\n  /// \\param X        The data itself.\n  ///\n  /// \\return void\n  ///\n  template <typename Schema> void addAuxData(typename Schema::Type&& X) {\n    // Make sure this type matches a registered type.\n    assert(checkAuxDataRegistration(\n               Schema::Name, AuxDataImpl<Schema>::staticGetApiTypeId()) &&\n           \"Attempting to add AuxData with unregistered or incorrect type.\");\n    this->AuxDatas[Schema::Name] =\n        std::make_unique<AuxDataImpl<Schema>>(std::move(X));\n  }\n\n  /// \\brief Get a reference to the underlying type stored in the \\ref\n  ///        AuxData by name.\n  ///\n  /// \\return     A non-owning pointer to the data if found,\n  ///             \\c nullptr otherwise.\n  ///\n  /// Note that this function can only be used for AuxData for which a\n  /// type has been registered with registerAuxDataType().\n  template <typename Schema> typename Schema::Type* getAuxData() {\n    return const_cast<typename Schema::Type*>(\n        const_cast<const AuxDataContainer*>(this)->getAuxData<Schema>());\n  }\n\n  /// \\brief Get a reference to the underlying type stored in the \\ref\n  ///        AuxData by name.\n  ///\n  /// \\return     A non-owning pointer to the data if found,\n  ///             \\c nullptr otherwise.\n  ///\n  /// Note that this function can only be used for AuxData for which a\n  /// type has been registered with registerAuxDataType().\n  template <typename Schema> const typename Schema::Type* getAuxData() const {\n    auto Found = this->AuxDatas.find(Schema::Name);\n\n    if (Found == this->AuxDatas.end())\n      return nullptr;\n\n    AuxData& AD = *(Found->second);\n\n    // Is the type of the AuxData registered?\n    if (AD.getApiTypeId() == AuxData::UNREGISTERED_API_TYPE_ID) {\n      // We can get here for two reasons:\n      //\n      //  1) The type is not registered. We treat this as a developer\n      //  error and assert. getAuxData should only ever be called for\n      //  types that are registered.\n      //\n      //  2) The type is registered, but the attempt to unserialized\n      //  the AuxData using the registered type failed. This is a\n      //  legitimate runtime error situation. An example might be\n      //  loading a GTIRB file that has a previous version of the\n      //  AuxData with a different type. In this situation, we don't\n      //  want to assert, just return nullptr.\n      assert(checkAuxDataRegistration(\n                 Schema::Name, AuxDataImpl<Schema>::staticGetApiTypeId()) &&\n             \"Attempting to retrieve AuxData with an unregistered type.\");\n      return nullptr;\n    }\n\n    // Does the type match the type being requested?\n    if (AD.getApiTypeId() != AuxDataImpl<Schema>::staticGetApiTypeId()) {\n      assert(false && \"Attempting to retrieve AuxData with incorrect type.\");\n      return nullptr;\n    }\n\n    // If we get here, it should be safe to downcast to the typed AuxDataImpl.\n    auto& ADI = static_cast<AuxDataImpl<Schema>&>(AD);\n    return ADI.get();\n  }\n\n  /// \\brief Remove an \\ref AuxData by schema.\n  ///\n  /// This will invalidate any pointers that may have been held externally.\n  ///\n  /// \\return     \\c true on success, \\c false otherwise.\n  ///\n  /// Note that this function can only be used for AuxData for which a\n  /// type has been registered with registerAuxDataType().\n  template <typename Schema> bool removeAuxData() {\n    assert(checkAuxDataRegistration(\n               Schema::Name, AuxDataImpl<Schema>::staticGetApiTypeId()) &&\n           \"Attempting to remove AuxData with an unregistered type.\");\n    return this->AuxDatas.erase(Schema::Name) > 0;\n  }\n\n  /// \\brief Remove an \\ref AuxData by name.\n  ///\n  /// This will invalidate any pointers that may have been held externally.\n  ///\n  /// \\return     \\c true on success, \\c false otherwise.\n  ///\n  /// Note that this function can be used for any AuxData regardless\n  /// of whether or not it has a registered schema.\n  bool removeAuxData(std::string Name) {\n    return this->AuxDatas.erase(Name) > 0;\n  }\n\n  /// \\brief An interface for accessing the serialized form of an AuxData\n  /// instance.\n  ///\n  /// The \\ref const_aux_data_iterator provides this value type for\n  /// the AuxData instances contained in this container. This provides\n  /// access to all AuxData present in a container regardless of\n  /// whether or not appropriate types have been registered.\n  ///\n  /// The content provided through this interface is only ever\n  /// populated at the point at which this container is\n  /// unserialized. Edits to AuxData after this point (or newly added\n  /// AuxData) will not be reflected through this interface.\n  struct AuxDataRaw {\n\n    /// \\brief The string name of the AuxData field.\n    const std::string& Key;\n\n    /// \\brief The raw bytes of the serialized form of the AuxData\n    const std::string& RawBytes;\n\n    /// \\brief The type of the AuxData as stored in protobuf.\n    ///\n    /// Note that this is not the AuxData's C++ type.\n    const std::string& ProtobufType;\n\n    AuxDataRaw(const std::string& K, const std::string& RB,\n               const std::string& PT)\n        : Key(K), RawBytes(RB), ProtobufType(PT) {}\n  };\n\nprivate:\n  struct AccessRawData {\n    auto operator()(const AuxDataSet::value_type& P) const {\n      return AuxDataRaw(P.first, P.second->rawData().RawBytes,\n                        P.second->rawData().ProtobufType);\n    }\n  };\n\npublic:\n  /// \\brief An iterator type for traversing the AuxData in this container.\n  ///\n  /// The value type for this iterator is AuxDataRaw. The iterator\n  /// provides access to the serialized form of all AuxData in this\n  /// container (regardless of whether or not the AuxData's type is\n  /// registered.) Note that the content is only valid with respect to\n  /// the most recent unserialization operation. Entries for new or\n  /// modified AuxData entities will contain empty or stale content.\n  using const_aux_data_iterator =\n      boost::transform_iterator<AccessRawData, AuxDataSet::const_iterator>;\n  using const_aux_data_range = boost::iterator_range<const_aux_data_iterator>;\n\n  /// \\brief Return a constant iterator to the first AuxData.\n  const_aux_data_iterator aux_data_begin() const {\n    return const_aux_data_iterator(AuxDatas.begin(), AccessRawData());\n  }\n\n  /// \\brief Return a constant iterator to the element following the last\n  /// AuxData.\n  const_aux_data_iterator aux_data_end() const {\n    return const_aux_data_iterator(AuxDatas.end(), AccessRawData());\n  }\n\n  /// \\brief Return a constant range of the auxiliary data (\\ref AuxData).\n  const_aux_data_range aux_data() const {\n    return boost::make_iterator_range(aux_data_begin(), aux_data_end());\n  }\n\n  /// \\brief Get the total number of \\ref AuxData objects in this IR.\n  ///\n  /// \\return     The total number of \\ref AuxData objects.\n  ///\n  size_t getAuxDataSize() const { return AuxDatas.size(); }\n\n  /// \\brief Check: Is the number of \\ref AuxData objects in this IR zero?\n  ///\n  /// \\return \\c true if this IR does not contain any \\ref AuxData, otherwise \\c\n  /// false\n  ///\n  bool getAuxDataEmpty() const { return AuxDatas.empty(); }\n\n  /// \\brief Clear all \\ref AuxData from the IR.\n  ///\n  /// \\return void\n  ///\n  void clearAuxData() { AuxDatas.clear(); }\n\n  /// @}\n  /// @cond INTERNAL\n\n  /// \\brief Serialize the aux data into a protobuf message.\n  ///\n  /// \\param[out] Message   Serialize into this message.\n  ///\n  /// \\return void\n  template <\n      class MessageType,\n      class = std::enable_if_t<message_has_aux_data_container_v<MessageType>>>\n  void toProtobuf(MessageType* Message) const {\n    containerToProtobuf(this->AuxDatas, Message->mutable_aux_data());\n  }\n\n  /// \\brief Load the aux data from a protobuf message.\n  ///\n  /// \\param Message  The protobuf message from which to deserialize.\n  ///\n  /// \\return void\n  template <\n      class MessageType,\n      class = std::enable_if_t<message_has_aux_data_container_v<MessageType>>>\n  void fromProtobuf(const MessageType& Message) {\n    this->AuxDatas.clear();\n    for (const auto& M : Message.aux_data()) {\n      std::unique_ptr<AuxData> Val;\n      std::string Key = M.first;\n\n      // See if the name for this AuxData is registered.\n      if (const auto* ADT = lookupAuxDataType(Key)) {\n        Val = ADT->fromProtobuf(M.second);\n      }\n\n      // If it wasn't registered or was registered with an incompatible\n      // type wrt the serialized object, unserialized as just the\n      // un-typed raw data.\n      if (!Val) {\n        Val = std::make_unique<AuxData>();\n        AuxData::fromProtobuf(*Val, M.second);\n      }\n      this->AuxDatas.insert(std::make_pair(Key, std::move(Val)));\n    }\n    /// @endcond\n  }\n\nprotected:\n  AuxDataContainer(Context& C, Kind knd);\n  AuxDataContainer(Context& C, Kind knd, const UUID& U);\n\nprivate:\n  AuxDataSet AuxDatas;\n\n  struct AuxDataType {\n    virtual ~AuxDataType() = default;\n    virtual std::unique_ptr<AuxData>\n    fromProtobuf(const proto::AuxData& Message) const = 0;\n    virtual std::size_t getApiTypeId() const = 0;\n  };\n\n  template <typename Schema> struct AuxDataTypeImpl : public AuxDataType {\n    std::unique_ptr<AuxData>\n    fromProtobuf(const proto::AuxData& Message) const override {\n      return AuxDataImpl<Schema>::fromProtobuf(Message);\n    }\n\n    std::size_t getApiTypeId() const override {\n      return AuxDataImpl<Schema>::staticGetApiTypeId();\n    }\n  };\n\n  static void registerAuxDataTypeInternal(const char* Name,\n                                          std::unique_ptr<AuxDataType> ADT);\n  static bool checkAuxDataRegistration(const char* Name, std::size_t Id);\n  static const AuxDataType* lookupAuxDataType(const std::string& Name);\n  friend struct AuxDataTypeMap; // Allows AuxDataTypeMap to use AuxDataType\n};\n} // namespace gtirb\n#endif // GTIRB_AUXDATACONTAINER_H\n"
  },
  {
    "path": "include/gtirb/AuxDataSchema.hpp",
    "content": "//===- AuxDataSchema.hpp ---------------------------------------------*-\n// C++-*-===//\n//\n//  Copyright (C) 2018-2019 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_AUXDATASCHEMA_HPP\n#define GTIRB_AUXDATASCHEMA_HPP\n\n#include <gtirb/Addr.hpp>\n#include <gtirb/Context.hpp> // UUID\n#include <gtirb/Offset.hpp>\n#include <cstdint>\n#include <map>\n#include <set>\n#include <string>\n\n/// \\file AuxDataSchema.hpp\n/// \\ingroup AUXDATA_GROUP\n/// \\brief  Type schema for sanctioned AuxData types\n/// \\see AUXDATA_GROUP\n\nnamespace gtirb {\nnamespace schema {\n\n/// \\brief Schema class for functionBlocks auxiliary data.\nstruct FunctionBlocks {\n  static constexpr const char* Name = \"functionBlocks\";\n  typedef std::map<gtirb::UUID, std::set<gtirb::UUID>> Type;\n};\n\n/// \\brief Schema class for functionEntries auxiliary data.\nstruct FunctionEntries {\n  static constexpr const char* Name = \"functionEntries\";\n  typedef std::map<gtirb::UUID, std::set<gtirb::UUID>> Type;\n};\n\n/// \\brief Schema class for functionNames auxiliary data.\nstruct FunctionNames {\n  static constexpr const char* Name = \"functionNames\";\n  typedef std::map<gtirb::UUID, gtirb::UUID> Type;\n};\n\n/// \\brief Schema class for types auxiliary data.\nstruct Types {\n  static constexpr const char* Name = \"types\";\n  typedef std::map<gtirb::UUID, std::string> Type;\n};\n\n/// \\brief Schema class for alignment auxiliary data.\nstruct Alignment {\n  static constexpr const char* Name = \"alignment\";\n  typedef std::map<gtirb::UUID, uint64_t> Type;\n};\n\n/// \\brief Schema class for comments auxiliary data.\nstruct Comments {\n  static constexpr const char* Name = \"comments\";\n  typedef std::map<gtirb::Offset, std::string> Type;\n};\n\n/// \\brief Schema class for symbolForwarding auxiliary data.\nstruct SymbolForwarding {\n  static constexpr const char* Name = \"symbolForwarding\";\n  typedef std::map<gtirb::UUID, gtirb::UUID> Type;\n};\n\n/// \\brief Schema class for padding auxiliary data.\nstruct Padding {\n  static constexpr const char* Name = \"padding\";\n  typedef std::map<gtirb::Offset, uint64_t> Type;\n};\n\n/// \\brief Schema class for ELF file's dynamic entry DT_INIT.\n/// It contains a CodeBlock's UUID.\nstruct ElfDynamicInit {\n  static constexpr const char* Name = \"elfDynamicInit\";\n  typedef gtirb::UUID Type;\n};\n\n/// \\brief Schema class for ELF file's dynamic entry DT_FINI.\n/// It contains a CodeBlock's UUID.\nstruct ElfDynamicFini {\n  static constexpr const char* Name = \"elfDynamicFini\";\n  typedef gtirb::UUID Type;\n};\n\n/// \\brief Schema class for ELF file's dynamic entry DT_SONAME.\n/// It contains a SONAME as string\nstruct ElfSoname {\n  static constexpr const char* Name = \"elfSoname\";\n  typedef std::string Type;\n};\n\n/// \\brief Schema class for stack executable flag specified by PT_GNU_STACK\n/// segment in ELF files.\nstruct ElfStackExec {\n  static constexpr const char* Name = \"elfStackExec\";\n  typedef bool Type;\n};\n\n/// \\brief Schema class for the size of the PT_GNU_STACK segment in ELF files,\n/// which may influence the runtime stack size in certain environments.\nstruct ElfStackSize {\n  static constexpr const char* Name = \"elfStackSize\";\n  typedef uint64_t Type;\n};\n\n} // namespace schema\n\nnamespace provisional_schema {\n\n/// \\brief Schema class for profile aux data.\nstruct Profile {\n  static constexpr const char* Name = \"profile\";\n  typedef std::map<gtirb::Offset, uint64_t> Type;\n};\n\n/// Version identifiers are 16 bit unsigned integers.\nusing SymbolVersionId = uint16_t;\n/// Map from version identifiers to version definitions. These correspond\n/// to ELFxx_Verdef entries in the ELF section .gnu.version_d.\n/// The values in the map are tuples containing the list of versions strings and\n/// the verdef flags. The verdef flag may be VER_FLG_BASE (0x1), which indicates\n/// that the given version definiton is the file itself, and must not be\n/// used for matching a symbol. The first element of the list is the version\n/// itself, the subsequent elements are predecessor versions.\nusing ElfSymVerDefs =\n    std::map<SymbolVersionId, std::tuple<std::vector<std::string>, uint16_t>>;\n/// Map from dynamic library names to the symbol versions that they need.\n/// For each library, we have a map from version identifiers to version strings.\nusing ElfSymVerNeeded =\n    std::map<std::string, std::map<SymbolVersionId, std::string>>;\n//// Map from gtirb::Symbol UUIDs to a tuple of symbol version identifier and\n/// hidden attribute.\nusing ElfSymbolVersionsEntries =\n    std::map<gtirb::UUID, std::tuple<SymbolVersionId, bool>>;\n\n/// \\brief Auxiliary data for ELF symbol versions.\n/// This includes the symbol version definitions, the symbol version\n/// requirements, and the mapping from symbols to symbol versions.\nstruct ElfSymbolVersions {\n  static constexpr const char* Name = \"elfSymbolVersions\";\n  typedef std::tuple<ElfSymVerDefs, ElfSymVerNeeded, ElfSymbolVersionsEntries>\n      Type;\n};\n\n} // namespace provisional_schema\n} // namespace gtirb\n\n#endif // GTIRB_AUXDATASCHEMA_HPP\n"
  },
  {
    "path": "include/gtirb/ByteInterval.hpp",
    "content": "//===- ByteInterval.hpp -----------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n\n#ifndef GTIRB_BYTE_INTERVAL_H\n#define GTIRB_BYTE_INTERVAL_H\n\n#include <gtirb/DecodeMode.hpp>\n#include <gtirb/Export.hpp>\n#include <gtirb/Node.hpp>\n#include <gtirb/Observer.hpp>\n#include <gtirb/SymbolicExpression.hpp>\n#include <gtirb/Utility.hpp>\n#include <array>\n#include <boost/endian/conversion.hpp>\n#include <boost/icl/interval_map.hpp>\n#include <boost/iterator/filter_iterator.hpp>\n#include <boost/iterator/indirect_iterator.hpp>\n#include <boost/iterator/iterator_categories.hpp>\n#include <boost/iterator/iterator_facade.hpp>\n#include <boost/iterator/iterator_traits.hpp>\n#include <boost/iterator/transform_iterator.hpp>\n#include <boost/multi_index/hashed_index.hpp>\n#include <boost/multi_index/identity.hpp>\n#include <boost/multi_index/key_extractors.hpp>\n#include <boost/multi_index/mem_fun.hpp>\n#include <boost/multi_index/ordered_index.hpp>\n#include <boost/multi_index_container.hpp>\n#include <boost/range/iterator_range.hpp>\n#include <cstdint>\n#include <functional>\n#include <map>\n#include <optional>\n#include <type_traits>\n#include <variant>\n#include <vector>\n\n/// \\file ByteInterval.hpp\n/// \\brief Class gtirb::ByteInterval.\n\nnamespace gtirb {\nnamespace proto {\nclass ByteInterval;\n} // namespace proto\n\nclass Section;   // Forward declared for the backpointer.\nclass CodeBlock; // Forward declared so Blocks can store CodeBlocks.\nclass DataBlock; // Forward declared so Blocks can store DataBlocks.\nclass ByteIntervalObserver;\n\ntemplate <class T> class ErrorOr;\n\n///\n/// \\brief Interface for notifying observers when a CodeBlock is modified.\n///\n\nclass GTIRB_EXPORT_API CodeBlockObserver {\npublic:\n  virtual ~CodeBlockObserver() = default;\n\n  /// \\brief Notify the parent when the CodeBlock changes size.\n  ///\n  /// Called after the CodeBlock updates its internal state.\n  ///\n  /// \\param B        the CodeBlock that changed.\n  /// \\param OldSize  the previous size of the CodeBlock.\n  /// \\param NewSize  the new size of the CodeBlock.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus sizeChange(CodeBlock* B, uint64_t OldSize,\n                                  uint64_t NewSize) = 0;\n  /// \\brief Notify the parent when the CodeBlock's decode mode changes.\n  ///\n  /// Called after the CodeBlock updates its internal state.\n  virtual ChangeStatus decodeModeChange(CodeBlock* B, DecodeMode OldMode,\n                                        DecodeMode NewMode) = 0;\n};\n\n///\n/// \\brief Interface for notifying observers when a DataBlock is modified.\n///\n\nclass GTIRB_EXPORT_API DataBlockObserver {\npublic:\n  virtual ~DataBlockObserver() = default;\n\n  /// \\brief Notify the parent when the DataBlock changes size.\n  ///\n  /// Called after the DataBlock updates its internal state.\n  ///\n  /// \\param B        the DataBlock that changed.\n  /// \\param OldSize  the previous size of the DataBlock.\n  /// \\param NewSize  the new size of the DataBlock.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus sizeChange(DataBlock* B, uint64_t OldSize,\n                                  uint64_t NewSize) = 0;\n};\n\n/// \\class ByteInterval\n///\n/// \\brief A contiguous region of bytes in a binary.\n///\n/// A ByteInterval defines a relative ordering for a group of \\ref Block\n/// objects, optionally at a fixed address in memory. It also stores the bytes\n/// associated with these blocks.\n///\n/// If two blocks are in two different ByteIntervals, then it should be\n/// considered safe (that is, preserving of program semantics) to move one block\n/// relative to the other in memory. If two blocks are in the same ByteInterval,\n/// then it should be considered unknown if moving the two blocks relative to\n/// one another in memory is a safe operation.\nclass GTIRB_EXPORT_API ByteInterval : public Node {\n  /// \\class Block\n  ///\n  /// \\brief A node (either a \\ref CodeBlock or \\ref DataBlock), alongside an\n  /// offset, held within this interval.\n  struct Block {\n    uint64_t Offset;\n    gtirb::Node* Node;\n\n    Block(uint64_t Off, gtirb::Node* N) : Offset(Off), Node(N) {}\n\n    /// \\brief Get the offset from the beginning of this block's \\ref\n    /// ByteInterval.\n    uint64_t getOffset() const { return Offset; }\n\n    /// \\brief Get the \\ref Node, either a \\ref CodeBlock or \\ref DataBlock, in\n    /// the \\ref ByteInterval.\n    ///\n    /// This function returns a nonconst pointer despite being const\n    /// because it's valid to mutate the nodes, but not valid to mutate the\n    /// block-offset pairs in the BlockSet.\n    gtirb::Node* getNode() const { return Node; }\n  };\n\n  /// \\class BlockKindEquals\n  ///\n  /// \\brief A predicate object to discern one type of block.\n  ///\n  /// This predicate does not interact with the subclassing system;\n  /// BlockKindEquals<Node::Kind::CfgNode> will not identify any blocks as CFG\n  /// nodes, for example.\n  template <Node::Kind K> struct BlockKindEquals {\n    bool operator()(const Block& B) const {\n      return B.getNode()->getKind() == K;\n    }\n  };\n\n  /// \\class BlockToNode\n  ///\n  /// \\brief A function for a transform iterator to turn blocks into nodes.\n  template <typename NodeType> struct BlockToNode {\n    BlockToNode() {}\n\n    /// \\brief Non-const to const conversion constructor.\n    BlockToNode(const BlockToNode<std::remove_const_t<NodeType>>&) {}\n\n    BlockToNode& operator=(const BlockToNode<std::remove_const_t<NodeType>>&) {\n      return *this;\n    }\n\n    NodeType& operator()(const Block& B) const {\n      // We avoid the call to cast() here because we use this function after\n      // BlockKindEquals, which confirms the type of the Node for us\n      // (and more importantly, we avoid having to include Code/DataBlock).\n      return *reinterpret_cast<NodeType*>(B.Node);\n    }\n\n    NodeType& operator()(const Block* B) const { return *B->Node; }\n  };\n\n  /// \\class BlockOffsetLess\n  ///\n  /// \\brief Provides a comparison for Block using the common functionality\n  ///        in Utility.hpp by adapting from the internal Block type a pair of\n  ///        offset and node.\n  struct GTIRB_EXPORT_API BlockOffsetLess {\n    bool operator()(const Block* B1, const Block* B2) const {\n      return BlockOffsetPairLess()({B1->Offset, B1->Node},\n                                   {B2->Offset, B2->Node});\n    }\n    bool operator()(const Block& B1, const Block& B2) const {\n      return operator()(&B1, &B2);\n    }\n  };\n\n  /// \\class OffsetCmp\n  ///\n  /// \\brief A comparison object that allows searching in the block set by\n  ///        offset.\n  struct GTIRB_EXPORT_API OffsetCmp {\n    bool operator()(uint64_t Offset, const Block& B) const {\n      return Offset < B.Offset;\n    }\n    bool operator()(const Block& B, uint64_t Offset) const {\n      return B.Offset < Offset;\n    }\n  };\n\n  struct by_offset {};\n  struct by_pointer {};\n  using BlockSet = boost::multi_index::multi_index_container<\n      Block, boost::multi_index::indexed_by<\n                 boost::multi_index::ordered_non_unique<\n                     boost::multi_index::tag<by_offset>,\n                     boost::multi_index::identity<Block>, BlockOffsetLess>,\n                 boost::multi_index::hashed_unique<\n                     boost::multi_index::tag<by_pointer>,\n                     boost::multi_index::const_mem_fun<Block, Node*,\n                                                       &Block::getNode>>>>;\n  using BlockIntMap =\n      boost::icl::interval_map<uint64_t,\n                               std::multiset<const Block*, BlockOffsetLess>>;\n  using SymbolicExpressionMap = std::map<uint64_t, SymbolicExpression>;\n\n  /// \\brief Get the \\ref Block that corresponds to a \\ref Node.\n  const Block& nodeToBlock(const Node* N) const {\n    auto& Index = Blocks.get<by_pointer>();\n    auto It = Index.find(const_cast<Node*>(N));\n    assert(It != Index.end() &&\n           \"ByteInterval::nodeToBlock called with block not in interval\");\n    return *It;\n  }\n\n  class CodeBlockObserverImpl;\n  class DataBlockObserverImpl;\n\n  /// \\brief Updates the interval map for a node by removing and re-inserting\n  ///        the interval. Must be called when either the block's offset or\n  ///        size changes.\n  /// \\param N         The Block that needs updating\n  /// \\param OldSize   The previous size of the block. If specified this will\n  ///                  cause the entry to be removed from the map.\n  /// \\param NewSize   The new size of the block. If specified this will cause\n  ///                  the entry to be added to the map.\n  void updateIntervalMap(Node* N, std::optional<uint64_t> OldSize,\n                         std::optional<uint64_t> NewSize);\n  /// \\brief Updates the block's sorted index. Must be called whenever a\n  ///        block's sort order would change.\n  void updateBlockSortOrder(Node* N);\n\n  ChangeStatus sizeChange(Node* N, uint64_t OldSize, uint64_t NewSize);\n  ChangeStatus decodeModeChange(CodeBlock* B, DecodeMode OldMode,\n                                DecodeMode NewMode);\n\npublic:\n  /// \\brief Create an unitialized ByteInterval object.\n  /// \\param C        The Context in which this ByteInterval will be held.\n  /// \\return         The newly created ByteInterval.\n  static ByteInterval* Create(Context& C) { return C.Create<ByteInterval>(C); }\n\n  /// \\brief Create a ByteInterval object.\n  ///\n  /// \\param C         The \\ref Context in which this interval will be held.\n  /// \\param Size      The size of this interval in bytes.\n  /// \\param InitSize  The number of bytes with initialized values. Defaults\n  ///                  to the value of Size.\n  /// \\return          The newly created ByteInterval.\n  static ByteInterval* Create(Context& C, uint64_t Size,\n                              std::optional<uint64_t> InitSize = std::nullopt) {\n    return C.Create<ByteInterval>(C, std::nullopt, Size,\n                                  InitSize.value_or(Size));\n  }\n\n  /// \\brief Create a ByteInterval object.\n  ///\n  /// \\param C         The \\ref Context in which this interval will be held.\n  /// \\param Address   An (optional) fixed address for this interval.\n  /// \\param Size      The size of this interval in bytes.\n  /// \\param InitSize  The number of bytes with initialized values. Defaults\n  ///                  to the value of Size.\n  /// \\return          The newly created ByteInterval.\n  static ByteInterval* Create(Context& C, std::optional<Addr> Address,\n                              uint64_t Size = 0,\n                              std::optional<uint64_t> InitSize = std::nullopt) {\n    return C.Create<ByteInterval>(C, Address, Size, InitSize.value_or(Size));\n  }\n\n  /// \\brief Create a ByteInterval object.\n  ///\n  /// \\tparam InputIterator An input iterator yielding bytes.\n  /// \\param C          The \\ref Context in which this interval will be held.\n  /// \\param BytesBegin The start of the range to copy to the byte vector.\n  /// \\param BytesEnd   The end of the range to copy to the byte vector.\n  /// \\param Size       The size of this interval in bytes. Defaults to the\n  ///                   size of the range of bytes. If specified, either\n  ///                   trucates the range of bytes given or pads it at the end\n  ///                   with zeroes.\n  /// \\param InitSize   The number of bytes with initialized values. Defaults to\n  ///                   the size of the range of bytes. If specified, does NOT\n  ///                   zero out values from the range past this number.\n  /// \\return           The newly created ByteInterval.\n  template <typename InputIterator>\n  static ByteInterval* Create(Context& C, InputIterator Begin,\n                              InputIterator End,\n                              std::optional<uint64_t> Size = std::nullopt,\n                              std::optional<uint64_t> InitSize = std::nullopt) {\n    return C.Create<ByteInterval>(\n        C, std::nullopt, Size ? *Size : std::distance(Begin, End),\n        InitSize ? *InitSize : std::distance(Begin, End), Begin, End);\n  }\n\n  /// \\brief Create a ByteInterval object.\n  ///\n  /// \\tparam InputIterator An input iterator yielding bytes.\n  /// \\param C          The \\ref Context in which this interval will be held.\n  /// \\param Address    An (optional) fixed address for this interval.\n  /// \\param BytesBegin The start of the range to copy to the byte vector.\n  /// \\param BytesEnd   The end of the range to copy to the byte vector.\n  /// \\param Size       The size of this interval in bytes. Defaults to the\n  ///                   size of the range of bytes. If specified, either\n  ///                   trucates the range of bytes given or pads it at the end\n  ///                   with zeroes.\n  /// \\param InitSize   The number of bytes with initialized values. Defaults to\n  ///                   the size of the range of bytes. If specified, does NOT\n  ///                   zero out values from the range past this number.\n  /// \\return           The newly created ByteInterval.\n  template <typename InputIterator>\n  static ByteInterval* Create(Context& C, std::optional<Addr> Address,\n                              InputIterator Begin, InputIterator End,\n                              std::optional<uint64_t> Size = std::nullopt,\n                              std::optional<uint64_t> InitSize = std::nullopt) {\n    return C.Create<ByteInterval>(\n        C, Address, Size ? *Size : std::distance(Begin, End),\n        InitSize ? *InitSize : std::distance(Begin, End), Begin, End);\n  }\n\n  /// \\brief Get the \\ref Section this byte interval belongs to.\n  Section* getSection() { return Parent; }\n  /// \\brief Get the \\ref Section this byte interval belongs to.\n  const Section* getSection() const { return Parent; }\n\n  /// \\brief Get the fixed address of this interval, if present.\n  ///\n  /// If this field is present, it may indicate the original address at which\n  /// this interval was located at in memory, or it may indicate that this\n  /// block's address is fixed and must not be changed. If this field is not\n  /// present, it indicates that the interval is free to be moved around in\n  /// memory while preserving program semantics.\n  std::optional<Addr> getAddress() const { return Address; }\n\n  /// \\brief Iterator over \\ref Block objects.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n\n  using block_iterator =\n      boost::transform_iterator<BlockToNode<Node>,\n                                BlockSet::index<by_offset>::type::iterator>;\n  /// \\brief Range of \\ref Block objects.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using block_range = boost::iterator_range<block_iterator>;\n  /// \\brief Sub-range of blocks overlapping an address or range of addreses.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using block_subrange = boost::iterator_range<boost::transform_iterator<\n      BlockToNode<Node>, BlockIntMap::codomain_type::iterator>>;\n  /// \\brief Const iterator over \\ref Block objects.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_block_iterator = boost::transform_iterator<\n      BlockToNode<const Node>,\n      BlockSet::index<by_offset>::type::const_iterator>;\n  /// \\brief Const range of \\ref Block objects.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_block_range = boost::iterator_range<const_block_iterator>;\n  /// \\brief Const sub-range of blocks overlapping an address or range of\n  /// addreses.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_block_subrange = boost::iterator_range<boost::transform_iterator<\n      BlockToNode<const Node>, BlockIntMap::codomain_type::const_iterator>>;\n\n  /// \\brief Return an iterator to the first \\ref Block.\n  block_iterator blocks_begin() { return block_iterator(Blocks.begin()); }\n  /// \\brief Return a const iterator to the first \\ref Block.\n  const_block_iterator blocks_begin() const {\n    return const_block_iterator(Blocks.begin());\n  }\n  /// \\brief Return an iterator to the element following the last \\ref Block.\n  block_iterator blocks_end() { return block_iterator(Blocks.end()); }\n  /// \\brief Return a const iterator to the element following the last\n  /// \\ref Block.\n  const_block_iterator blocks_end() const {\n    return const_block_iterator(Blocks.end());\n  }\n  /// \\brief Return a range of the \\ref Block objects in this interval.\n  block_range blocks() {\n    return boost::make_iterator_range(blocks_begin(), blocks_end());\n  }\n  /// \\brief Return a const range of the \\ref Block objects in this interval.\n  const_block_range blocks() const {\n    return boost::make_iterator_range(blocks_begin(), blocks_end());\n  }\n\n  /// \\brief Find all the blocks that have a byte at the specified offset.\n  ///\n  /// \\param Off The offset to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock or\n  /// \\ref CodeBlock objects, that contain the offset \\p Off.\n  block_subrange findBlocksOnOffset(uint64_t Off) {\n    if (auto It = BlockOffsets.find(Off); It != BlockOffsets.end()) {\n      return block_subrange(It->second.begin(), It->second.end());\n    }\n    return {};\n  }\n\n  /// \\brief Find all the blocks that have a byte at the specified offset.\n  ///\n  /// \\param Off The offset to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock or\n  /// \\ref CodeBlock objects, that contain the offset \\p Off.\n  const_block_subrange findBlocksOnOffset(uint64_t Off) const {\n    if (auto It = BlockOffsets.find(Off); It != BlockOffsets.end()) {\n      return const_block_subrange(It->second.begin(), It->second.end());\n    }\n    return {};\n  }\n\n  /// \\brief Find all the blocks that have bytes that lie within the address\n  /// specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that intersect the address \\p A.\n  block_subrange findBlocksOn(Addr A) {\n    if (Address) {\n      return findBlocksOnOffset(A - *Address);\n    }\n    return {};\n  }\n\n  /// \\brief Find all the blocks that have bytes that lie within the address\n  /// specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that intersect the address \\p A.\n  const_block_subrange findBlocksOn(Addr A) const {\n    if (Address) {\n      return findBlocksOnOffset(A - *Address);\n    }\n    return {};\n  }\n\n  /// \\brief Find all the blocks that start at an offset.\n  ///\n  /// \\param Off The offset to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are at the offset \\p Off.\n  block_range findBlocksAtOffset(uint64_t Off) {\n    auto Pair = Blocks.get<by_offset>().equal_range(Off, OffsetCmp());\n    return boost::make_iterator_range(block_iterator(Pair.first),\n                                      block_iterator(Pair.second));\n  }\n\n  /// \\brief Find all the blocks that start between a range of offsets.\n  ///\n  /// \\param Low  The low offset, inclusive.\n  /// \\param High The high offset, exclusive.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are between the offsets.\n  block_range findBlocksAtOffset(uint64_t Low, uint64_t High) {\n    auto& Index = Blocks.get<by_offset>();\n    auto LowIt = Index.lower_bound(Low, OffsetCmp());\n    auto HighIt = Index.lower_bound(std::max(Low, High), OffsetCmp());\n    return boost::make_iterator_range(block_iterator(LowIt),\n                                      block_iterator(HighIt));\n  }\n\n  /// \\brief Find all the blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are at the address \\p A.\n  block_range findBlocksAt(Addr A) {\n    if (!Address || A < *Address) {\n      // Return an empty range without default-constructing the iterators.\n      return findBlocksAtOffset(0, 0);\n    }\n    return findBlocksAtOffset(A - *Address);\n  }\n\n  /// \\brief Find all the blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are between the addresses.\n  block_range findBlocksAt(Addr Low, Addr High) {\n    if (!Address) {\n      // Return an empty range without default-constructing the iterators.\n      return findBlocksAtOffset(0, 0);\n    }\n    return findBlocksAtOffset(Low - std::min(*Address, Low),\n                              High - std::min(*Address, High));\n  }\n\n  /// \\brief Find all the blocks that start at an offset.\n  ///\n  /// \\param Off The offset to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are at the offset \\p Off.\n  const_block_range findBlocksAtOffset(uint64_t Off) const {\n    auto Pair = Blocks.get<by_offset>().equal_range(Off, OffsetCmp());\n    return boost::make_iterator_range(const_block_iterator(Pair.first),\n                                      const_block_iterator(Pair.second));\n  }\n\n  /// \\brief Find all the blocks that start between a range of offsets.\n  ///\n  /// \\param Low  The low offset, inclusive.\n  /// \\param High The high offset, exclusive.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are between the offsets.\n  const_block_range findBlocksAtOffset(uint64_t Low, uint64_t High) const {\n    auto& Index = Blocks.get<by_offset>();\n    auto LowIt = Index.lower_bound(Low, OffsetCmp());\n    auto HighIt = Index.lower_bound(std::max(Low, High), OffsetCmp());\n    return boost::make_iterator_range(const_block_iterator(LowIt),\n                                      const_block_iterator(HighIt));\n  }\n\n  /// \\brief Find all the blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are at the address \\p A.\n  const_block_range findBlocksAt(Addr A) const {\n    if (!Address || A < *Address) {\n      // Return an empty range without default-constructing the iterators.\n      return findBlocksAtOffset(0, 0);\n    }\n    return findBlocksAtOffset(A - *Address);\n  }\n\n  /// \\brief Find all the blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are between the addresses.\n  const_block_range findBlocksAt(Addr Low, Addr High) const {\n    if (!Address) {\n      // Return an empty range without default-constructing the iterators.\n      return findBlocksAtOffset(0, 0);\n    }\n    return findBlocksAtOffset(Low - std::min(*Address, Low),\n                              High - std::min(*Address, High));\n  }\n\n  /// \\brief Iterator over \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using code_block_iterator = boost::transform_iterator<\n      BlockToNode<CodeBlock>,\n      boost::filter_iterator<BlockKindEquals<Node::Kind::CodeBlock>,\n                             BlockSet::index<by_offset>::type::iterator>>;\n  /// \\brief Range of \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using code_block_range = boost::iterator_range<code_block_iterator>;\n  /// \\brief Sub-range of code blocks overlapping an address or range of\n  /// addreses.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using code_block_subrange = boost::iterator_range<boost::transform_iterator<\n      BlockToNode<CodeBlock>,\n      boost::filter_iterator<\n          BlockKindEquals<Node::Kind::CodeBlock>,\n          boost::indirect_iterator<BlockIntMap::codomain_type::iterator>>>>;\n  /// \\brief Const iterator over \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_code_block_iterator = boost::transform_iterator<\n      BlockToNode<const CodeBlock>,\n      boost::filter_iterator<BlockKindEquals<Node::Kind::CodeBlock>,\n                             BlockSet::index<by_offset>::type::const_iterator>>;\n  /// \\brief Const range of \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_code_block_range =\n      boost::iterator_range<const_code_block_iterator>;\n  /// \\brief Const sub-range of code blocks overlapping an address or range of\n  /// addreses.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_code_block_subrange =\n      boost::iterator_range<boost::transform_iterator<\n          BlockToNode<const CodeBlock>,\n          boost::filter_iterator<\n              BlockKindEquals<Node::Kind::CodeBlock>,\n              boost::indirect_iterator<\n                  BlockIntMap::codomain_type::const_iterator>>>>;\n\n  /// \\brief Return an iterator to the first \\ref CodeBlock.\n  code_block_iterator code_blocks_begin() {\n    return code_block_iterator(\n        code_block_iterator::base_type(Blocks.begin(), Blocks.end()));\n  }\n  /// \\brief Return a const iterator to the first \\ref CodeBlock.\n  const_code_block_iterator code_blocks_begin() const {\n    return const_code_block_iterator(\n        const_code_block_iterator::base_type(Blocks.begin(), Blocks.end()));\n  }\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// CodeBlock.\n  code_block_iterator code_blocks_end() {\n    return code_block_iterator(\n        code_block_iterator::base_type(Blocks.end(), Blocks.end()));\n  }\n  /// \\brief Return a const iterator to the element following the last \\ref\n  /// CodeBlock.\n  const_code_block_iterator code_blocks_end() const {\n    return const_code_block_iterator(\n        const_code_block_iterator::base_type(Blocks.end(), Blocks.end()));\n  }\n  /// \\brief Return a range of the \\ref CodeBlock objects in this interval.\n  code_block_range code_blocks() {\n    return boost::make_iterator_range(code_blocks_begin(), code_blocks_end());\n  }\n  /// \\brief Return a const range of the \\ref CodeBlock objects in this\n  /// interval.\n  const_code_block_range code_blocks() const {\n    return boost::make_iterator_range(code_blocks_begin(), code_blocks_end());\n  }\n\n  /// \\brief Find all the code blocks that have a byte at the specified offset.\n  ///\n  /// \\param Off The offset to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects, that contain the offset \\p Off.\n  code_block_subrange findCodeBlocksOnOffset(uint64_t Off) {\n    if (auto It = BlockOffsets.find(Off); It != BlockOffsets.end()) {\n      auto End = boost::make_indirect_iterator(It->second.end());\n      return code_block_subrange(\n          code_block_subrange::iterator::base_type(\n              boost::make_indirect_iterator(It->second.begin()), End),\n          code_block_subrange::iterator::base_type(End, End));\n    }\n    return {};\n  }\n\n  /// \\brief Find all the code blocks that have a byte at the specified offset.\n  ///\n  /// \\param Off The offset to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects, that contain the addres \\p Off.\n  const_code_block_subrange findCodeBlocksOnOffset(uint64_t Off) const {\n    if (auto It = BlockOffsets.find(Off); It != BlockOffsets.end()) {\n      auto End = boost::make_indirect_iterator(It->second.end());\n      return const_code_block_subrange(\n          const_code_block_subrange::iterator::base_type(\n              boost::make_indirect_iterator(It->second.begin()), End),\n          const_code_block_subrange::iterator::base_type(End, End));\n    }\n    return {};\n  }\n\n  /// \\brief Find all the code blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that intersect the address \\p A.\n  code_block_subrange findCodeBlocksOn(Addr A) {\n    if (Address) {\n      return findCodeBlocksOnOffset(A - *Address);\n    }\n    return {};\n  }\n\n  /// \\brief Find all the code blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that intersect the address \\p A.\n  const_code_block_subrange findCodeBlocksOn(Addr A) const {\n    if (Address) {\n      return findCodeBlocksOnOffset(A - *Address);\n    }\n    return {};\n  }\n\n  /// \\brief Find all the code blocks that start at an offset.\n  ///\n  /// \\param Off The offset to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are at the offset \\p Off.\n  code_block_range findCodeBlocksAtOffset(uint64_t Off) {\n    auto Pair = Blocks.get<by_offset>().equal_range(Off, OffsetCmp());\n    return boost::make_iterator_range(\n        code_block_iterator(\n            code_block_iterator::base_type(Pair.first, Pair.second)),\n        code_block_iterator(\n            code_block_iterator::base_type(Pair.second, Pair.second)));\n  }\n\n  /// \\brief Find all the code blocks that start between a range of offsets.\n  ///\n  /// \\param Low  The low offset, inclusive.\n  /// \\param High The high offset, exclusive.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are between the offsets.\n  code_block_range findCodeBlocksAtOffset(uint64_t Low, uint64_t High) {\n    auto& Index = Blocks.get<by_offset>();\n    auto LowIt = Index.lower_bound(Low, OffsetCmp());\n    auto HighIt = Index.lower_bound(std::max(Low, High), OffsetCmp());\n    return boost::make_iterator_range(\n        code_block_iterator(code_block_iterator::base_type(LowIt, HighIt)),\n        code_block_iterator(code_block_iterator::base_type(HighIt, HighIt)));\n  }\n\n  /// \\brief Find all the code blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are at the address \\p A.\n  code_block_range findCodeBlocksAt(Addr A) {\n    if (!Address || A < *Address) {\n      // Return an empty range without default-constructing the iterators.\n      return findCodeBlocksAtOffset(0, 0);\n    }\n    return findCodeBlocksAtOffset(A - *Address);\n  }\n\n  /// \\brief Find all the code blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are between the addresses.\n  code_block_range findCodeBlocksAt(Addr Low, Addr High) {\n    if (!Address) {\n      // Return an empty range without default-constructing the iterators.\n      return findCodeBlocksAtOffset(0, 0);\n    }\n    return findCodeBlocksAtOffset(Low - std::min(*Address, Low),\n                                  High - std::min(*Address, High));\n  }\n\n  /// \\brief Find all the code blocks that start at an offset.\n  ///\n  /// \\param Off The offset to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are at the offset \\p Off.\n  const_code_block_range findCodeBlocksAtOffset(uint64_t Off) const {\n    auto Pair = Blocks.get<by_offset>().equal_range(Off, OffsetCmp());\n    return boost::make_iterator_range(\n        const_code_block_iterator(\n            const_code_block_iterator::base_type(Pair.first, Pair.second)),\n        const_code_block_iterator(\n            const_code_block_iterator::base_type(Pair.second, Pair.second)));\n  }\n\n  /// \\brief Find all the code blocks that start between a range of offsets.\n  ///\n  /// \\param Low  The low offset, inclusive.\n  /// \\param High The high offset, exclusive.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are between the offsets.\n  const_code_block_range findCodeBlocksAtOffset(uint64_t Low,\n                                                uint64_t High) const {\n    auto& Index = Blocks.get<by_offset>();\n    auto LowIt = Index.lower_bound(Low, OffsetCmp());\n    auto HighIt = Index.lower_bound(std::max(Low, High), OffsetCmp());\n    return boost::make_iterator_range(\n        const_code_block_iterator(\n            const_code_block_iterator::base_type(LowIt, HighIt)),\n        const_code_block_iterator(\n            const_code_block_iterator::base_type(HighIt, HighIt)));\n  }\n\n  /// \\brief Find all the code blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are at the address \\p A.\n  const_code_block_range findCodeBlocksAt(Addr A) const {\n    if (!Address || A < *Address) {\n      // Return an empty range without default-constructing the iterators.\n      return findCodeBlocksAtOffset(0, 0);\n    }\n    return findCodeBlocksAtOffset(A - *Address);\n  }\n\n  /// \\brief Find all the code blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are between the addresses.\n  const_code_block_range findCodeBlocksAt(Addr Low, Addr High) const {\n    if (!Address) {\n      // Return an empty range without default-constructing the iterators.\n      return findCodeBlocksAtOffset(0, 0);\n    }\n    return findCodeBlocksAtOffset(Low - std::min(*Address, Low),\n                                  High - std::min(*Address, High));\n  }\n\n  /// \\brief Iterator over \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using data_block_iterator = boost::transform_iterator<\n      BlockToNode<DataBlock>,\n      boost::filter_iterator<BlockKindEquals<Node::Kind::DataBlock>,\n                             BlockSet::index<by_offset>::type::iterator>>;\n  /// \\brief Range of \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using data_block_range = boost::iterator_range<data_block_iterator>;\n  /// \\brief Sub-range of data blocks overlapping an address or range of\n  /// addreses.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using data_block_subrange = boost::iterator_range<boost::transform_iterator<\n      BlockToNode<DataBlock>,\n      boost::filter_iterator<\n          BlockKindEquals<Node::Kind::DataBlock>,\n          boost::indirect_iterator<BlockIntMap::codomain_type::iterator>>>>;\n  /// \\brief Const iterator over \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_data_block_iterator = boost::transform_iterator<\n      BlockToNode<const DataBlock>,\n      boost::filter_iterator<BlockKindEquals<Node::Kind::DataBlock>,\n                             BlockSet::index<by_offset>::type::const_iterator>>;\n  /// \\brief Const range of \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_data_block_range =\n      boost::iterator_range<const_data_block_iterator>;\n  /// \\brief Const sub-range of data blocks overlapping an address or range of\n  /// addreses.\n  ///\n  /// Blocks are yielded in offset order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_data_block_subrange =\n      boost::iterator_range<boost::transform_iterator<\n          BlockToNode<const DataBlock>,\n          boost::filter_iterator<\n              BlockKindEquals<Node::Kind::DataBlock>,\n              boost::indirect_iterator<\n                  BlockIntMap::codomain_type::const_iterator>>>>;\n\n  /// \\brief Return an iterator to the first \\ref DataBlock.\n  data_block_iterator data_blocks_begin() {\n    return data_block_iterator(\n        data_block_iterator::base_type(Blocks.begin(), Blocks.end()));\n  }\n  /// \\brief Return a const iterator to the first \\ref DataBlock.\n  const_data_block_iterator data_blocks_begin() const {\n    return const_data_block_iterator(\n        const_data_block_iterator::base_type(Blocks.begin(), Blocks.end()));\n  }\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// DataBlock.\n  data_block_iterator data_blocks_end() {\n    return data_block_iterator(\n        data_block_iterator::base_type(Blocks.end(), Blocks.end()));\n  }\n  /// \\brief Return a const iterator to the element following the last \\ref\n  /// DataBlock.\n  const_data_block_iterator data_blocks_end() const {\n    return const_data_block_iterator(\n        const_data_block_iterator::base_type(Blocks.end(), Blocks.end()));\n  }\n  /// \\brief Return a range of the \\ref DataBlock objects in this interval.\n  data_block_range data_blocks() {\n    return boost::make_iterator_range(data_blocks_begin(), data_blocks_end());\n  }\n  /// \\brief Return a const range of the \\ref DataBlock objects in this\n  /// interval.\n  const_data_block_range data_blocks() const {\n    return boost::make_iterator_range(data_blocks_begin(), data_blocks_end());\n  }\n\n  /// \\brief Find all the data blocks that have a byte at the specified offset.\n  ///\n  /// \\param Off The offset to look up.\n  ///\n  /// \\return A range of \\ref DataBlock objects, that contain the offset \\p Off.\n  data_block_subrange findDataBlocksOnOffset(uint64_t Off) {\n    if (auto It = BlockOffsets.find(Off); It != BlockOffsets.end()) {\n      auto End = boost::make_indirect_iterator(It->second.end());\n      return data_block_subrange(\n          data_block_subrange::iterator::base_type(\n              boost::make_indirect_iterator(It->second.begin()), End),\n          data_block_subrange::iterator::base_type(End, End));\n    }\n    return {};\n  }\n\n  /// \\brief Find all the data blocks that have a byte at the specified offset.\n  ///\n  /// \\param Off The offset to look up.\n  ///\n  /// \\return A range of \\ref DataBlock objects, that contain the addres \\p Off.\n  const_data_block_subrange findDataBlocksOnOffset(uint64_t Off) const {\n    if (auto It = BlockOffsets.find(Off); It != BlockOffsets.end()) {\n      auto End = boost::make_indirect_iterator(It->second.end());\n      return const_data_block_subrange(\n          const_data_block_subrange::iterator::base_type(\n              boost::make_indirect_iterator(It->second.begin()), End),\n          const_data_block_subrange::iterator::base_type(End, End));\n    }\n    return {};\n  }\n\n  /// \\brief Find all the data blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataBlock objects that intersect the address \\p A.\n  data_block_subrange findDataBlocksOn(Addr A) {\n    if (Address) {\n      return findDataBlocksOnOffset(A - *Address);\n    }\n    return {};\n  }\n\n  /// \\brief Find all the data blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataBlock objects that intersect the address \\p A.\n  const_data_block_subrange findDataBlocksOn(Addr A) const {\n    if (Address) {\n      return findDataBlocksOnOffset(A - *Address);\n    }\n    return {};\n  }\n\n  /// \\brief Find all the data blocks that start at an offset.\n  ///\n  /// \\param Off The offset to look up.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are at the offset \\p Off.\n  data_block_range findDataBlocksAtOffset(uint64_t Off) {\n    auto Pair = Blocks.get<by_offset>().equal_range(Off, OffsetCmp());\n    return boost::make_iterator_range(\n        data_block_iterator(\n            data_block_iterator::base_type(Pair.first, Pair.second)),\n        data_block_iterator(\n            data_block_iterator::base_type(Pair.second, Pair.second)));\n  }\n\n  /// \\brief Find all the data blocks that start between a range of offsets.\n  ///\n  /// \\param Low  The low offset, inclusive.\n  /// \\param High The high offset, exclusive.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are between the offsets.\n  data_block_range findDataBlocksAtOffset(uint64_t Low, uint64_t High) {\n    auto& Index = Blocks.get<by_offset>();\n    auto LowIt = Index.lower_bound(Low, OffsetCmp());\n    auto HighIt = Index.lower_bound(std::max(Low, High), OffsetCmp());\n    return boost::make_iterator_range(\n        data_block_iterator(data_block_iterator::base_type(LowIt, HighIt)),\n        data_block_iterator(data_block_iterator::base_type(HighIt, HighIt)));\n  }\n\n  /// \\brief Find all the data blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are at the address \\p A.\n  data_block_range findDataBlocksAt(Addr A) {\n    if (!Address || A < *Address) {\n      // Return an empty range without default-constructing the iterators.\n      return findDataBlocksAtOffset(0, 0);\n    }\n    return findDataBlocksAtOffset(A - *Address);\n  }\n\n  /// \\brief Find all the data blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are between the addresses.\n  data_block_range findDataBlocksAt(Addr Low, Addr High) {\n    if (!Address) {\n      // Return an empty range without default-constructing the iterators.\n      return findDataBlocksAtOffset(0, 0);\n    }\n    return findDataBlocksAtOffset(Low - std::min(*Address, Low),\n                                  High - std::min(*Address, High));\n  }\n\n  /// \\brief Find all the data blocks that start at an offset.\n  ///\n  /// \\param Off The offset to look up.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are at the offset \\p Off.\n  const_data_block_range findDataBlocksAtOffset(uint64_t Off) const {\n    auto Pair = Blocks.get<by_offset>().equal_range(Off, OffsetCmp());\n    return boost::make_iterator_range(\n        const_data_block_iterator(\n            const_data_block_iterator::base_type(Pair.first, Pair.second)),\n        const_data_block_iterator(\n            const_data_block_iterator::base_type(Pair.second, Pair.second)));\n  }\n\n  /// \\brief Find all the data blocks that start between a range of offsets.\n  ///\n  /// \\param Low  The low offset, inclusive.\n  /// \\param High The high offset, exclusive.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are between the offsets.\n  const_data_block_range findDataBlocksAtOffset(uint64_t Low,\n                                                uint64_t High) const {\n    auto& Index = Blocks.get<by_offset>();\n    auto LowIt = Index.lower_bound(Low, OffsetCmp());\n    auto HighIt = Index.lower_bound(std::max(Low, High), OffsetCmp());\n    return boost::make_iterator_range(\n        const_data_block_iterator(\n            const_data_block_iterator::base_type(LowIt, HighIt)),\n        const_data_block_iterator(\n            const_data_block_iterator::base_type(HighIt, HighIt)));\n  }\n\n  /// \\brief Find all the data blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are at the address \\p A.\n  const_data_block_range findDataBlocksAt(Addr A) const {\n    if (!Address || A < *Address) {\n      // Return an empty range without default-constructing the iterators.\n      return findDataBlocksAtOffset(0, 0);\n    }\n    return findDataBlocksAtOffset(A - *Address);\n  }\n\n  /// \\brief Find all the data blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are between the addresses.\n  const_data_block_range findDataBlocksAt(Addr Low, Addr High) const {\n    if (!Address) {\n      // Return an empty range without default-constructing the iterators.\n      return findDataBlocksAtOffset(0, 0);\n    }\n    return findDataBlocksAtOffset(Low - std::min(*Address, Low),\n                                  High - std::min(*Address, High));\n  }\n\nprivate:\n  /// \\class SymbolicExpressionElementBase\n  ///\n  /// \\brief The base class for \\ref SymbolicExpressionElement and\n  /// \\ref ConstSymbolicExpressionElement.\n  ///\n  /// \\tparam ByteIntervalType either \"ByteInterval\" or \"const ByteInterval\".\n  template <typename ByteIntervalType> class SymbolicExpressionElementBase {\n  public:\n    /// \\brief Construct a new symbolic expression element.\n    ///\n    /// \\param BI_  The interval this symbolic expression belongs to.\n    /// \\prarm Off_ The offset in the interval this symbolic expression is at.\n    /// \\param SE_  The \\ref SymbolicExpression in \\p BI_ at \\p Off_.\n    SymbolicExpressionElementBase(ByteIntervalType* BI_, uint64_t Off_,\n                                  const SymbolicExpression& SE_)\n        : BI{BI_}, Off{Off_}, SE{SE_} {}\n\n    /// \\brief Get the interval this symbolic expression belongs to.\n    ByteIntervalType* getByteInterval() { return BI; }\n\n    /// \\brief Get the interval this symbolic expression belongs to.\n    const ByteIntervalType* getByteInterval() const { return BI; }\n\n    /// \\brief Get the offset in the interval this symbolic expression is at.\n    uint64_t getOffset() const { return Off; }\n\n    /// \\brief Get the \\ref SymbolicExpression in \\ref getByteInterval at\n    /// \\ref getOffset.\n    const SymbolicExpression& getSymbolicExpression() const { return SE; }\n\n    /// \\brief Convert this \\ref SymbolicExpressionElement into a \\ref\n    /// ConstSymbolicExpressionElement.\n    operator SymbolicExpressionElementBase<const ByteIntervalType>() const {\n      return SymbolicExpressionElementBase<const ByteIntervalType>(BI, Off, SE);\n    }\n\n    /// \\class AddressLess\n    ///\n    /// \\brief A comparison function object to order symbolic expression\n    /// elements by the address in which they occur.\n    struct AddressLess {\n      using key_type = std::optional<Addr>;\n      static key_type\n      key(const SymbolicExpressionElementBase<ByteIntervalType>& SEE) {\n        if (auto A = SEE.getByteInterval()->getAddress(); A) {\n          return *A + SEE.getOffset();\n        }\n        return std::nullopt;\n      };\n      bool operator()(\n          const SymbolicExpressionElementBase<ByteIntervalType>& SEE1,\n          const SymbolicExpressionElementBase<ByteIntervalType>& SEE2) const {\n        return key(SEE1) < key(SEE2);\n      }\n    };\n\n  private:\n    ByteIntervalType* BI;\n    uint64_t Off;\n    SymbolicExpression SE;\n  };\n\n  /// \\class SymExprPairToElement\n  ///\n  /// \\brief A transform function object to convert \\ref SymbolicExpressions\n  /// values into \\ref SymbolicExpressionElement objects.\n  ///\n  /// \\tparam SymExprElementType Either \\ref SymbolicExpressionElement or \\ref\n  /// ConstSymbolicExpressionElement.\n  template <typename SymExprElementType> class SymExprPairToElement {\n    using ByteIntervalType =\n        decltype(std::declval<SymExprElementType>().getByteInterval());\n    ByteIntervalType BI;\n\n  public:\n    explicit SymExprPairToElement(ByteIntervalType BI_) : BI{BI_} {}\n\n    SymExprElementType\n    operator()(const SymbolicExpressionMap::value_type& Pair) const {\n      return SymExprElementType(BI, Pair.first, Pair.second);\n    }\n  };\n\npublic:\n  /// \\brief A symbolic expression paired with the information needed to look\n  /// up or alter the symbolic expression after the fact.\n  using SymbolicExpressionElement = SymbolicExpressionElementBase<ByteInterval>;\n\n  /// \\brief A symbolic expression paired with the information needed to look\n  /// up or alter the symbolic expression after the fact.\n  using ConstSymbolicExpressionElement =\n      SymbolicExpressionElementBase<const ByteInterval>;\n\n  /// \\brief Iterator over \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in offset order, ascending.\n  using symbolic_expression_iterator =\n      boost::transform_iterator<SymExprPairToElement<SymbolicExpressionElement>,\n                                SymbolicExpressionMap::iterator>;\n  /// \\brief Range of \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in offset order, ascending.\n  using symbolic_expression_range =\n      boost::iterator_range<symbolic_expression_iterator>;\n  /// \\brief Const iterator over \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in offset order, ascending.\n  using const_symbolic_expression_iterator = boost::transform_iterator<\n      SymExprPairToElement<ConstSymbolicExpressionElement>,\n      SymbolicExpressionMap::const_iterator>;\n  /// \\brief Const range of \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in offset order, ascending.\n  using const_symbolic_expression_range =\n      boost::iterator_range<const_symbolic_expression_iterator>;\n\n  /// \\brief Return an iterator to the first \\ref SymbolicExpression.\n  symbolic_expression_iterator symbolic_expressions_begin() {\n    return boost::make_transform_iterator(\n        SymbolicExpressions.begin(),\n        SymExprPairToElement<SymbolicExpressionElement>(this));\n  }\n  /// \\brief Return a const iterator to the first \\ref SymbolicExpression.\n  const_symbolic_expression_iterator symbolic_expressions_begin() const {\n    return boost::make_transform_iterator(\n        SymbolicExpressions.begin(),\n        SymExprPairToElement<ConstSymbolicExpressionElement>(this));\n  }\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// SymbolicExpression.\n  symbolic_expression_iterator symbolic_expressions_end() {\n    return boost::make_transform_iterator(\n        SymbolicExpressions.end(),\n        SymExprPairToElement<SymbolicExpressionElement>(this));\n  }\n  /// \\brief Return a const iterator to the element following the last \\ref\n  /// SymbolicExpression.\n  const_symbolic_expression_iterator symbolic_expressions_end() const {\n    return boost::make_transform_iterator(\n        SymbolicExpressions.end(),\n        SymExprPairToElement<ConstSymbolicExpressionElement>(this));\n  }\n  /// \\brief Return a range of the \\ref SymbolicExpression objects in this\n  /// interval.\n  symbolic_expression_range symbolic_expressions() {\n    return boost::make_iterator_range(symbolic_expressions_begin(),\n                                      symbolic_expressions_end());\n  }\n  /// \\brief Return a const range of the \\ref SymbolicExpression objects in\n  /// this interval.\n  const_symbolic_expression_range symbolic_expressions() const {\n    return boost::make_iterator_range(symbolic_expressions_begin(),\n                                      symbolic_expressions_end());\n  }\n\n  /// \\brief Find all the symbolic expressions that start at an offset.\n  ///\n  /// Note that only one symbolic expression can be at any given offset, so this\n  /// iterator will only ever return 0 or 1 elements. This function is provided\n  /// for consistency with other \\ref Node objects; prefer \\ref\n  /// getSymbolicExpression instead.\n  ///\n  /// \\param Off The offset to look up.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are at the offset\n  /// \\p Off.\n  symbolic_expression_range findSymbolicExpressionsAtOffset(uint64_t Off) {\n    auto Pair = SymbolicExpressions.equal_range(Off);\n    return boost::make_iterator_range(\n        boost::make_transform_iterator(\n            Pair.first, SymExprPairToElement<SymbolicExpressionElement>(this)),\n        boost::make_transform_iterator(\n            Pair.second,\n            SymExprPairToElement<SymbolicExpressionElement>(this)));\n  }\n\n  /// \\brief Find all the symbolic expressions that start between a range of\n  /// offsets.\n  ///\n  /// \\param Low  The low offset, inclusive.\n  /// \\param High The high offset, exclusive.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are between the\n  /// offsets.\n  symbolic_expression_range findSymbolicExpressionsAtOffset(uint64_t Low,\n                                                            uint64_t High) {\n    return boost::make_iterator_range(\n        boost::make_transform_iterator(\n            SymbolicExpressions.lower_bound(Low),\n            SymExprPairToElement<SymbolicExpressionElement>(this)),\n        boost::make_transform_iterator(\n            SymbolicExpressions.lower_bound(High),\n            SymExprPairToElement<SymbolicExpressionElement>(this)));\n  }\n\n  /// \\brief Find all the symbolic expressions that start at an address.\n  ///\n  /// Note that only one symbolic expression can be at any given offset, so this\n  /// iterator will only ever return 0 or 1 elements. This function is provided\n  /// for consistency with other \\ref Node objects; prefer \\ref\n  /// getSymbolicExpression instead.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are at the address\n  /// \\p A.\n  symbolic_expression_range findSymbolicExpressionsAt(Addr A) {\n    if (!Address) {\n      return boost::make_iterator_range(symbolic_expressions_end(),\n                                        symbolic_expressions_end());\n    }\n    return findSymbolicExpressionsAtOffset(A - *Address);\n  }\n\n  /// \\brief Find all the symbolic expressions that start between a range of\n  /// addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are between the\n  /// addresses.\n  symbolic_expression_range findSymbolicExpressionsAt(Addr Low, Addr High) {\n    if (!Address) {\n      return boost::make_iterator_range(symbolic_expressions_end(),\n                                        symbolic_expressions_end());\n    }\n    return findSymbolicExpressionsAtOffset(Low - *Address, High - *Address);\n  }\n\n  /// \\brief Find all the symbolic expressions that start at an offset.\n  ///\n  /// Note that only one symbolic expression can be at any given offset, so this\n  /// iterator will only ever return 0 or 1 elements. This function is provided\n  /// for consistency with other \\ref Node objects; prefer \\ref\n  /// getSymbolicExpression instead.\n  ///\n  /// \\param Off The offset to look up.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are at the offset\n  /// \\p Off.\n  const_symbolic_expression_range\n  findSymbolicExpressionsAtOffset(uint64_t Off) const {\n    auto Pair = SymbolicExpressions.equal_range(Off);\n    return boost::make_iterator_range(\n        boost::make_transform_iterator(\n            Pair.first,\n            SymExprPairToElement<ConstSymbolicExpressionElement>(this)),\n        boost::make_transform_iterator(\n            Pair.second,\n            SymExprPairToElement<ConstSymbolicExpressionElement>(this)));\n  }\n\n  /// \\brief Find all the symbolic expressions that start between a range of\n  /// offsets.\n  ///\n  /// \\param Low  The low offset, inclusive.\n  /// \\param High The high offset, exclusive.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are between the\n  /// offsets.\n  const_symbolic_expression_range\n  findSymbolicExpressionsAtOffset(uint64_t Low, uint64_t High) const {\n    return boost::make_iterator_range(\n        boost::make_transform_iterator(\n            SymbolicExpressions.lower_bound(Low),\n            SymExprPairToElement<ConstSymbolicExpressionElement>(this)),\n        boost::make_transform_iterator(\n            SymbolicExpressions.lower_bound(High),\n            SymExprPairToElement<ConstSymbolicExpressionElement>(this)));\n  }\n\n  /// \\brief Find all the symbolic expressions that start at an address.\n  ///\n  /// Note that only one symbolic expression can be at any given offset, so this\n  /// iterator will only ever return 0 or 1 elements. This function is provided\n  /// for consistency with other \\ref Node objects; prefer \\ref\n  /// getSymbolicExpression instead.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are at the address\n  /// \\p A.\n  const_symbolic_expression_range findSymbolicExpressionsAt(Addr A) const {\n    if (!Address) {\n      return boost::make_iterator_range(symbolic_expressions_end(),\n                                        symbolic_expressions_end());\n    }\n    return findSymbolicExpressionsAtOffset(A - *Address);\n  }\n\n  /// \\brief Find all the symbolic expressions that start between a range of\n  /// addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are between the\n  /// addresses.\n  const_symbolic_expression_range findSymbolicExpressionsAt(Addr Low,\n                                                            Addr High) const {\n    if (!Address) {\n      return boost::make_iterator_range(symbolic_expressions_end(),\n                                        symbolic_expressions_end());\n    }\n    return findSymbolicExpressionsAtOffset(Low - *Address, High - *Address);\n  }\n\n  /// \\brief Remove a block from this interval.\n  ///\n  /// \\param  B           The block to remove.\n  ///\n  /// \\return Whether or not the operation succeeded. This operation can\n  /// fail if the node to remove is not actually part of this node to begin\n  /// with.\n  ChangeStatus removeBlock(CodeBlock* B);\n\n  /// \\brief Remove a block from this interval.\n  ///\n  /// \\param  B           The block to remove.\n  ///\n  /// \\return Whether or not the operation succeeded. This operation can\n  /// fail if the node to remove is not actually part of this node to begin\n  /// with.\n  ChangeStatus removeBlock(DataBlock* B);\n\n  /// \\brief Move an existing CodeBlock to be a part of this interval.\n  ///\n  /// \\param  Off         The offset to move the block to.\n  /// \\param  N           The block to move.\n  ///\n  /// \\return a ChangeStatus indicating whether the insertion took place\n  /// (\\c Accepted), was unnecessary because this node already contained the\n  /// CodeBlock (\\c NoChange), or could not be completed (\\c Rejected).\n  ChangeStatus addBlock(uint64_t Off, CodeBlock* N);\n\n  /// \\brief Move an existing DataBlock to be a part of this interval.\n  ///\n  /// \\param  Off         The offset to move the block to.\n  /// \\param  N           The block to move.\n  ///\n  /// \\return a ChangeStatus indicating whether the insertion took place\n  /// (\\c Accepted), was unnecessary because this node already contained the\n  /// DataBlock (\\c NoChange), or could not be completed (\\c Rejected).\n  ChangeStatus addBlock(uint64_t Off, DataBlock* N);\n\n  /// \\brief Creates a new \\ref Block of the given type at a given offset.\n  ///\n  /// \\tparam BlockType Either \\ref CodeBlock or \\ref DataBlock.\n  /// \\tparam Args  The arguments to construct a \\ref CodeBlock.\n  /// \\param  C     The \\ref Context to use.\n  /// \\param  O     The offset to add the new \\ref CodeBlock at.\n  /// \\param  A     The arguments to construct a \\ref CodeBlock.\n  /// \\return       The newly created \\ref CodeBlock.\n  template <typename BlockType, typename... Args>\n  BlockType* addBlock(Context& C, uint64_t O, Args&&... A) {\n    BlockType* B = BlockType::Create(C, std::forward<Args>(A)...);\n    [[maybe_unused]] ChangeStatus Status = addBlock(O, B);\n    // addBlock(uint64_t, BlockType*) does not currently reject any insertions\n    // and the result cannot be NoChange because we just inserted a newly\n    // created ByteInterval.\n    assert(Status == ChangeStatus::Accepted &&\n           \"unexpected result when inserting ByteInterval\");\n    return B;\n  }\n\n  /// \\brief Adds a new \\ref SymbolicExpression to this interval.\n  ///\n  /// \\param  Off       The offset to add the new \\ref SymbolicExpression at.\n  /// \\param  SymExpr   An existing \\ref SymbolicExpression to copy into this\n  ///                   interval.\n  /// \\return           The newly created \\ref SymbolicExpression.\n  SymbolicExpression& addSymbolicExpression(uint64_t Off,\n                                            const SymbolicExpression& SymExpr) {\n    SymbolicExpressions[Off] = SymExpr;\n    return SymbolicExpressions[Off];\n  }\n\n  /// \\brief Adds a new \\ref SymbolicExpression to this interval.\n  ///\n  /// \\tparam ExprType  The type of symbolic expression to create\n  ///                   (\\ref SymAddrConst, \\ref SymAddrAddr, etc).\n  /// \\tparam Args      The arguments to construct something of ExprType.\n  /// \\param  O         The offset to add the new \\ref SymbolicExpression at.\n  /// \\param  A         The arguments to construct something of ExprType.\n  /// \\return           The newly created \\ref SymbolicExpression.\n  template <class ExprType, class... Args>\n  SymbolicExpression& addSymbolicExpression(uint64_t Off, Args... A) {\n    SymbolicExpressions[Off] = ExprType{A...};\n    return SymbolicExpressions[Off];\n  }\n\n  /// \\brief Removes a \\ref SymbolicExpression at the given offset, if\n  /// present.\n  ///\n  /// \\param Off  The offset of the \\ref SymbolicExpression to remove.\n  ///\n  /// \\return Whether or not the operation succeeded. This operation can\n  /// fail if the node to remove is not actually part of this node to begin\n  /// with.\n  bool removeSymbolicExpression(uint64_t Off) {\n    std::size_t N;\n    N = SymbolicExpressions.erase(Off);\n    return N != 0;\n  }\n\n  /// \\brief Get the symbolic expression at the given offset, if present.\n  ///\n  /// \\param Off  The offset of the \\ref SymbolicExpression to return.\n  /// \\return   The \\ref SymbolicExpression at that offset, or nullptr if\n  /// there\n  ///           is no \\ref SymbolicExpression at that offset.\n  SymbolicExpression* getSymbolicExpression(uint64_t Off) {\n    if (auto It = SymbolicExpressions.find(Off);\n        It != SymbolicExpressions.end()) {\n      return &It->second;\n    }\n    return nullptr;\n  }\n\n  /// \\brief Get the symbolic expression at the given offset, if present.\n  ///\n  /// \\param Off  The offset of the \\ref SymbolicExpression to return.\n  /// \\return   The \\ref SymbolicExpression at that offset, or nullptr if\n  /// there\n  ///           is no \\ref SymbolicExpression at that offset.\n  const SymbolicExpression* getSymbolicExpression(uint64_t Off) const {\n    if (auto It = SymbolicExpressions.find(Off);\n        It != SymbolicExpressions.end()) {\n      return &It->second;\n    }\n    return nullptr;\n  }\n\n  /// \\brief Set or clear the address of this interval.\n  ///\n  /// \\param A  Either the new address, or an empty \\ref std::optional if you\n  ///           wish to remove the address.\n  void setAddress(std::optional<Addr> A);\n\n  /// \\brief Get the size of this interval in bytes.\n  ///\n  /// If this number is greater than the value returned by \\ref\n  /// getInitializedSize, this indicates that the high addresses taken up by\n  /// this interval consist of uninitialized bytes. This often occurs in BSS\n  /// sections, where data is zero-initialized rather than stored as zeroes in\n  /// the binary.\n  uint64_t getSize() const { return Size; }\n\n  /// \\brief Set the size of this interval.\n  ///\n  /// This will also adjust \\ref getInitializedSize if the size given is less\n  /// than the initialized size.\n  ///\n  /// \\param S  The new size.\n  void setSize(uint64_t S);\n\n  /// \\brief Get the number of initialized bytes in this interval.\n  ///\n  /// Not all bytes in this interval may correspond to bytes physically stored\n  /// in the underlying file format. This can occur, for example, in BSS\n  /// sections, which are zero-initialized at loadtime, but these zeroes are\n  /// not stored in the file itself. If this number is smaller than the value\n  /// returned by \\ref getSize, this indicates that any bytes past this number\n  /// are unitialized bytes with values determined at loadtime. As such, all\n  /// bytes past this number in this interval's byte vector are truncated when\n  /// saving to file.\n  ///\n  /// This number will never be larger than the value returned by \\ref\n  /// getSize.\n  uint64_t getInitializedSize() const { return Bytes.size(); }\n\n  /// \\brief Set the number of initialized bytes in this interval.\n  ///\n  /// Not all bytes in this interval may correspond to bytes physically stored\n  /// in the underlying file format. This can occur, for example, in BSS\n  /// sections, which are zero-initialized at loadtime, but these zeroes are\n  /// not stored in the file itself. If this number is smaller than the value\n  /// returned by \\ref getSize, this indicates that any bytes past this number\n  /// are unitialized bytes with values determined at loadtime. As such, all\n  /// bytes past this number in this interval's byte vector are truncated when\n  /// saving to file.\n  ///\n  /// If the number specified is larger than \\ref getSize, then\n  /// the byte vector is expanded with zeroes to be equal to the new allocated\n  /// size.\n  void setInitializedSize(uint64_t S) {\n    Bytes.resize(S);\n    if (S > getSize()) {\n      setSize(S);\n    }\n  }\n\nprivate:\n  // Wrapper to boost::endian::conditional_reverse which skips the call for\n  // 1-byte types (char, [un]signed char, [u]int8_t).\n  // This layer was added to work around a bug in boost 1.67 (fixed as of 1.74)\n  // which gave wrong results for T=char.\n  // It also allows BytesReference to work for std::byte.\n  template <typename T>\n  static inline std::enable_if_t<sizeof(T) != 1, T>\n  endian_flip(T From, boost::endian::order In, boost::endian::order Out) {\n    return boost::endian::conditional_reverse(From, In, Out);\n  }\n  template <typename T>\n  static inline std::enable_if_t<sizeof(T) == 1, T>\n  endian_flip(T From, boost::endian::order, boost::endian::order) {\n    return From;\n  }\n\n  /// \\class BytesReference\n  ///\n  /// \\brief A reference to a section of the byte interval, allowing for\n  /// seamless reading and writing of chunks of data.\n  ///\n  /// \\tparam ByteIntervalType  Either \"ByteInterval\" or\n  ///                           \"const ByteInterval\".\n  /// \\tparam T  The type of the data to iterate over. Must be a POD\n  ///            type that satisfies Boost's EndianReversible concept.\n  template <typename ByteIntervalType, typename T> class BytesReference {\n  public:\n    BytesReference(ByteIntervalType* BI_, size_t I_,\n                   boost::endian::order InputOrder_,\n                   boost::endian::order OutputOrder_)\n        : BI(BI_), I(I_), InputOrder(InputOrder_), OutputOrder(OutputOrder_) {}\n\n    /// \\brief Use this reference as an rvalue.\n    ///\n    /// This method automatically handles endian conversions.\n    /// If uninitlized bytes are read from, then those bytes are treated as\n    /// zeroes.\n    operator T() const {\n      assert(I + sizeof(T) <= BI->Size &&\n             \"read into interval's bytes out of bounds!\");\n\n      auto S = BI->Bytes.size();\n\n      if (I >= S) {\n        // anything this far past the end of initialized bytes is composed of\n        // all zero bytes, so we return what T would have been interpreted as\n        // if all bytes are zero.\n        //\n        // (note that you may be tempted to replace this with \"return T{};\",\n        // but beware: T might be a non-scalar type whose default constructor\n        // differs from the value returned when all bytes are re-interpeted as\n        // zeroes. A similar argument exists for \"return T{0};\".)\n        const std::array<uint8_t, sizeof(T)> Array{};\n        return *reinterpret_cast<const T*>(Array.data());\n      }\n\n      if (sizeof(T) > S - I) {\n        // Here, I < S < I + sizeof(T), so we need to partially fill the\n        // initialized bytes and combine it with zeroes for the uninitialized\n        // bytes. The condition is S - I < sizeof(T) not S < I + sizeof(T) to\n        // help compilers verify the bounds in the std::copy_n below are safe.\n        std::array<uint8_t, sizeof(T)> Array{};\n        std::copy_n(BI->Bytes.begin() + I, S - I, Array.begin());\n        return endian_flip(*reinterpret_cast<const T*>(Array.data()),\n                           InputOrder, OutputOrder);\n      }\n\n      return endian_flip(*reinterpret_cast<const T*>(BI->Bytes.data() + I),\n                         InputOrder, OutputOrder);\n    }\n\n    /// \\brief Use this reference as an lvalue.\n    ///\n    /// This method automatically handles endian conversions.\n    /// If uninitlized bytes are written to, then the initialized byte count\n    /// is adjusted (see \\ref getInitializedSize for details), padding with\n    /// zeroes as necesary.\n    BytesReference<ByteIntervalType, T>& operator=(const T& rhs) {\n      assert(I + sizeof(T) <= BI->Size &&\n             \"write into interval's bytes out of bounds!\");\n\n      if (I + sizeof(T) > BI->Bytes.size()) {\n        BI->Bytes.resize(I + sizeof(T));\n      }\n\n      *reinterpret_cast<T*>(BI->Bytes.data() + I) =\n          endian_flip(rhs, OutputOrder, InputOrder);\n      return *this;\n    }\n\n    ByteIntervalType* BI;\n    size_t I;\n    boost::endian::order InputOrder;\n    boost::endian::order OutputOrder;\n  };\n\n  /// \\brief An iterator over the bytes in this byte vector.\n  ///\n  /// \\tparam ByteIntervalType  Either \"ByteInterval\" or\n  ///                           \"const ByteInterval\".\n  /// \\tparam T  The type of the data to iterate over. Must be a POD\n  ///            type that satisfies Boost's EndianReversible concept.\n  template <typename ByteIntervalType, typename T>\n  class BytesBaseIterator\n      : public boost::iterator_facade<BytesBaseIterator<ByteIntervalType, T>, T,\n                                      boost::random_access_traversal_tag,\n                                      BytesReference<ByteIntervalType, T>> {\n  private:\n    using self = BytesBaseIterator<ByteIntervalType, T>;\n\n    BytesBaseIterator(ByteIntervalType* BI_, size_t I_,\n                      boost::endian::order InputOrder_,\n                      boost::endian::order OutputOrder_)\n        : BI(BI_), I(I_), InputOrder(InputOrder_), OutputOrder(OutputOrder_) {}\n\n  public:\n    using reference = BytesReference<ByteIntervalType, T>;\n\n    /// \\brief Default-construct an iterator to a byte interval's bytes.\n    ///\n    /// A default-constructed iterator compares equal only to other\n    /// default-constructed iterators. Dereferencing, incremending, or\n    /// decrementing a default-constructed iterator results in undefined\n    /// behavior.\n    BytesBaseIterator() = default;\n\n    // Beginning of functions for iterator facade compatibility.\n    reference dereference() const {\n      assert(BI && \"attempt to dereference default-constructed byte iterator!\");\n      return reference(BI, I, InputOrder, OutputOrder);\n    }\n\n    bool equal(const self& other) const {\n      return BI == other.BI && I == other.I;\n    }\n\n    void increment() {\n      assert(BI && \"attempt to increment default-constructed byte iterator!\");\n      I += sizeof(T);\n    }\n\n    void decrement() {\n      assert(BI && \"attempt to decrement default-constructed byte iterator!\");\n      I -= sizeof(T);\n    }\n\n    void advance(typename self::difference_type n) {\n      assert(BI && \"attempt to advance default-constructed byte iterator!\");\n      I += n * sizeof(T);\n    }\n\n    typename self::difference_type distance_to(const self& other) const {\n      return (other.I - I) / sizeof(T);\n    }\n    // End of functions for iterator facade compatibility.\n\n    /// \\brief Convert this iterator into a const iterator.\n    operator BytesBaseIterator<const ByteIntervalType, T>() const {\n      return BytesBaseIterator<const ByteIntervalType, T>(BI, I, InputOrder,\n                                                          OutputOrder);\n    }\n\n  private:\n    ByteIntervalType* BI{nullptr};\n    size_t I{0};\n    boost::endian::order InputOrder{boost::endian::order::native};\n    boost::endian::order OutputOrder{boost::endian::order::native};\n\n    friend class ByteInterval;\n  };\n\npublic:\n  /// \\brief Iterator over bytes.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  template <typename T>\n  using bytes_iterator = BytesBaseIterator<ByteInterval, T>;\n  /// \\brief Range over bytes.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  template <typename T>\n  using bytes_range = boost::iterator_range<bytes_iterator<T>>;\n  /// \\brief Const iterator over bytes.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  template <typename T>\n  using const_bytes_iterator = BytesBaseIterator<const ByteInterval, T>;\n  /// \\brief Const range over bytes.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  template <typename T>\n  using const_bytes_range = boost::iterator_range<const_bytes_iterator<T>>;\n\n  /// \\brief Get an iterator to the beginning of this byte vector.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> bytes_iterator<T> bytes_begin() {\n    return bytes_begin<T>(getBoostEndianOrder());\n  }\n\n  /// \\brief Get an iterator to the beginning of this byte vector.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the vector.\n  /// \\param  OutputOrder The endianness you wish to read out from the vector.\n  template <typename T>\n  bytes_iterator<T>\n  bytes_begin(boost::endian::order InputOrder,\n              boost::endian::order OutputOrder = boost::endian::order::native) {\n    return bytes_iterator<T>(this, 0, InputOrder, OutputOrder);\n  }\n\n  /// \\brief Get an iterator past the end of this byte vector.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> bytes_iterator<T> bytes_end() {\n    return bytes_end<T>(getBoostEndianOrder());\n  }\n\n  /// \\brief Get an iterator past the end of this byte vector.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the vector.\n  /// \\param  OutputOrder The endianness you wish to read out from the vector.\n  template <typename T>\n  bytes_iterator<T>\n  bytes_end(boost::endian::order InputOrder,\n            boost::endian::order OutputOrder = boost::endian::order::native) {\n    return bytes_iterator<T>(this, Size, InputOrder, OutputOrder);\n  }\n\n  /// \\brief Get a range of data in this byte vector.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> bytes_range<T> bytes() {\n    return bytes<T>(getBoostEndianOrder());\n  }\n\n  /// \\brief Get a range of data in this byte vector.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the vector.\n  /// \\param  OutputOrder The endianness you wish to read out from the vector.\n  template <typename T>\n  bytes_range<T>\n  bytes(boost::endian::order InputOrder,\n        boost::endian::order OutputOrder = boost::endian::order::native) {\n    return bytes_range<T>(bytes_begin<T>(InputOrder, OutputOrder),\n                          bytes_end<T>(InputOrder, OutputOrder));\n  }\n\n  /// \\brief Get an iterator to the beginning of this byte vector.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> const_bytes_iterator<T> bytes_begin() const {\n    return bytes_begin<T>(getBoostEndianOrder());\n  }\n\n  /// \\brief Get an iterator to the beginning of this byte vector.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the vector.\n  /// \\param  OutputOrder The endianness you wish to read out from the vector.\n  template <typename T>\n  const_bytes_iterator<T> bytes_begin(\n      boost::endian::order InputOrder,\n      boost::endian::order OutputOrder = boost::endian::order::native) const {\n    return const_bytes_iterator<T>(this, 0, InputOrder, OutputOrder);\n  }\n\n  /// \\brief Get an iterator past the end of this byte vector.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> const_bytes_iterator<T> bytes_end() const {\n    return bytes_end<T>(getBoostEndianOrder());\n  }\n\n  /// \\brief Get an iterator past the end of this byte vector.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the vector.\n  /// \\param  OutputOrder The endianness you wish to read out from the vector.\n  template <typename T>\n  const_bytes_iterator<T> bytes_end(\n      boost::endian::order InputOrder,\n      boost::endian::order OutputOrder = boost::endian::order::native) const {\n    return const_bytes_iterator<T>(this, Size, InputOrder, OutputOrder);\n  }\n\n  /// \\brief Get a range of data in this byte vector.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> const_bytes_range<T> bytes() const {\n    return bytes<T>(getBoostEndianOrder());\n  }\n\n  /// \\brief Get a range of data in this byte vector.\n  ///\n  /// \\tparam T  The type of data stored in this byte vector. Must be a\n  /// POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the vector.\n  /// \\param  OutputOrder The endianness you wish to read out from the vector.\n  template <typename T>\n  const_bytes_range<T>\n  bytes(boost::endian::order InputOrder,\n        boost::endian::order OutputOrder = boost::endian::order::native) const {\n    return const_bytes_range<T>(bytes_begin<T>(InputOrder, OutputOrder),\n                                bytes_end<T>(InputOrder, OutputOrder));\n  }\n\nprivate:\n  /// \\brief Insert data into this byte vector.\n  ///\n  /// \\tparam T  The type of data you wish to insert into the byte\n  /// vector. Must be a POD type that satisfies Boost's EndianReversible\n  /// concept.\n  ///\n  /// \\tparam BytesIterator  The type of iterator you wish to determine\n  /// the position of where the inserted data will go.\n  ///\n  /// \\tparam InputIterator       The type of an iterator yielding T.\n  ///\n  /// \\param  Pos           The position in the byte vector to insert data at.\n  /// \\param  Begin         The start of the data to insert.\n  /// \\param  End           The end of the data to insert.\n  ///\n  /// \\return An iterator pointing to the first element inserted by this call.\n  template <typename T, typename BytesIterator, typename InputIterator>\n  BytesIterator insertByteVec(\n      BytesIterator Pos, InputIterator Begin, InputIterator End,\n      boost::endian::order VectorOrder,\n      boost::endian::order ElementsOrder = boost::endian::order::native) {\n    static_assert(\n        std::is_same<BytesIterator, bytes_iterator<T>>::value ||\n            std::is_same<BytesIterator, const_bytes_iterator<T>>::value,\n        \"Pos must be a byte_iterator<T> or a const_byte_iterator<T>\");\n\n    auto N = std::distance(Begin, End) * sizeof(T);\n    setSize(Size + N);\n    // If the position to insert is currently outside the initilized bytes,\n    // we let the iterator's operator= handle resizing the byte vector,\n    // otherwise we insert zeroes and then overwrite them via said operator=.\n    if (Pos.I < Bytes.size()) {\n      Bytes.insert(Bytes.begin() + Pos.I, N, 0);\n    }\n    // std::copy calls operator= one time for every element in the input iter.\n    std::copy(Begin, End,\n              bytes_iterator<T>(this, Pos.I, VectorOrder, ElementsOrder));\n    return Pos;\n  }\n\n  /// \\brief Insert a single datum into this byte vector.\n  ///\n  /// \\tparam T  The type of data you wish to insert into the byte\n  /// vector. Must be a POD type that satisfies Boost's EndianReversible\n  /// concept.\n  ///\n  /// \\tparam BytesIterator  The type of iterator you wish to determine\n  /// the position of where the inserted data will go.\n  ///\n  /// \\param  Pos           The position in the byte vector to insert data at.\n  /// \\param  X             The data to insert.\n  /// \\param  VectorOrder   The endianness of the data in the byte vector.\n  /// \\param  ElementOrder  The endianness of the data to be inserted.\n  ///\n  /// \\return An iterator pointing to the element inserted by this call.\n  template <typename T, typename BytesIterator>\n  BytesIterator insertSingleByte(\n      BytesIterator Pos, const T& X, boost::endian::order VectorOrder,\n      boost::endian::order ElementOrder = boost::endian::order::native) {\n    return insertByteVec<T>(Pos, &X, &X + 1, VectorOrder, ElementOrder);\n  }\n\npublic:\n  /// \\brief Insert a single datum into this byte vector.\n  ///\n  /// \\tparam T  The type of data you wish to insert into the byte\n  /// vector. Must be a POD type that satisfies Boost's EndianReversible\n  /// concept.\n  ///\n  /// \\param  Pos           The position in the byte vector to insert data at.\n  /// \\param  X             The data to insert.\n  ///\n  /// \\return An iterator pointing to the element inserted by this call.\n  template <typename T>\n  const_bytes_iterator<T> insertBytes(const const_bytes_iterator<T> Pos,\n                                      const T& X) {\n    return insertBytes<T>(Pos, X, getBoostEndianOrder());\n  }\n\n  /// \\brief Insert a single datum into this byte vector.\n  ///\n  /// \\tparam T  The type of data you wish to insert into the byte\n  /// vector. Must be a POD type that satisfies Boost's EndianReversible\n  /// concept.\n  ///\n  /// \\param  Pos           The position in the byte vector to insert data at.\n  /// \\param  X             The data tprivato insert.\n  ///\n  /// \\return An iterator pointing to the element inserted by this call.\n  template <typename T>\n  bytes_iterator<T> insertBytes(bytes_iterator<T> Pos, const T& X) {\n    return insertBytes<T>(Pos, X, getBoostEndianOrder());\n  }\n\n  /// \\brief Insert a single datum into this byte vector.\n  ///\n  /// \\tparam T  The type of data you wish to insert into the byte\n  /// vector. Must be a POD type that satisfies Boost's EndianReversible\n  /// concept.\n  ///\n  /// \\param  Pos           The position in the byte vector to insert data at.\n  /// \\param  X             The data to insert.\n  /// \\param  VectorOrder   The endianness of the data in the byte vector.\n  /// \\param  ElementOrder  The endianness of the data to be inserted.\n  ///\n  /// \\return An iterator pointing to the element inserted by this call.\n  template <typename T>\n  const_bytes_iterator<T> insertBytes(\n      const const_bytes_iterator<T> Pos, const T& X,\n      boost::endian::order VectorOrder,\n      boost::endian::order ElementOrder = boost::endian::order::native) {\n    return insertSingleByte<T>(Pos, X, VectorOrder, ElementOrder);\n  }\n\n  /// \\brief Insert a single datum into this byte vector.\n  ///\n  /// \\tparam T  The type of data you wish to insert into the byte\n  /// vector. Must be a POD type that satisfies Boost's EndianReversible\n  /// concept.\n  ///\n  /// \\param  Pos           The position in the byte vector to insert data at.\n  /// \\param  X             The data to insert.\n  /// \\param  VectorOrder   The endianness of the data in the byte vector.\n  /// \\param  ElementOrder  The endianness of the data to be inserted.\n  ///\n  /// \\return An iterator pointing to the element inserted by this call.\n  template <typename T>\n  bytes_iterator<T> insertBytes(\n      bytes_iterator<T> Pos, const T& X, boost::endian::order VectorOrder,\n      boost::endian::order ElementOrder = boost::endian::order::native) {\n    return insertSingleByte<T>(Pos, X, VectorOrder, ElementOrder);\n  }\n\n  /// \\brief Insert data into this byte vector.\n  ///\n  /// \\tparam T  The type of data you wish to insert into the byte\n  /// vector. Must be a POD type that satisfies Boost's EndianReversible\n  /// concept.\n  ///\n  /// \\tparam InputIterator      The type of an iterator yielding T.\n  ///\n  /// \\param  Pos           The position in the byte vector to insert data at.\n  /// \\param  Begin         The start of the data to insert.\n  /// \\param  End           The end of the data to insert.\n  ///\n  /// \\return An iterator pointing to the first element inserted by this call.\n\n  template <typename T, typename InputIterator>\n  const_bytes_iterator<T> insertBytes(const const_bytes_iterator<T> Pos,\n                                      InputIterator Begin, InputIterator End) {\n    return insertBytes<T>(Pos, Begin, End, getBoostEndianOrder());\n  }\n  /// \\brief Insert data into this byte vector.\n  ///\n  /// \\tparam T  The type of data you wish to insert into the byte\n  /// vector. Must be a POD type that satisfies Boost's EndianReversible\n  /// concept.\n  ///\n  /// \\tparam InputIterator       The type of an iterator yielding T.\n  ///\n  /// \\param  Pos           The position in the byte vector to insert data at.\n  /// \\param  Begin         The start of the data to insert.\n  /// \\param  End           The end of the data to insert.\n  ///\n  /// \\return An iterator pointing to the first element inserted by this call.\n  template <typename T, typename InputIterator>\n  bytes_iterator<T> insertBytes(bytes_iterator<T> Pos, InputIterator Begin,\n                                InputIterator End) {\n    return insertBytes<T>(Pos, Begin, End, getBoostEndianOrder());\n  }\n\n  /// \\brief Insert data into this byte vector.\n  ///\n  /// \\tparam T  The type of data you wish to insert into the byte\n  /// vector. Must be a POD type that satisfies Boost's EndianReversible\n  /// concept.\n  ///\n  /// \\tparam InputIterator             The type of an iterator yielding T.\n  ///\n  /// \\param  Pos           The position in the byte vector to insert data at.\n  /// \\param  Begin         The start of the data to insert.\n  /// \\param  End           The end of the data to insert.\n  /// \\param  VectorOrder   The endianness of the data in the byte vector.\n  /// \\param  ElementsOrder The endianness of the data to be inserted.\n  ///\n  /// \\return An iterator pointing to the first element inserted by this call.\n  template <typename T, typename InputIterator>\n  const_bytes_iterator<T> insertBytes(\n      const const_bytes_iterator<T> Pos, InputIterator Begin, InputIterator End,\n      boost::endian::order VectorOrder,\n      boost::endian::order ElementsOrder = boost::endian::order::native) {\n    return insertByteVec<T>(Pos, Begin, End, VectorOrder, ElementsOrder);\n  }\n\n  /// \\brief Insert data into this byte vector.\n  ///\n  /// \\tparam T  The type of data you wish to insert into the byte\n  /// vector. Must be a POD type that satisfies Boost's EndianReversible\n  /// concept.\n  ///\n  /// \\tparam InputIterator       The type of an iterator yielding T.\n  ///\n  /// \\param  Pos           The position in the byte vector to insert data at.\n  /// \\param  Begin         The start of the data to insert.\n  /// \\param  End           The end of the data to insert.\n  /// \\param  VectorOrder   The endianness of the data in the byte vector.\n  /// \\param  ElementsOrder The endianness of the data to be inserted.\n  ///\n  /// \\return An iterator pointing to the first element inserted by this call.\n  template <typename T, typename InputIterator>\n  bytes_iterator<T> insertBytes(\n      bytes_iterator<T> Pos, InputIterator Begin, InputIterator End,\n      boost::endian::order VectorOrder,\n      boost::endian::order ElementsOrder = boost::endian::order::native) {\n    return insertByteVec<T>(Pos, Begin, End, VectorOrder, ElementsOrder);\n  }\n\n  /// \\brief Erase data from this byte vector.\n  ///\n  /// \\tparam T  The type of data you wish to erase.\n  ///\n  /// \\param  Begin The start of the data to erase.\n  /// \\param  End   The end of the data to erase.\n  ///\n  /// \\return An iterator pointing to the first element after those erased by\n  /// this call.\n\n  template <typename T>\n  const_bytes_iterator<T> eraseBytes(const const_bytes_iterator<T> Begin,\n                                     const const_bytes_iterator<T> End) {\n    assert(Begin.I <= End.I && \"eraseBytes: Begin > End!\");\n    assert(Begin.I <= Size && \"eraseBytes: Begin out of range!\");\n    assert(End.I <= Size && \"eraseBytes: End out of range!\");\n\n    // If the beginning iter is outside the init vector, nothing need be done.\n    if (Begin.I < Bytes.size()) {\n      if (End.I < Bytes.size()) {\n        // All positions are within the initilized vector.\n        Bytes.erase(Bytes.begin() + Begin.I, Bytes.begin() + End.I);\n      } else {\n        // The beginning is within vector, the end isn't; clamp to\n        // Bytes.end().\n        Bytes.erase(Bytes.begin() + Begin.I, Bytes.end());\n      }\n    }\n\n    setSize(Size - (End.I - Begin.I));\n    return Begin;\n  }\n\n  /// \\brief Return the raw data underlying this byte vector.\n  ///\n  /// Much like \\ref std::vector::data, this function is low-level and\n  /// potentially unsafe. This pointer refers to valid memory only where an\n  /// iterator would be valid to point to. Modifying the size of the byte\n  /// vector may invalidate this pointer. Any endian conversions will not be\n  /// performed.\n  ///\n  /// \\tparam T The type of data stored in this byte vector. Must be a POD\n  /// type.\n  template <typename T> T* rawBytes() {\n    return reinterpret_cast<T*>(Bytes.data());\n  }\n\n  /// \\brief Return the raw data underlying this byte vector.\n  ///\n  /// Much like \\ref std::vector::data, this function is low-level and\n  /// potentially unsafe. This pointer refers to valid memory only where an\n  /// iterator would be valid to point to. Modifying the size of the byte\n  /// vector may invalidate this pointer. Any endian conversions will not be\n  /// performed.\n  ///\n  /// \\tparam T The type of data stored in this byte vector. Must be a POD\n  /// type.\n  template <typename T> const T* rawBytes() const {\n    return reinterpret_cast<const T*>(Bytes.data());\n  }\n\n  /// @cond INTERNAL\n  static bool classof(const Node* N) {\n    return N->getKind() == Kind::ByteInterval;\n  }\n  /// @endcond\n\n  /// \\brief Get the ``boost::endian::order`` of this module, suitable for\n  /// passing to the ``bytes`` iterator.\n  boost::endian::order getBoostEndianOrder() const;\n\nprivate:\n  ByteInterval(Context& C);\n\n  ByteInterval(Context& C, std::optional<Addr> A, uint64_t S, uint64_t InitSize,\n               const UUID& U);\n\n  ByteInterval(Context& C, std::optional<Addr> A, uint64_t S,\n               uint64_t InitSize);\n\n  template <typename InputIterator>\n  ByteInterval(Context& C, std::optional<Addr> A, uint64_t S, uint64_t InitSize,\n               InputIterator Begin, InputIterator End)\n      : ByteInterval(C, A, S, 0) {\n    Bytes.insert(Bytes.end(), Begin, End);\n    Bytes.resize(InitSize);\n  }\n\n  template <typename InputIterator>\n  ByteInterval(Context& C, std::optional<Addr> A, uint64_t S, uint64_t InitSize,\n               InputIterator Begin, InputIterator End, const UUID& U)\n      : ByteInterval(C, A, S, 0, U) {\n    Bytes.insert(Bytes.end(), Begin, End);\n    Bytes.resize(InitSize);\n  }\n\n  void setParent(Section* S, ByteIntervalObserver* O) {\n    Parent = S;\n    Observer = O;\n  }\n\n  template <typename InputIterator>\n  static ByteInterval* Create(Context& C, std::optional<Addr> Address,\n                              InputIterator Begin, InputIterator End,\n                              std::optional<uint64_t> Size,\n                              std::optional<uint64_t> InitSize, const UUID& U) {\n    return C.Create<ByteInterval>(\n        C, Address, Size ? *Size : std::distance(Begin, End),\n        InitSize ? *InitSize : std::distance(Begin, End), Begin, End, U);\n  }\n\n  /// \\brief The protobuf message type used for serializing ByteInterval.\n  using MessageType = proto::ByteInterval;\n\n  /// \\brief Serialize into a protobuf message.\n  ///\n  /// \\param[out] Message   Serialize into this message.\n  ///\n  /// \\return void\n  void toProtobuf(MessageType* Message) const;\n\n  /// \\brief Construct a ByteInterval from a protobuf message.\n  ///\n  /// \\param C  The Context in which the deserialized ByteInterval will be held.\n  /// \\param Message  The protobuf message from which to deserialize.\n  ///\n  /// \\return The deserialized ByteInterval object, or null on failure.\n  static ErrorOr<ByteInterval*> fromProtobuf(Context& C,\n                                             const MessageType& Message);\n\n  /// \\brief Populate symbolic expressions from a Protobuf message.\n  ///\n  /// \\param C  The Context in which the deserialized SymbolicExpressions will\n  /// be held.\n  /// \\param Message  The protobuf message from which to deserialize.\n  /// \\return true if the symbolic expression could be loaded from protobuf,\n  /// false otherwise.\n  bool symbolicExpressionsFromProtobuf(Context& C, const MessageType& Message);\n\n  // Present for testing purposes only.\n  void save(std::ostream& Out) const;\n\n  // Present for testing purposes only.\n  static ByteInterval* load(Context& C, std::istream& In);\n\n  // Present for testing purposes only.\n  bool loadSymbolicExpressions(Context& C, std::istream& In);\n\n  // Shared implementation for adding CodeBlocks and DataBlocks.\n  template <typename BlockType, typename IterType>\n  ChangeStatus addBlock(uint64_t Off, BlockType* B);\n\n  // Shared implementation for removing CodeBlocks and DataBlocks.\n  template <typename BlockType, typename IterType>\n  ChangeStatus removeBlock(BlockType* B);\n\n  Section* Parent{nullptr};\n  ByteIntervalObserver* Observer{nullptr};\n  std::optional<Addr> Address;\n  uint64_t Size{0};\n  BlockSet Blocks;\n  BlockIntMap BlockOffsets;\n  SymbolicExpressionMap SymbolicExpressions;\n  std::vector<uint8_t> Bytes;\n\n  std::unique_ptr<CodeBlockObserver> CBO;\n  std::unique_ptr<DataBlockObserver> DBO;\n\n  friend class Context;   // Friend to enable Context::Create.\n  friend class Section;   // Friend to enable Section::(re)moveByteInterval,\n                          // Create, etc.\n  friend class CodeBlock; // Friend to enable CodeBlock::getAddress.\n  friend class DataBlock; // Friend to enable DataBlock::getAddress.\n  friend class Module;    // Allow Module::fromProtobuf to deserialize symbolic\n                          // expressions.\n  friend struct BlockOffsetLess;\n  friend class SerializationTestHarness; // Testing support.\n};\n\n///\n/// \\brief Interface for notifying observers when the ByteInterval is modified.\n///\n\nclass GTIRB_EXPORT_API ByteIntervalObserver {\npublic:\n  virtual ~ByteIntervalObserver() = default;\n\n  /// \\brief Notify the parent when new CodeBlocks are added to the interval.\n  ///\n  /// Called after the ByteInterval updates its internal state.\n  ///\n  /// \\param BI      the ByteInterval to which the CodeBlocks were added.\n  /// \\param Blocks  a range containing the new CodeBlocks.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus addCodeBlocks(ByteInterval* BI,\n                                     ByteInterval::code_block_range Blocks) = 0;\n\n  /// \\brief Notify the parent when the addresses of existing CodeBlocks change.\n  ///\n  /// Called after the ByteInterval updates its internal state.\n  ///\n  /// \\param BI      the ByteInterval containing the CodeBlocks.\n  /// \\param Blocks  a range containing the CodeBlocks that moved.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus\n  moveCodeBlocks(ByteInterval* BI, ByteInterval::code_block_range Blocks) = 0;\n\n  /// \\brief Notify the parent when CodeBlocks are removed from the interval.\n  ///\n  /// Called before the ByteInterval updates its internal state.\n  ///\n  /// \\param BI      the ByteInterval from which the CodeBlocks will be removed.\n  /// \\param Blocks  a range containing the CodeBlocks to remove.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus\n  removeCodeBlocks(ByteInterval* BI, ByteInterval::code_block_range Blocks) = 0;\n\n  /// \\brief Notify the parent when new DataBlocks are added to the interval.\n  ///\n  /// Called after the ByteInterval updates its internal state.\n  ///\n  /// \\param BI      the ByteInterval to which the DataBlocks were added.\n  /// \\param Blocks  a range containing the new DataBlocks.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus addDataBlocks(ByteInterval* BI,\n                                     ByteInterval::data_block_range Blocks) = 0;\n\n  /// \\brief Notify the parent when the addresses of existing CodeBlocks change.\n  ///\n  /// Called after the ByteInterval updates its internal state.\n  ///\n  /// \\param BI      the ByteInterval containing the DataBlocks.\n  /// \\param Blocks  a range containing the DataBlocks that moved.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus\n  moveDataBlocks(ByteInterval* BI, ByteInterval::data_block_range Blocks) = 0;\n\n  /// \\brief Notify the parent when DataBlocks are removed from the interval.\n  ///\n  /// Called before the ByteInterval updates its internal state.\n  ///\n  /// \\param BI      the ByteInterval from which the DataBlocks will be removed.\n  /// \\param Blocks  a range containing the DataBlocks to remove.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus\n  removeDataBlocks(ByteInterval* BI, ByteInterval::data_block_range Blocks) = 0;\n\n  /// \\brief Notify the parent when the range of addresses in the interval\n  /// changes.\n  ///\n  /// Called before the ByteInterval's extent changes. This method should\n  /// invoke the callback with \\p BI to update its extent.\n  ///\n  /// \\param BI        the ByteInterval that changed.\n  /// \\param Callback  callable to update the ByteInterval's extent.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus\n  changeExtent(ByteInterval* BI,\n               std::function<void(ByteInterval*)> Callback) = 0;\n};\n\n} // namespace gtirb\n\n#endif // GTIRB_BYTE_INTERVAL_H\n"
  },
  {
    "path": "include/gtirb/CFG.hpp",
    "content": "//===- CFG.hpp --------------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2021 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_CFG_H\n#define GTIRB_CFG_H\n\n#include <gtirb/Casting.hpp>\n#include <gtirb/Export.hpp>\n#include <boost/graph/adjacency_list.hpp>\n#include <boost/iterator/filter_iterator.hpp>\n#include <boost/iterator/indirect_iterator.hpp>\n#include <boost/iterator/iterator_facade.hpp>\n#include <boost/iterator/transform_iterator.hpp>\n#include <boost/range/iterator_range.hpp>\n#include <variant>\n\n/// \\file CFG.hpp\n/// \\ingroup CFG_GROUP\n/// \\brief Types and operations for interprocedural control flow\n/// graphs (CFGs).\n///\n/// \\see CFG_GROUP\n\nnamespace gtirb {\nclass CfgNode;\nclass CodeBlock;\n\n/// \\defgroup CFG_GROUP Control Flow Graphs (CFGs)\n/// \\brief Interprocedural control flow graph, with vertices of type\n/// \\ref Block.\n///\n/// See also \\ref md_CFG-Edges.\n///\n/// @{ @}\n\n/// \\ingroup CFG_GROUP\n/// \\brief Indicates whether an edge is conditional on true.\nenum class ConditionalEdge : bool {\n  OnFalse, ///< \\brief Indicates an unconditional edge or a conditional edge\n           ///< that fires when the condition is false.\n  OnTrue   ///< \\brief Indicates a conditional edge that fires when the\n           ///< condition is true.\n};\nGTIRB_EXPORT_API std::ostream& operator<<(std::ostream& OS,\n                                          const ConditionalEdge& CE);\n\n/// \\ingroup CFG_GROUP\n/// \\brief Indicates whether an edge represents indirect control flow.\nenum class DirectEdge : bool { IsIndirect, IsDirect };\nGTIRB_EXPORT_API std::ostream& operator<<(std::ostream& OS,\n                                          const DirectEdge& DE);\n\n/// \\ingroup CFG_GROUP\n/// \\brief Indicates the type of control flow transfer indicated by this edge.\nenum class EdgeType { Branch, Call, Fallthrough, Return, Syscall, Sysret };\nGTIRB_EXPORT_API std::ostream& operator<<(std::ostream& OS, const EdgeType& ET);\n\n/// \\ingroup CFG_GROUP\n/// \\brief A label on a \\ref CFG edge.\nusing EdgeLabel =\n    std::optional<std::tuple<ConditionalEdge, DirectEdge, EdgeType>>;\nGTIRB_EXPORT_API std::ostream& operator<<(std::ostream& OS,\n                                          const EdgeLabel& Label);\n/// @cond INTERNAL\n\n// Helper for constructing the CFG type. The graph property needs to refer to\n// the graph's vertex_descriptor type. This is accessible via\n// boost::adjacency_list_traits, but requires keeping the template parameters\n// for boost::adjacency_list and boost::adjacency_list_traits in sync. This\n// helper ensures the relevant parameters are the same for both.\ntemplate <class OutEdgeListS = boost::vecS, class VertexListS = boost::vecS,\n          class DirectedS = boost::directedS, class EdgeListS = boost::listS>\nstruct CfgBuilder {\n  using vertex_descriptor = typename boost::adjacency_list_traits<\n      OutEdgeListS, VertexListS, DirectedS, EdgeListS>::vertex_descriptor;\n  using type = boost::adjacency_list<\n      OutEdgeListS, VertexListS, DirectedS,\n      // Vertices are CfgNodes.\n      CfgNode*,\n      // Edges have labels.\n      EdgeLabel,\n      // The graph keeps track of vertex descriptors for\n      // each node.\n      std::unordered_map<const CfgNode*, vertex_descriptor>, EdgeListS>;\n};\n/// @endcond\n\n/// \\ingroup CFG_GROUP\n/// \\brief Interprocedural \\ref CFG_GROUP \"control flow graph\", with\n/// vertices of type \\ref Block.\nusing CFG = CfgBuilder<boost::listS,         // allow parallel edges\n                       boost::listS,         // preserve IDs after mutations\n                       boost::bidirectionalS // successor and predecessor edges\n                       >::type;\n/// @cond INTERNAL\nclass cfg_node_iter_base\n    : public boost::iterator_facade<cfg_node_iter_base,\n                                    const boost::vertex_bundle_type<CFG>::type,\n                                    CFG::vertex_iterator::iterator_category> {\npublic:\n  cfg_node_iter_base() = default;\n  cfg_node_iter_base(const CFG& cfg_, CFG::vertex_iterator& it_)\n      : cfg(&cfg_), it(it_) {}\n\n  // Use default move and copy constructors and assignment operators.\n  cfg_node_iter_base(const cfg_node_iter_base&) = default;\n  cfg_node_iter_base(cfg_node_iter_base&&) = default;\n  cfg_node_iter_base& operator=(const cfg_node_iter_base&) = default;\n  cfg_node_iter_base& operator=(cfg_node_iter_base&&) = default;\n\nprivate:\n  friend class boost::iterator_core_access;\n\n  void increment() { ++it; }\n  void decrement() { --it; }\n\n  std::ptrdiff_t distance_to(const cfg_node_iter_base& other) const {\n    return std::distance(it, other.it);\n  }\n\n  bool equal(const cfg_node_iter_base& other) const { return it == other.it; }\n\n  const boost::vertex_bundle_type<CFG>::type& dereference() const {\n    return (*cfg)[*it];\n  }\n\n  const CFG* cfg{nullptr};\n  CFG::vertex_iterator it;\n};\n\ntemplate <typename ToTy> struct downcast {\n  template <typename FromTy> auto operator()(FromTy& Val) const {\n    return dyn_cast_or_null<ToTy>(Val);\n  }\n};\n\nstruct not_null {\n  template <typename T> bool operator()(const T* t) { return t != nullptr; }\n};\n\ntemplate <typename T>\nusing cfg_node_downcast_iter =\n    boost::transform_iterator<downcast<std::remove_const_t<T>>,\n                              cfg_node_iter_base>;\n\ntemplate <typename T>\nusing cfg_node_downcast_not_null_iter =\n    boost::filter_iterator<not_null, cfg_node_downcast_iter<T>>;\n\ntemplate <typename T>\nclass cfg_node_cast_iter\n    : public boost::indirect_iterator<cfg_node_downcast_not_null_iter<T>, T> {\nprivate:\n  using xform_iterator = cfg_node_downcast_iter<T>;\n  using filter_iterator = cfg_node_downcast_not_null_iter<T>;\n  using parent = boost::indirect_iterator<filter_iterator, T>;\n\npublic:\n  cfg_node_cast_iter() : parent() {}\n\n  cfg_node_cast_iter(const CFG& g, CFG::vertex_iterator& first,\n                     CFG::vertex_iterator& last)\n      : parent(filter_iterator(xform_iterator(cfg_node_iter_base(g, first)),\n                               xform_iterator(cfg_node_iter_base(g, last)))) {}\n\n  template <typename OtherT>\n  cfg_node_cast_iter(const cfg_node_cast_iter<OtherT>& other) : parent(other) {}\n};\n\n/// @endcond\n\n/// \\ingroup CFG_GROUP\n/// \\brief Iterator over CfgNodes (\\ref CfgNode).\nusing cfg_iterator = boost::indirect_iterator<cfg_node_iter_base>;\n\n/// \\ingroup CFG_GROUP\n/// \\brief Const iterator over CfgNodes (\\ref CfgNode).\nusing const_cfg_iterator =\n    boost::indirect_iterator<cfg_node_iter_base, const CfgNode>;\n\n/// \\ingroup CFG_GROUP\n/// \\brief Iterator over blocks (\\ref Block).\nusing block_iterator = cfg_node_cast_iter<CodeBlock>;\n\n/// \\ingroup CFG_GROUP\n/// \\brief Constant iterator over blocks (\\ref Block).\nusing const_block_iterator = cfg_node_cast_iter<const CodeBlock>;\n\n/// \\ingroup CFG_GROUP\n/// \\brief Add a node to the CFG.\n///\n/// If the graph already contains the node, it is not modified.\n///\n/// \\param N    The CFG node to add.\n/// \\param Cfg  The graph to modify.\n///\n/// \\return A pair consisting of a descriptor to the vertex for that node and a\n/// \\c bool indicating whether the graph was modified.\nGTIRB_EXPORT_API std::pair<CFG::vertex_descriptor, bool> addVertex(CfgNode* B,\n                                                                   CFG& Cfg);\n\n/// \\ingroup CFG_GROUP\n/// \\brief Remove a node from the CFG.\n///\n/// If the graph does not contain the node, it is not modified.\n///\n/// \\param N    The CFG node to remove.\n/// \\param Cfg  The graph to modify.\n///\n/// \\return A \\c bool indicating whether the graph was modified.\nGTIRB_EXPORT_API bool removeVertex(CfgNode* N, CFG& Cfg);\n\n/// \\ingroup CFG_GROUP\n/// \\brief Get the boost::graph vertex descriptor for a CfgNode if it is in the\n/// graph.\n///\n/// \\param N    The node to query.\n/// \\param Cfg  The graph to query.\n///\n/// \\return A descriptor which can be used to retrieve the node from the graph.\nGTIRB_EXPORT_API std::optional<CFG::vertex_descriptor>\ngetVertex(const CfgNode* N, const CFG& Cfg);\n\n/// \\ingroup CFG_GROUP\n/// \\brief Create a new edge between two CFG nodes if they exist in the graph.\n///\n/// \\param Cfg   The graph to modify.\n/// \\param From  The source node.\n/// \\param To    The target node.\n///\n/// \\return A descriptor which can be used to retrieve the edge from the\n/// graph or assign a label. If either CFG node is not present in the graph,\n/// returns \\c std::nullopt instead.\nGTIRB_EXPORT_API std::optional<CFG::edge_descriptor>\naddEdge(const CfgNode* From, const CfgNode* To, CFG& Cfg);\n\n/// \\ingroup CFG_GROUP\n/// \\brief Remove all edges between the source and target nodes from the CFG.\n///\n/// If the graph does not contain any of these nodes, it is not modified.\n///\n/// \\param Cfg  The graph to modify.\n/// \\param From  The source node.\n/// \\param To    The target node.\n///\n/// \\return A \\c bool indicating whether the graph was modified.\nGTIRB_EXPORT_API bool removeEdge(const CfgNode* From, const CfgNode* To,\n                                 CFG& Cfg);\n\n/// \\ingroup CFG_GROUP\n/// \\brief Remove all edges with given label between the source and target nodes\n/// from the CFG.\n///\n/// If the graph does not contain any of these nodes, it is not modified.\n///\n/// \\param Cfg  The graph to modify.\n/// \\param From  The source node.\n/// \\param To    The target node.\n/// \\param Label The Edge label. Only edges with this label will be removed.\n///\n/// \\return A \\c bool indicating whether the graph was modified.\nGTIRB_EXPORT_API bool removeEdge(const CfgNode* From, const CfgNode* To,\n                                 EdgeLabel Label, CFG& Cfg);\n\n/// \\ingroup CFG_GROUP\n/// \\brief Get a range of the \\ref CfgNode elements in the specified graph.\n///\n/// \\param Cfg  The graph to be iterated over.\n///\n/// \\return a range over the \\p Cfg.\nGTIRB_EXPORT_API boost::iterator_range<cfg_iterator> nodes(CFG& Cfg);\n\n/// \\ingroup CFG_GROUP\n/// \\brief Get a constant range of the \\ref CfgNode elements in the specified\n/// graph.\n///\n/// \\param Cfg  The graph to be iterated over.\n///\n/// \\return A range over teh \\p Cfg.\nGTIRB_EXPORT_API boost::iterator_range<const_cfg_iterator>\nnodes(const CFG& Cfg);\n\n/// \\ingroup CFG_GROUP\n/// \\brief Get a range of just the \\ref Block elements in the specified graph.\n///\n/// The returned range will not include any \\ref ProxyBlocks. To retrieve those\n/// as well, use \\ref nodes(CFG&).\n///\n/// \\param Cfg  The graph to be iterated over.\n///\n/// \\return A range over the \\ref Blocks in the \\p Cfg\nGTIRB_EXPORT_API boost::iterator_range<block_iterator> blocks(CFG& Cfg);\n\n/// \\ingroup CFG_GROUP\n/// \\brief Get a constant range of just the \\ref Block elements in the specified\n/// graph.\n///\n/// The returned range will not include any \\ref ProxyBlocks. To retrieve those\n/// as well, use \\ref nodes(CFG&).\n///\n/// \\param Cfg  The graph to be iterated over.\n///\n/// \\return A range over the \\ref Blocks in the \\p Cfg\nGTIRB_EXPORT_API boost::iterator_range<const_block_iterator>\nblocks(const CFG& Cfg);\n\n/// @cond INTERNAL\n// Traits for instantiating cfgEdgeIters as cfgPredecessors.\nstruct CfgPredecessorTraits {\n  using edge_iterator = boost::graph_traits<CFG>::in_edge_iterator;\n  static CfgNode* getNode(const CFG::edge_descriptor& EDesc, const CFG& Cfg) {\n    return Cfg[source(EDesc, Cfg)];\n  }\n  static std::pair<edge_iterator, edge_iterator>\n  getEdges(const CFG::vertex_descriptor& VtxDescr, const CFG& Cfg) {\n    return in_edges(VtxDescr, Cfg);\n  }\n};\n/// @endcond\n\n/// @cond INTERNAL\n// Traits for instantiating cfgEdgeIters as cfgSuccessors.\nstruct CfgSuccessorTraits {\n  using edge_iterator = boost::graph_traits<CFG>::out_edge_iterator;\n  static CfgNode* getNode(const CFG::edge_descriptor& EDesc, const CFG& Cfg) {\n    return Cfg[target(EDesc, Cfg)];\n  }\n  static std::pair<edge_iterator, edge_iterator>\n  getEdges(const CFG::vertex_descriptor& VtxDescr, const CFG& Cfg) {\n    return out_edges(VtxDescr, Cfg);\n  }\n};\n/// @endcond\n\n/// @cond INTERNAL\n/// \\brief Convert a CFG edge_descriptor to a pair<[const] CfgNode*, EdgeLabel>.\n///\n/// \\tparam Traits     Controls edge direction (predecessor vs successor).\n/// \\tparam CfgNodePtr Specifies constness of the returned CfgNode.\ntemplate <class Traits, typename CfgNodePtr> struct EdgeDescrToNodeLabel {\n  // Yes, this stores a const CFG* even for the version that returns a\n  // non-const CfgNode.  We can do this because the constness of the two are\n  // actually independent, though we maintain the illusion of their related\n  // constness in the public interface functions cfgPredecessors and\n  // cfgSuccessors.\n  const CFG* Cfg = nullptr; // Should only be null for end iterator\n\n  EdgeDescrToNodeLabel() = default;\n  EdgeDescrToNodeLabel(const CFG* G) : Cfg(G) {}\n  // This quasi-copy constructor enables conversion from non-const iterator to\n  // const iterator, but not vice versa.\n  EdgeDescrToNodeLabel(const EdgeDescrToNodeLabel<Traits, CfgNode*>& Rhs)\n      : Cfg(Rhs.Cfg) {}\n\n  std::pair<CfgNodePtr, EdgeLabel>\n  operator()(const CFG::edge_descriptor& EDesc) const {\n    return {Traits::getNode(EDesc, *Cfg), (*Cfg)[EDesc]};\n  }\n};\n/// @endcond\n\n/// @cond INTERNAL\n/// \\brief Returns a iterator_range to iterate the predecessors or successors\n/// of a \\ref CfgNode.\n///\n/// This template method is instantiated as cfgPredecessors and cfgSuccessors\n/// for iterating CFG predecessor and successor edges respectively from a given\n/// node.  The underlying iterator's value_type (type returned by dereference\n/// operator*) is a pair<[const] CfgNode*, EdgeLabel>.\n///\n/// \\tparam Traits     Controls edge direction (predecessor vs successor).\n/// \\tparam CfgNodePtr Specifies constness of the returned CfgNode.\n/// \\param G  The \\ref CFG containing N.\n/// \\param N  The \\ref CfgNode whose edges will be iterated.\n/// \\return A range over \\p N's predecessors or successors.\ntemplate <class Traits, typename CfgNodePtr>\nauto cfgEdgeIters(const CFG& G, const CfgNode* N) {\n  const std::optional<CFG::vertex_descriptor> OptVtxDescr = getVertex(N, G);\n  if (OptVtxDescr == std::nullopt) {\n    // FYI: this is the return type\n    return boost::iterator_range<\n        boost::transform_iterator<EdgeDescrToNodeLabel<Traits, CfgNodePtr>,\n                                  typename Traits::edge_iterator>>();\n  } else {\n    const auto [Begin, End] = Traits::getEdges(OptVtxDescr.value(), G);\n    return boost::make_iterator_range(\n        boost::make_transform_iterator(\n            Begin, EdgeDescrToNodeLabel<Traits, CfgNodePtr>{&G}),\n        boost::make_transform_iterator(\n            End, EdgeDescrToNodeLabel<Traits, CfgNodePtr>{&G}));\n  }\n}\n/// @endcond\n\n/// \\brief iterator_range over a CfgNode's predecessors, non-const version\nusing cfg_predecessors_range = boost::iterator_range<boost::transform_iterator<\n    EdgeDescrToNodeLabel<CfgPredecessorTraits, CfgNode*>,\n    CfgPredecessorTraits::edge_iterator>>;\n/// \\brief iterator_range over a CfgNode's predecessors, const version\nusing const_cfg_predecessors_range =\n    boost::iterator_range<boost::transform_iterator<\n        EdgeDescrToNodeLabel<CfgPredecessorTraits, const CfgNode*>,\n        CfgPredecessorTraits::edge_iterator>>;\n/// \\brief iterator_range over a CfgNode's successors, non-const version\nusing cfg_successors_range = boost::iterator_range<boost::transform_iterator<\n    EdgeDescrToNodeLabel<CfgSuccessorTraits, CfgNode*>,\n    CfgSuccessorTraits::edge_iterator>>;\n/// \\brief iterator_range over a CfgNode's successors, const version\nusing const_cfg_successors_range =\n    boost::iterator_range<boost::transform_iterator<\n        EdgeDescrToNodeLabel<CfgSuccessorTraits, const CfgNode*>,\n        CfgSuccessorTraits::edge_iterator>>;\n\n/// \\ingroup CFG_GROUP\n/// \\brief Returns an iterator_range to iterate the predecessors\n/// of a \\ref CfgNode.\n///\n/// To iterate the predecessors of node N in graph G:\n/// \\code\n/// for (auto [PredNode, EdgeLabel] : gtirb::cfgPredecessors(G, N)) { ... }\n/// \\endcode\n///\n/// \\param G  The \\ref CFG containing N.\n/// \\param N  The \\ref CfgNode whose predecessors will be iterated.\n/// \\return A range over \\p N's predecessors.\ninline cfg_predecessors_range cfgPredecessors(CFG& G, const CfgNode* N) {\n  return cfgEdgeIters<CfgPredecessorTraits, CfgNode*>(G, N);\n}\ninline const_cfg_predecessors_range cfgPredecessors(const CFG& G,\n                                                    const CfgNode* N) {\n  return cfgEdgeIters<CfgPredecessorTraits, const CfgNode*>(G, N);\n}\n\n/// \\ingroup CFG_GROUP\n/// \\brief Returns an iterator_range to iterate the successors\n/// of a \\ref CfgNode.\n///\n/// To iterate the successors of node N in graph G:\n/// \\code\n/// for (auto [SuccNode, EdgeLabel] : gtirb::cfgSuccessors(G, N)) { ... }\n/// \\endcode\n///\n/// \\param G  The \\ref CFG containing N.\n/// \\param N  The \\ref CfgNode whose successors will be iterated.\n/// \\return A range over \\p N's successors.\ninline cfg_successors_range cfgSuccessors(CFG& G, const CfgNode* N) {\n  return cfgEdgeIters<CfgSuccessorTraits, CfgNode*>(G, N);\n}\ninline const_cfg_successors_range cfgSuccessors(const CFG& G,\n                                                const CfgNode* N) {\n  return cfgEdgeIters<CfgSuccessorTraits, const CfgNode*>(G, N);\n}\n\n} // namespace gtirb\n#endif // GTIRB_CFG_H\n"
  },
  {
    "path": "include/gtirb/Casting.hpp",
    "content": "//===- Casting.hpp ----------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===-Addition License Information-----------------------------------------===//\n//\n// This file was initially written for the LLVM Compiler Infrastructure\n// project where it is distributed under the University of Illinois Open Source\n// License. See the LICENSE file in the project root for license terms.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_CASTING_H\n#define GTIRB_CASTING_H\n\n#include <cassert>\n#include <type_traits>\n\n/// @cond INTERNAL\n#ifndef GTIRB_WRAP_UTILS_IN_NAMESPACE\n#define GTIRB_DEPRECATED_UTILS                                                 \\\n  [[deprecated(\"Define GTIRB_WRAP_UTILS_IN_NAMESPACE and access via the \"      \\\n               \"gtirb namespace to suppress this error.\")]]\n#else\n#define GTIRB_DEPRECATED_UTILS\n#endif\n/// @endcond\n\nnamespace gtirb {\n\n// We want clients to use the names in the gtirb namespace, so we exclude\n// the allocator namespace when generating documentation.\n/// @cond INTERNAL\nnamespace casting {\n/// @endcond\n\n/// \\file Casting.hpp\n/// \\ingroup casting\n/// \\brief The various casting and type checking operations that apply\n/// to gtirb::Node subclasses.\n///\n/// \\see \\ref casting.\n\n/// \\defgroup casting Casting\n///\n/// \\brief \\ref gtirb::Node \"Node\" and its subclasses support custom casting\n/// machinery that allows for type checking, safer static casting, and\n/// safe dynamic casting without needing the overhead of a vtable or\n/// RTTI.\n///\n/// File Casting.hpp defines the various operations that apply\n/// to \\ref gtirb::Node \"Node\" subclasses.\n/// - \\ref ISA \"isa<Ty>\" Performs a type check.\n/// - \\ref CAST \"cast<Ty>\" Returns the given argument cast to the\n///   specified type;  the argument cannot be null.\n/// - \\ref CAST_OR_NULL \"cast_or_null<Ty>\" Returns the given argument\n///   cast to the specified type; the argument can be null.\n/// - \\ref DYN_CAST \"dyn_cast<Ty>\" Returns the given argument cast to\n///   the specified type, or null if the casting operation fails\n///   because the types do not match; the argument cannot be null.\n/// - \\ref DYN_CAST_OR_NULL \"dyn_cast_or_null<Ty>\" Returns the given\n///   argument cast to the specified type, or null if the casting\n///   operation fails because the types do not match; the argument can\n///   be null.\n///\n/// \\section casting_operations Casting Operations\n///\n/// \\subsection ISA isa<Ty>\n///\n/// Perform a type check.\n///\n/// \\param Val The object to check. Cannot be null.\n///\n/// \\return \\c true if \\p Val is an instance of the template parameter\n/// type, \\c false otherwise.\n///\n/// - isa<Ty>(const Y& Val)\n///\n/// Example usage:\n/// \\code\n/// void f(Node *N) { if (isa<Block>(N) { ... } }\n/// \\endcode\n///\n/// (Deprecated) Available in the global namespace when\n/// GTIRB_WRAP_UTILS_IN_NAMESPACE is enabled.\n///\n///\n/// \\subsection CAST cast<Ty>\n///\n/// Cast to the specified type; the argument cannot be null.\n///\n/// \\param Val the value to cast. Cannot be null; consider using\n/// \\ref CAST_OR_NULL \"cast_or_null<Ty>\" in that case.\n///\n/// \\return The result of casting \\p Val to the specified type.\n///   This function asserts that the types match and will not return\n///   null on failure.\n///\n/// - cast<Ty>(Y* Val)\n/// - cast<Ty>(Y& Val)\n/// - cast<Ty>(const Y& Val)\n///\n/// Example usage:\n/// \\code\n/// void f(Node * N) { auto *B = cast<Block>(N); }\n/// \\endcode\n///\n/// (Deprecated) Available in the global namespace when\n/// GTIRB_WRAP_UTILS_IN_NAMESPACE is enabled.\n///\n/// \\subsection CAST_OR_NULL cast_or_null<Ty>\n///\n/// Cast to the specified type; the argument can be null.\n///\n/// \\param Val the value to cast. Can be null.\n///\n/// \\return The result of casting \\p Val to the specified type.\n///   This function asserts that the types match and will not return\n///   null on failure. If \\p Val is null, returns a null pointer cast\n///   to the given type.\n///\n/// - cast_or_null<Ty>(Y* Val)\n/// - cast_or_null<Ty>(Y& Val)\n/// - cast_or_null<Ty>(const Y& Val)\n///\n/// Example usage:\n/// \\code\n///  void f(Node *N) { auto *B = cast_or_null<Block>(N); }\n/// \\endcode\n///\n/// (Deprecated) Available in the global namespace when\n/// GTIRB_WRAP_UTILS_IN_NAMESPACE is enabled.\n///\n/// \\subsection  DYN_CAST dyn_cast<Ty>\n///\n/// Dynamic cast to the specified type; the argument cannot be null.\n///\n/// \\param Val the value to cast. Cannot be null; consider using\n/// \\ref DYN_CAST_OR_NULL \"dyn_cast_or_null<Ty>\" in that case.\n///\n/// \\return The result of casting \\p Val to the specified type, or\n/// null if the casting operation fails because the types do not\n/// match.\n///\n/// - dyn_cast<Ty>(Y* Val)\n/// - dyn_cast<Ty>(Y& Val)\n/// - dyn_cast<Ty>(const Y& Val)\n///\n/// Example usage:\n/// \\code\n/// void f(Node * N) { auto *B = dyn_cast<Block>(N); }\n/// \\endcode\n///\n/// (Deprecated) Available in the global namespace when\n/// GTIRB_WRAP_UTILS_IN_NAMESPACE is enabled.\n///\n/// \\subsection DYN_CAST_OR_NULL dyn_cast_or_null<Ty>\n///\n/// Cast to the specified type; the argument can be null.\n///\n/// \\param Val the value to cast. Can be null.\n///\n/// \\return The result of casting \\p Val to the specified type, or\n/// null if the casting operation fails because the types do not\n/// match. If \\p Val is null, returns a null pointer cast to the given\n/// type.\n///\n/// - dyn_cast_or_null<Ty>(Y* Val)\n/// - dyn_cast_or_null<Ty>(Y& Val)\n/// - dyn_cast_or_null<Ty>(const Y& Val)\n///\n/// Example usage:\n/// \\code\n/// void f(Node *N) { auto *B = dyn_cast_or_null<Block>(N); }\n/// \\endcode\n///\n/// (Deprecated) Available in the global namespace when\n/// GTIRB_WRAP_UTILS_IN_NAMESPACE is enabled.\n///\n/// @{ @}\n\n/// \\fn isa(const Y& Val)\n/// See \\ref ISA.\n\n/// \\fn cast(Y* Val)\n/// See \\ref CAST.\n\n/// \\fn cast(Y& Val)\n/// See \\ref CAST.\n\n/// \\fn cast(const Y& Val)\n/// See \\ref CAST.\n\n/// \\fn cast_or_null(Y* Val)\n/// See \\ref CAST_OR_NULL.\n\n/// \\fn cast_or_null(Y& Val)\n/// See \\ref CAST_OR_NULL.\n\n/// \\fn cast_or_null(const Y& Val)\n/// See \\ref CAST_OR_NULL.\n\n/// \\fn dyn_cast(Y* Val)\n/// See \\ref DYN_CAST.\n\n/// \\fn dyn_cast(Y& Val)\n/// See \\ref DYN_CAST.\n\n/// \\fn dyn_cast(const Y& Val)\n/// See \\ref DYN_CAST.\n\n/// \\fn dyn_cast_or_null(Y* Val)\n/// See \\ref DYN_CAST_OR_NULL.\n\n/// \\fn dyn_cast_or_null(Y& Val)\n/// See \\ref DYN_CAST_OR_NULL.\n\n/// \\fn dyn_cast_or_null(const Y& Val)\n/// See \\ref DYN_CAST_OR_NULL.\n\n//===----------------------------------------------------------------------===//\n//                          isa<x> Support Templates\n//===----------------------------------------------------------------------===//\n\n/// @cond INTERNAL\n// Define a template that can be specialized by smart pointers to reflect the\n// fact that they are automatically dereferenced, and are not involved with the\n// template selection process...  the default implementation is a noop.\n//\ntemplate <typename From> struct simplify_type {\n  using SimpleType = From; // The real type this represents...\n\n  // An accessor to get the real value...\n  static SimpleType& getSimplifiedValue(From& Val) { return Val; }\n};\n/// @endcond\n\n/// @cond INTERNAL\n// The core of the implementation of isa<X> is here; To and From should be\n// the names of classes.  This template can be specialized to customize the\n// implementation of isa<> without rewriting it from scratch.\ntemplate <typename To, typename From, typename Enabler = void> struct isa_impl {\n  static inline bool doit(const From& Val) { return To::classof(&Val); }\n};\n/// @endcond\n\n/// @cond INTERNAL\n// Always allow upcasts, and perform no dynamic check for them.\ntemplate <typename To, typename From>\nstruct isa_impl<\n    To, From, typename std::enable_if<std::is_base_of<To, From>::value>::type> {\n  static inline bool doit(const From&) { return true; }\n};\n/// @endcond\n\n/// @cond INTERNAL\ntemplate <typename To, typename From> struct isa_impl_cl {\n  static inline bool doit(const From& Val) {\n    return isa_impl<To, From>::doit(Val);\n  }\n};\n/// @endcond\n\n/// @cond  INTERNAL\ntemplate <typename To, typename From> struct isa_impl_cl<To, const From> {\n  static inline bool doit(const From& Val) {\n    return isa_impl<To, From>::doit(Val);\n  }\n};\n/// @endcond\n\n/// @cond INTERNAL\ntemplate <typename To, typename From> struct isa_impl_cl<To, From*> {\n  static inline bool doit(const From* Val) {\n    assert(Val && \"isa<> used on a null pointer\");\n    return isa_impl<To, From>::doit(*Val);\n  }\n};\n/// @endcond\n\n/// @cond INTERNAL\ntemplate <typename To, typename From> struct isa_impl_cl<To, From* const> {\n  static inline bool doit(const From* Val) {\n    assert(Val && \"isa<> used on a null pointer\");\n    return isa_impl<To, From>::doit(*Val);\n  }\n};\n/// @endcond\n\n/// @cond INTERNAL\ntemplate <typename To, typename From> struct isa_impl_cl<To, const From*> {\n  static inline bool doit(const From* Val) {\n    assert(Val && \"isa<> used on a null pointer\");\n    return isa_impl<To, From>::doit(*Val);\n  }\n};\n/// @endcond\n\n/// @cond INTERNAL\ntemplate <typename To, typename From>\nstruct isa_impl_cl<To, const From* const> {\n  static inline bool doit(const From* Val) {\n    assert(Val && \"isa<> used on a null pointer\");\n    return isa_impl<To, From>::doit(*Val);\n  }\n};\n/// @endcond\n\n/// @cond INTERNAL\ntemplate <typename To, typename From, typename SimpleFrom>\nstruct isa_impl_wrap {\n  // When From != SimplifiedType, we can simplify the type some more by using\n  // the simplify_type template.\n  static bool doit(const From& Val) {\n    return isa_impl_wrap<To, SimpleFrom,\n                         typename simplify_type<SimpleFrom>::SimpleType>::\n        doit(simplify_type<const From>::getSimplifiedValue(Val));\n  }\n};\n/// @endcond\n\n/// @cond INTERNAL\ntemplate <typename To, typename FromTy>\nstruct isa_impl_wrap<To, FromTy, FromTy> {\n  // When From == SimpleType, we are as simple as we are going to get.\n  static bool doit(const FromTy& Val) {\n    return isa_impl_cl<To, FromTy>::doit(Val);\n  }\n};\n/// @endcond\n\n// isa<X> - Return true if the parameter to the template is an instance of the\n// template type argument.  Used like this:\n//\n//  if (isa<Type>(myVal)) { ... }\n//\ntemplate <class X, class Y>\nGTIRB_DEPRECATED_UTILS [[nodiscard]] inline bool isa(const Y& Val) {\n  return isa_impl_wrap<X, const Y,\n                       typename simplify_type<const Y>::SimpleType>::doit(Val);\n}\n\n//===----------------------------------------------------------------------===//\n//                          cast<x> Support Templates\n//===----------------------------------------------------------------------===//\n/// @cond INTERNAL\ntemplate <class To, class From> struct cast_retty;\n/// @endcond\n\n/// @cond INTERNAL\n// Calculate what type the 'cast' function should return, based on a requested\n// type of To and a source type of From.\ntemplate <class To, class From> struct cast_retty_impl {\n  using ret_type = To&; // Normal case, return Ty&\n};\ntemplate <class To, class From> struct cast_retty_impl<To, const From> {\n  using ret_type = const To&; // Normal case, return Ty&\n};\n\ntemplate <class To, class From> struct cast_retty_impl<To, From*> {\n  using ret_type = To*; // Pointer arg case, return Ty*\n};\n\ntemplate <class To, class From> struct cast_retty_impl<To, const From*> {\n  using ret_type = const To*; // Constant pointer arg case, return const Ty*\n};\n\ntemplate <class To, class From> struct cast_retty_impl<To, const From* const> {\n  using ret_type = const To*; // Constant pointer arg case, return const Ty*\n};\n/// @endcond\n\n/// @cond INTERNAL\ntemplate <class To, class From, class SimpleFrom> struct cast_retty_wrap {\n  // When the simplified type and the from type are not the same, use the type\n  // simplifier to reduce the type, then reuse cast_retty_impl to get the\n  // resultant type.\n  using ret_type = typename cast_retty<To, SimpleFrom>::ret_type;\n};\n\ntemplate <class To, class FromTy> struct cast_retty_wrap<To, FromTy, FromTy> {\n  // When the simplified type is equal to the from type, use it directly.\n  using ret_type = typename cast_retty_impl<To, FromTy>::ret_type;\n};\n\ntemplate <class To, class From> struct cast_retty {\n  using ret_type = typename cast_retty_wrap<\n      To, From, typename simplify_type<From>::SimpleType>::ret_type;\n};\n/// @endcond\n\n/// @cond INTERNAL\n// Ensure the non-simple values are converted using the simplify_type template\n// that may be specialized by smart pointers...\n//\ntemplate <class To, class From, class SimpleFrom> struct cast_convert_val {\n  // This is not a simple type, use the template to simplify it...\n  static typename cast_retty<To, From>::ret_type doit(From& Val) {\n    return cast_convert_val<To, SimpleFrom,\n                            typename simplify_type<SimpleFrom>::SimpleType>::\n        doit(simplify_type<From>::getSimplifiedValue(Val));\n  }\n};\n\ntemplate <class To, class FromTy> struct cast_convert_val<To, FromTy, FromTy> {\n  // This _is_ a simple type, just cast it.\n  static typename cast_retty<To, FromTy>::ret_type doit(const FromTy& Val) {\n    typename cast_retty<To, FromTy>::ret_type Res2 =\n        (typename cast_retty<To, FromTy>::ret_type) const_cast<FromTy&>(Val);\n    return Res2;\n  }\n};\n/// @endcond\n\n/// @cond INTERNAL\ntemplate <class X> struct is_simple_type {\n  static const bool value =\n      std::is_same<X, typename simplify_type<X>::SimpleType>::value;\n};\n/// @endcond\n\n// cast<X> - Return the argument parameter cast to the specified type.  This\n// casting operator asserts that the type is correct, so it does not return null\n// on failure.  It does not allow a null argument (use cast_or_null for that).\n// It is typically used like this:\n//\n//  cast<Instruction>(myVal)->getParent()\n//\ntemplate <class X, class Y>\nGTIRB_DEPRECATED_UTILS inline\n    typename std::enable_if<!is_simple_type<Y>::value,\n                            typename cast_retty<X, const Y>::ret_type>::type\n    cast(const Y& Val) {\n  assert(isa<X>(Val) && \"cast<Ty>() argument of incompatible type!\");\n  return cast_convert_val<\n      X, const Y, typename simplify_type<const Y>::SimpleType>::doit(Val);\n}\n\ntemplate <class X, class Y>\nGTIRB_DEPRECATED_UTILS inline typename cast_retty<X, Y>::ret_type cast(Y& Val) {\n  assert(isa<X>(Val) && \"cast<Ty>() argument of incompatible type!\");\n  return cast_convert_val<X, Y, typename simplify_type<Y>::SimpleType>::doit(\n      Val);\n}\n\ntemplate <class X, class Y>\nGTIRB_DEPRECATED_UTILS inline typename cast_retty<X, Y*>::ret_type\ncast(Y* Val) {\n  assert(isa<X>(Val) && \"cast<Ty>() argument of incompatible type!\");\n  return cast_convert_val<X, Y*, typename simplify_type<Y*>::SimpleType>::doit(\n      Val);\n}\n\n// cast_or_null<X> - Functionally identical to cast, except that a null value is\n// accepted.\n//\ntemplate <class X, class Y>\nGTIRB_DEPRECATED_UTILS [[nodiscard]] inline\n    typename std::enable_if<!is_simple_type<Y>::value,\n                            typename cast_retty<X, const Y>::ret_type>::type\n    cast_or_null(const Y& Val) {\n  if (!Val)\n    return nullptr;\n  assert(isa<X>(Val) && \"cast_or_null<Ty>() argument of incompatible type!\");\n  return cast<X>(Val);\n}\n\ntemplate <class X, class Y>\nGTIRB_DEPRECATED_UTILS [[nodiscard]] inline\n    typename std::enable_if<!is_simple_type<Y>::value,\n                            typename cast_retty<X, Y>::ret_type>::type\n    cast_or_null(Y& Val) {\n  if (!Val)\n    return nullptr;\n  assert(isa<X>(Val) && \"cast_or_null<Ty>() argument of incompatible type!\");\n  return cast<X>(Val);\n}\n\ntemplate <class X, class Y>\nGTIRB_DEPRECATED_UTILS [[nodiscard]] inline typename cast_retty<X, Y*>::ret_type\ncast_or_null(Y* Val) {\n  if (!Val)\n    return nullptr;\n  assert(isa<X>(Val) && \"cast_or_null<Ty>() argument of incompatible type!\");\n  return cast<X>(Val);\n}\n\n// dyn_cast<X> - Return the argument parameter cast to the specified type.  This\n// casting operator returns null if the argument is of the wrong type, so it can\n// be used to test for a type as well as cast if successful.  This should be\n// used in the context of an if statement like this:\n//\n//  if (const Instruction *I = dyn_cast<Instruction>(myVal)) { ... }\n//\n\ntemplate <class X, class Y>\nGTIRB_DEPRECATED_UTILS [[nodiscard]] inline\n    typename std::enable_if<!is_simple_type<Y>::value,\n                            typename cast_retty<X, const Y>::ret_type>::type\n    dyn_cast(const Y& Val) {\n  return isa<X>(Val) ? cast<X>(Val) : nullptr;\n}\n\ntemplate <class X, class Y>\nGTIRB_DEPRECATED_UTILS [[nodiscard]] inline typename cast_retty<X, Y>::ret_type\ndyn_cast(Y& Val) {\n  return isa<X>(Val) ? cast<X>(Val) : nullptr;\n}\n\ntemplate <class X, class Y>\nGTIRB_DEPRECATED_UTILS [[nodiscard]] inline typename cast_retty<X, Y*>::ret_type\ndyn_cast(Y* Val) {\n  return isa<X>(Val) ? cast<X>(Val) : nullptr;\n}\n\n// dyn_cast_or_null<X> - Functionally identical to dyn_cast, except that a null\n// value is accepted.\n//\ntemplate <class X, class Y>\nGTIRB_DEPRECATED_UTILS [[nodiscard]] inline\n    typename std::enable_if<!is_simple_type<Y>::value,\n                            typename cast_retty<X, const Y>::ret_type>::type\n    dyn_cast_or_null(const Y& Val) {\n  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;\n}\n\ntemplate <class X, class Y>\nGTIRB_DEPRECATED_UTILS [[nodiscard]] inline\n    typename std::enable_if<!is_simple_type<Y>::value,\n                            typename cast_retty<X, Y>::ret_type>::type\n    dyn_cast_or_null(Y& Val) {\n  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;\n}\n\ntemplate <class X, class Y>\nGTIRB_DEPRECATED_UTILS [[nodiscard]] inline typename cast_retty<X, Y*>::ret_type\ndyn_cast_or_null(Y* Val) {\n  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;\n}\n\n/// @cond INTERNAL\n} // namespace casting\n/// @endcond\n\n#ifdef GTIRB_WRAP_UTILS_IN_NAMESPACE\n\nusing casting::cast;\nusing casting::cast_or_null;\nusing casting::dyn_cast;\nusing casting::dyn_cast_or_null;\nusing casting::isa;\n\n#endif // GTIRB_WRAP_UTILS_IN_NAMESPACE\n\n} // namespace gtirb\n\n#ifndef GTIRB_WRAP_UTILS_IN_NAMESPACE\n\nusing gtirb::casting::cast;\nusing gtirb::casting::cast_or_null;\nusing gtirb::casting::dyn_cast;\nusing gtirb::casting::dyn_cast_or_null;\nusing gtirb::casting::isa;\n\n#endif // GTIRB_WRAP_UTILS_IN_NAMESPACE\n\n#endif // GTIRB_CASTING_H\n"
  },
  {
    "path": "include/gtirb/CfgNode.hpp",
    "content": "//===- CfgNode.hpp -----------------------------------------------*- C++-*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_CFG_NODE_HPP\n#define GTIRB_CFG_NODE_HPP\n\n#include <gtirb/Node.hpp>\n\n/// \\file CfgNode.hpp\n/// \\ingroup CFG_GROUP\n/// \\brief Base class for nodes of the CFG.\n/// \\see CFG_GROUP\n\nnamespace gtirb {\n\n/// \\class CfgNode\n///\n/// \\brief Represents the base of types that can be inserted into the CFG.\nclass GTIRB_EXPORT_API CfgNode : public Node {\npublic:\n  /// \\cond INTERNAL\n  static bool classof(const Node* N) { return classofKind(N->getKind()); }\n  static bool classofKind(Kind K) {\n    return K >= Kind::CfgNode && K <= Kind::LAST_CfgNode;\n  }\n  /// \\endcond\nprotected:\n  CfgNode(Context& C, Kind Knd) : Node(C, Knd) {}\n  CfgNode(Context& C, Kind Knd, const UUID& U) : Node(C, Knd, U) {}\n};\n\n} // namespace gtirb\n#endif // GTIRB_CFG_NODE_HPP\n"
  },
  {
    "path": "include/gtirb/CodeBlock.hpp",
    "content": "//===- CodeBlock.hpp ---------------------------------------------*- C++-*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_BLOCK_H\n#define GTIRB_BLOCK_H\n\n#include <gtirb/Addr.hpp>\n#include <gtirb/ByteInterval.hpp>\n#include <gtirb/CfgNode.hpp>\n#include <gtirb/DecodeMode.hpp>\n#include <gtirb/Export.hpp>\n#include <gtirb/Node.hpp>\n#include <gtirb/proto/CodeBlock.pb.h>\n#include <boost/range/iterator_range.hpp>\n#include <cstdint>\n#include <functional>\n#include <optional>\n#include <vector>\n\n/// \\file CodeBlock.hpp\n/// \\ingroup CFG_GROUP\n/// \\brief Class gtirb::CodeBlock.\n/// \\see CFG_GROUP\n\nnamespace gtirb {\ntemplate <class T> class ErrorOr;\n\nnamespace proto {\nclass CodeBlock;\n} // namespace proto\n\n/// \\class CodeBlock\n///\n/// \\brief A basic block.\n/// \\see \\ref CFG_GROUP\nclass GTIRB_EXPORT_API CodeBlock : public CfgNode {\npublic:\n  /// \\brief Create an unitialized CodeBlock object.\n  /// \\param C        The Context in which this CodeBlock will be held.\n  /// \\return         The newly created CodeBlock.\n  static CodeBlock* Create(Context& C) { return C.Create<CodeBlock>(C); }\n\n  /// \\brief Create a CodeBlock object.\n  ///\n  /// \\param C          The Context in which this block will be held.\n  /// \\param Size       The size of the block in bytes.\n  /// \\param DMode      The decode mode of the block.\n  ///\n  /// \\return The newly created CodeBlock.\n  static CodeBlock* Create(Context& C, uint64_t Size,\n                           gtirb::DecodeMode DMode = DecodeMode::Default) {\n    return C.Create<CodeBlock>(C, Size, DMode);\n  }\n\n  /// \\brief Get the \\ref ByteInterval this block belongs to.\n  ByteInterval* getByteInterval() { return Parent; }\n  /// \\brief Get the \\ref ByteInterval this block belongs to.\n  const ByteInterval* getByteInterval() const { return Parent; }\n\n  /// \\brief Get the size from a \\ref CodeBlock.\n  ///\n  /// \\return The size in bytes.\n  ///\n  /// Use with CodeBlock::getAddress() to obtain arguments to pass to\n  /// ByteMap::data() for an iterator over the contents of a \\ref CodeBlock.\n  uint64_t getSize() const { return Size; }\n\n  /// \\brief Get the decode mode from a \\ref CodeBlock.\n  ///\n  /// This field is used in some ISAs where it is used to\n  /// differentiate between sub-ISAs; ARM and Thumb, for example.\n  ///\n  /// \\return The decode mode.\n  gtirb::DecodeMode getDecodeMode() const { return this->DecodeMode; }\n\n  /// \\brief Get the offset from the beginning of the \\ref ByteInterval this\n  /// block belongs to.\n  uint64_t getOffset() const;\n\n  /// \\brief Get the address of this block, if present. See \\ref\n  /// ByteInterval.getAddress for details on why this address may not be\n  /// present.\n  std::optional<Addr> getAddress() const;\n\n  /// \\brief Set the size of this block.\n  ///\n  /// Note that this does not automatically update any \\ref ByteInterval's size,\n  /// bytes, or symbolic expressions. This simply changes the extents of a block\n  /// in its \\ref ByteInterval.\n  void setSize(uint64_t S) {\n    if (Observer) {\n      std::swap(Size, S);\n      [[maybe_unused]] ChangeStatus Status =\n          Observer->sizeChange(this, S, Size);\n      assert(Status != ChangeStatus::Rejected &&\n             \"recovering from rejected size change is not implemented yet\");\n    } else {\n      Size = S;\n    }\n  }\n\n  /// \\brief Set the decode mode of this block.\n  ///\n  /// This field is used in some ISAs where it is used to\n  /// differentiate between sub-ISAs; ARM and Thumb, for example.\n  void setDecodeMode(gtirb::DecodeMode DM) {\n    if (Observer) {\n      std::swap(DecodeMode, DM);\n      [[maybe_unused]] ChangeStatus Status =\n          Observer->decodeModeChange(this, DM, DecodeMode);\n      assert(\n          Status != ChangeStatus::Rejected &&\n          \"recovering from rejected decode mode change is not implemented yet\");\n    } else {\n      DecodeMode = DM;\n    }\n  }\n\n  /// \\brief Iterator over bytes in this block.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> using bytes_iterator = ByteInterval::bytes_iterator<T>;\n  /// \\brief Range over bytes in this block.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> using bytes_range = ByteInterval::bytes_range<T>;\n  /// \\brief Const iterator over bytes in this block.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T>\n  using const_bytes_iterator = ByteInterval::const_bytes_iterator<T>;\n  /// \\brief Const range over bytes in this block.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T>\n  using const_bytes_range = ByteInterval::const_bytes_range<T>;\n\n  /// \\brief Get an iterator to the first byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> bytes_iterator<T> bytes_begin() {\n    assert(Parent && \"Block has no byte interval!\");\n    return bytes_begin<T>(Parent->getBoostEndianOrder());\n  }\n\n  /// \\brief Get an iterator to the first byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the block.\n  /// \\param  OutputOrder The endianness you wish to read out from the block.\n  template <typename T>\n  bytes_iterator<T>\n  bytes_begin(boost::endian::order InputOrder,\n              boost::endian::order OutputOrder = boost::endian::order::native) {\n    assert(Parent && \"Block has no byte interval!\");\n    return Parent->bytes_begin<T>(InputOrder, OutputOrder) + getOffset();\n  }\n\n  /// \\brief Get an iterator past the last byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> bytes_iterator<T> bytes_end() {\n    assert(Parent && \"Block has no byte interval!\");\n    return bytes_end<T>(Parent->getBoostEndianOrder());\n  }\n\n  /// \\brief Get an iterator past the last byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the block.\n  /// \\param  OutputOrder The endianness you wish to read out from the block.\n  template <typename T>\n  bytes_iterator<T>\n  bytes_end(boost::endian::order InputOrder,\n            boost::endian::order OutputOrder = boost::endian::order::native) {\n    assert(Parent && \"Block has no byte interval!\");\n    return Parent->bytes_begin<T>(InputOrder, OutputOrder) + getOffset() + Size;\n  }\n\n  /// \\brief Get a range of the bytes in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> bytes_range<T> bytes() {\n    assert(Parent && \"Block has no byte interval!\");\n    return bytes<T>(Parent->getBoostEndianOrder());\n  }\n\n  /// \\brief Get a range of the bytes in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the block.\n  /// \\param  OutputOrder The endianness you wish to read out from the block.\n  template <typename T>\n  bytes_range<T>\n  bytes(boost::endian::order InputOrder,\n        boost::endian::order OutputOrder = boost::endian::order::native) {\n    assert(Parent && \"Block has no byte interval!\");\n    return bytes_range<T>(bytes_begin<T>(InputOrder, OutputOrder),\n                          bytes_end<T>(InputOrder, OutputOrder));\n  }\n\n  /// \\brief Get an iterator to the first byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> const_bytes_iterator<T> bytes_begin() const {\n    assert(Parent && \"Block has no byte interval!\");\n    return bytes_begin<T>(Parent->getBoostEndianOrder());\n  }\n\n  /// \\brief Get an iterator to the first byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the block.\n  /// \\param  OutputOrder The endianness you wish to read out from the block.\n  template <typename T>\n  const_bytes_iterator<T> bytes_begin(\n      boost::endian::order InputOrder,\n      boost::endian::order OutputOrder = boost::endian::order::native) const {\n    assert(Parent && \"Block has no byte interval!\");\n    return Parent->bytes_begin<T>(InputOrder, OutputOrder) + getOffset();\n  }\n\n  /// \\brief Get an iterator past the last byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> const_bytes_iterator<T> bytes_end() const {\n    assert(Parent && \"Block has no byte interval!\");\n    return bytes_end<T>(Parent->getBoostEndianOrder());\n  }\n\n  /// \\brief Get an iterator past the last byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the block.\n  /// \\param  OutputOrder The endianness you wish to read out from the block.\n  template <typename T>\n  const_bytes_iterator<T> bytes_end(\n      boost::endian::order InputOrder,\n      boost::endian::order OutputOrder = boost::endian::order::native) const {\n    assert(Parent && \"Block has no byte interval!\");\n    return Parent->bytes_begin<T>(InputOrder, OutputOrder) + getOffset() + Size;\n  }\n\n  /// \\brief Get a range of the bytes in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> const_bytes_range<T> bytes() const {\n    assert(Parent && \"Block has no byte interval!\");\n    return bytes<T>(Parent->getBoostEndianOrder());\n  }\n\n  /// \\brief Get a range of the bytes in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the block.\n  /// \\param  OutputOrder The endianness you wish to read out from the block.\n  template <typename T>\n  const_bytes_range<T>\n  bytes(boost::endian::order InputOrder,\n        boost::endian::order OutputOrder = boost::endian::order::native) const {\n    assert(Parent && \"Block has no byte interval!\");\n    return const_bytes_range<T>(bytes_begin<T>(InputOrder, OutputOrder),\n                                bytes_end<T>(InputOrder, OutputOrder));\n  }\n\n  /// \\brief Return the raw data underlying this block's byte vector.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// Much like \\ref std::vector::data, this function is low-level and\n  /// potentially unsafe. This pointer refers to valid memory only where an\n  /// iterator would be valid to point to. Modifying the size of the byte\n  /// vector may invalidate this pointer. Any endian conversions will not be\n  /// performed.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type.\n  ///\n  /// \\retrurn A pointer to raw data.\n  template <typename T> T* rawBytes() {\n    assert(Parent && \"Block has no byte interval!\");\n    return reinterpret_cast<T*>(Parent->rawBytes<uint8_t>() + getOffset());\n  }\n\n  /// \\brief Return the raw data underlying this block's byte vector.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// Much like \\ref std::vector::data, this function is low-level and\n  /// potentially unsafe. This pointer refers to valid memory only where an\n  /// iterator would be valid to point to. Modifying the size of the byte\n  /// vector may invalidate this pointer. Any endian conversions will not be\n  /// performed.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type.\n  ///\n  /// \\retrurn A pointer to raw data.\n  template <typename T> const T* rawBytes() const {\n    assert(Parent && \"Block has no byte interval!\");\n    return reinterpret_cast<const T*>(Parent->rawBytes<uint8_t>() +\n                                      getOffset());\n  }\n\n  /// @cond INTERNAL\n  static bool classof(const Node* N) { return N->getKind() == Kind::CodeBlock; }\n  /// @endcond\n\nprivate:\n  CodeBlock(Context& C) : CfgNode(C, Kind::CodeBlock) {}\n  CodeBlock(Context& C, uint64_t S, gtirb::DecodeMode DMode)\n      : CfgNode(C, Kind::CodeBlock), Size(S), DecodeMode(DMode) {}\n  CodeBlock(Context& C, uint64_t S, gtirb::DecodeMode DMode, const UUID& U)\n      : CfgNode(C, Kind::CodeBlock, U), Size(S), DecodeMode(DMode) {}\n\n  void setParent(ByteInterval* BI, CodeBlockObserver* O) {\n    Parent = BI;\n    Observer = O;\n  }\n\n  static CodeBlock* Create(Context& C, uint64_t Size, gtirb::DecodeMode DMode,\n                           const UUID& U) {\n    return C.Create<CodeBlock>(C, Size, DMode, U);\n  }\n\n  /// \\brief The protobuf message type used for serializing CodeBlock.\n  using MessageType = proto::CodeBlock;\n\n  /// \\brief Serialize into a protobuf message.\n  ///\n  /// \\param[out] Message   Serialize into this message.\n  ///\n  /// \\return void\n  void toProtobuf(MessageType* Message) const;\n\n  /// \\brief Construct a CodeBlock from a protobuf message.\n  ///\n  /// \\param C  The Context in which the deserialized CodeBlock will be held.\n  /// \\param Message  The protobuf message from which to deserialize.\n  ///\n  /// \\return The deserialized CodeBlock object, or null on failure.\n  static ErrorOr<CodeBlock*> fromProtobuf(Context& C,\n                                          const MessageType& Message);\n\n  // Present for testing purposes only.\n  void save(std::ostream& Out) const;\n\n  // Present for testing purposes only.\n  static CodeBlock* load(Context& C, std::istream& In);\n\n  ByteInterval* Parent{nullptr};\n  CodeBlockObserver* Observer{nullptr};\n  uint64_t Size{0};\n  gtirb::DecodeMode DecodeMode{DecodeMode::Default};\n\n  friend class Context;      // Enables Context::Create\n  friend class ByteInterval; // Enables to/fromProtobuf, setByteInterval\n  friend class SerializationTestHarness; // Testing support.\n};\n\n} // namespace gtirb\n\n#endif // GTIRB_BLOCK_H\n"
  },
  {
    "path": "include/gtirb/Context.hpp",
    "content": "//===- Context.hpp ----------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_CONTEXT_H\n#define GTIRB_CONTEXT_H\n\n#include <gtirb/Allocator.hpp>\n#include <gtirb/Export.hpp>\n#include <boost/functional/hash.hpp>\n#include <boost/uuid/uuid.hpp>\n#include <boost/uuid/uuid_hash.hpp>\n#include <cstdlib>\n#include <functional>\n#include <map>\n\n/// \\file Context.hpp\n/// \\brief Class \\ref gtirb::Context and related operators.\n\nnamespace gtirb {\n\n/// \\brief Represents a universally unique identifier used to identify Node\n/// objects across serialization boundaries.\n///\n/// \\see Node\n/// \\see Context\nusing UUID = boost::uuids::uuid;\n\nclass Node;\nclass CfgNode;\nclass ByteInterval;\nclass CodeBlock;\nclass DataBlock;\nclass IR;\nclass Module;\nclass ProxyBlock;\nclass Section;\nclass Symbol;\n\n/// \\class Context\n///\n/// \\brief The context under which GTIRB operations occur.\n///\n/// This object is responsible for holding serialization and\n/// serialization state, allowing for control over when Node memory\n/// can be released and providing a mechanism for ensuring thread\n/// safety.\n///\n/// Any API that requires a \\ref Context object may potentially\n/// allocate memory within that context. Destroying the Context object\n/// will release that memory.  In a multithreaded environment, sharing\n/// a Context object across multiple threads can introduce data races,\n/// so protecting the object with a locking primitive is recommended.\nclass GTIRB_EXPORT_API Context {\n  // Note: this must be declared first so it outlives the allocators. They\n  // will access the UuidMap during their destructors to unregister nodes.\n  std::map<UUID, Node*> UuidMap;\n\n  // Allocate each node type in a separate arena.\n  mutable SpecificBumpPtrAllocator<Node> NodeAllocator;\n  mutable SpecificBumpPtrAllocator<ByteInterval> ByteIntervalAllocator;\n  mutable SpecificBumpPtrAllocator<CodeBlock> CodeBlockAllocator;\n  mutable SpecificBumpPtrAllocator<DataBlock> DataBlockAllocator;\n  mutable SpecificBumpPtrAllocator<IR> IrAllocator;\n  mutable SpecificBumpPtrAllocator<Module> ModuleAllocator;\n  mutable SpecificBumpPtrAllocator<ProxyBlock> ProxyBlockAllocator;\n  mutable SpecificBumpPtrAllocator<Section> SectionAllocator;\n  mutable SpecificBumpPtrAllocator<Symbol> SymbolAllocator;\n\n  /// \\copybrief gtirb::Node\n  friend class Node;\n\n  void registerNode(const UUID& ID, Node* N) { UuidMap[ID] = N; }\n\n  void unregisterNode(const Node* N);\n  const Node* findNode(const UUID& ID) const;\n  Node* findNode(const UUID& ID);\n\n  /// \\brief Allocates a chunk of memory for an object of type \\ref T.\n  ///\n  /// \\tparam T   The type of object for which to allocate memory.\n  ///\n  /// \\return The newly allocated memory, suitably sized for the given\n  /// type. Will return nullptr if the allocation cannot be honored.\n  template <class T> void* Allocate() const;\n\n  /// \\brief Deallocates memory allocated through a call to Allocate().\n  ///\n  /// \\return void\n  ///\n  /// Deallocation of individual pointers leads to memory fragmentation, which\n  /// is why this function is currently a placeholder that does not actually\n  /// perform the deallocation. Instead, memory is freed as a whole when the\n  /// \\ref Context object is destroyed.\n  void Deallocate(void*, size_t) const {\n    // Noop -- we don't want callers to deallocate individual allocations, but\n    // should instead deallocate the entire Context object to free memory.\n  }\n\npublic:\n  Context();\n  ~Context();\n\n  /// \\brief Forgets all arena allocations held by this \\ref Context object.\n  /// This can be useful under circumstances where leaking the memory is\n  /// acceptable, such as when shutting a program down.\n  void ForgetAllocations();\n\n  /// \\brief Create an object of type \\ref T.\n  ///\n  /// \\tparam NodeTy   The type of object for which to allocate memory.\n  /// \\tparam Args     The types of the constructor arguments.\n  /// \\param TheArgs   The constructor arguments.\n  ///\n  /// \\return A newly created object, allocated within the Context.\n  template <typename NodeTy, typename... Args>\n  NodeTy* Create(Args&&... TheArgs) {\n    return new (Allocate<NodeTy>()) NodeTy(std::forward<Args>(TheArgs)...);\n  }\n};\n\ntemplate <> GTIRB_EXPORT_API void* Context::Allocate<Node>() const;\ntemplate <> GTIRB_EXPORT_API void* Context::Allocate<ByteInterval>() const;\ntemplate <> GTIRB_EXPORT_API void* Context::Allocate<CodeBlock>() const;\ntemplate <> GTIRB_EXPORT_API void* Context::Allocate<DataBlock>() const;\ntemplate <> GTIRB_EXPORT_API void* Context::Allocate<IR>() const;\ntemplate <> GTIRB_EXPORT_API void* Context::Allocate<Module>() const;\ntemplate <> GTIRB_EXPORT_API void* Context::Allocate<ProxyBlock>() const;\ntemplate <> GTIRB_EXPORT_API void* Context::Allocate<Section>() const;\ntemplate <> GTIRB_EXPORT_API void* Context::Allocate<Symbol>() const;\n\n} // namespace gtirb\n\n#endif // GTIRB_CONTEXT_H\n"
  },
  {
    "path": "include/gtirb/DataBlock.hpp",
    "content": "//===- DataBlock.hpp --------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_DataBlock_H\n#define GTIRB_DataBlock_H\n\n#include <gtirb/Addr.hpp>\n#include <gtirb/ByteInterval.hpp>\n#include <gtirb/Node.hpp>\n#include <cstdint>\n#include <functional>\n#include <optional>\n#include <vector>\n\n/// \\file DataBlock.hpp\n/// \\brief Class gtirb::DataBlock.\n\nnamespace gtirb {\nnamespace proto {\nclass DataBlock;\n}\n\ntemplate <class T> class ErrorOr;\n\n///\n/// \\class DataBlock\n///\n/// \\brief Represents a data object, possibly symbolic.\n///\n/// Does not directly store the data bytes, which are kept in the\n/// \\ref ImageByteMap.\n///\nclass GTIRB_EXPORT_API DataBlock : public Node {\n  DataBlock(Context& C) : Node(C, Kind::DataBlock) {}\n  DataBlock(Context& C, uint64_t S, const UUID& U)\n      : Node(C, Kind::DataBlock, U), Size(S) {}\n  DataBlock(Context& C, uint64_t S) : Node(C, Kind::DataBlock), Size(S) {}\n\n  static DataBlock* Create(Context& C, uint64_t S, const UUID& U) {\n    return C.Create<DataBlock>(C, S, U);\n  }\n\npublic:\n  /// \\brief Create an unitialized DataBlock object.\n  /// \\param C        The Context in which this DataBlock will be held.\n  /// \\return         The newly created DataBlock.\n  static DataBlock* Create(Context& C) { return C.Create<DataBlock>(C); }\n\n  /// \\brief Create a DataBlock object.\n  ///\n  /// \\param C        The Context in which the newly-created DataBlock will be\n  /// \\param Size     The size of the object in bytes.\n  /// \\return The newly created DataBlock.\n  static DataBlock* Create(Context& C, uint64_t Size) {\n    return C.Create<DataBlock>(C, Size);\n  }\n\n  /// \\brief Get the \\ref ByteInterval this block belongs to.\n  ByteInterval* getByteInterval() { return Parent; }\n  /// \\brief Get the \\ref ByteInterval this block belongs to.\n  const ByteInterval* getByteInterval() const { return Parent; }\n\n  /// \\brief Get the size of a DataBlock.\n  ///\n  /// \\return The size.\n  ///\n  uint64_t getSize() const { return Size; }\n\n  /// \\brief Get the offset from the beginning of the \\ref ByteInterval this\n  /// block belongs to.\n  uint64_t getOffset() const;\n\n  /// \\brief Get the address of this block, if present. See \\ref\n  /// ByteInterval.getAddress for details on why this address may not be\n  /// present.\n  std::optional<Addr> getAddress() const;\n\n  /// \\brief Set the size of this block.\n  ///\n  /// Note that this does not automatically update any \\ref ByteInterval's size,\n  /// bytes, or symbolic expressions. This simply changes the extents of a block\n  /// in its \\ref ByteInterval.\n  void setSize(uint64_t S) {\n    if (Observer) {\n      std::swap(S, Size);\n      [[maybe_unused]] ChangeStatus Status =\n          Observer->sizeChange(this, S, Size);\n      assert(Status != ChangeStatus::Rejected &&\n             \"recovering from rejected size change is not implemented yet\");\n    } else {\n      Size = S;\n    }\n  }\n\n  /// \\brief Iterator over bytes in this block.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> using bytes_iterator = ByteInterval::bytes_iterator<T>;\n  /// \\brief Range over bytes in this block.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> using bytes_range = ByteInterval::bytes_range<T>;\n  /// \\brief Const iterator over bytes in this block.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T>\n  using const_bytes_iterator = ByteInterval::const_bytes_iterator<T>;\n  /// \\brief Const range over bytes in this block.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T>\n  using const_bytes_range = ByteInterval::const_bytes_range<T>;\n\n  /// \\brief Get an iterator to the first byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> bytes_iterator<T> bytes_begin() {\n    assert(Parent && \"Block has no byte interval!\");\n    return bytes_begin<T>(Parent->getBoostEndianOrder());\n  }\n\n  /// \\brief Get an iterator to the first byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the block.\n  /// \\param  OutputOrder The endianness you wish to read out from the block.\n  template <typename T>\n  bytes_iterator<T>\n  bytes_begin(boost::endian::order InputOrder,\n              boost::endian::order OutputOrder = boost::endian::order::native) {\n    assert(Parent && \"Block has no byte interval!\");\n    return Parent->bytes_begin<T>(InputOrder, OutputOrder) + getOffset();\n  }\n\n  /// \\brief Get an iterator past the last byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> bytes_iterator<T> bytes_end() {\n    assert(Parent && \"Block has no byte interval!\");\n    return bytes_end<T>(Parent->getBoostEndianOrder());\n  }\n\n  /// \\brief Get an iterator past the last byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the block.\n  /// \\param  OutputOrder The endianness you wish to read out from the block.\n  template <typename T>\n  bytes_iterator<T>\n  bytes_end(boost::endian::order InputOrder,\n            boost::endian::order OutputOrder = boost::endian::order::native) {\n    assert(Parent && \"Block has no byte interval!\");\n    return Parent->bytes_begin<T>(InputOrder, OutputOrder) + getOffset() + Size;\n  }\n\n  /// \\brief Get a range of the bytes in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> bytes_range<T> bytes() {\n    assert(Parent && \"Block has no byte interval!\");\n    return bytes<T>(Parent->getBoostEndianOrder());\n  }\n\n  /// \\brief Get a range of the bytes in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the block.\n  /// \\param  OutputOrder The endianness you wish to read out from the block.\n  template <typename T>\n  bytes_range<T>\n  bytes(boost::endian::order InputOrder,\n        boost::endian::order OutputOrder = boost::endian::order::native) {\n    assert(Parent && \"Block has no byte interval!\");\n    return bytes_range<T>(bytes_begin<T>(InputOrder, OutputOrder),\n                          bytes_end<T>(InputOrder, OutputOrder));\n  }\n\n  /// \\brief Get an iterator to the first byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> const_bytes_iterator<T> bytes_begin() const {\n    assert(Parent && \"Block has no byte interval!\");\n    return bytes_begin<T>(Parent->getBoostEndianOrder());\n  }\n\n  /// \\brief Get an iterator to the first byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the block.\n  /// \\param  OutputOrder The endianness you wish to read out from the block.\n  template <typename T>\n  const_bytes_iterator<T> bytes_begin(\n      boost::endian::order InputOrder,\n      boost::endian::order OutputOrder = boost::endian::order::native) const {\n    assert(Parent && \"Block has no byte interval!\");\n    return Parent->bytes_begin<T>(InputOrder, OutputOrder) + getOffset();\n  }\n\n  /// \\brief Get an iterator past the last byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> const_bytes_iterator<T> bytes_end() const {\n    assert(Parent && \"Block has no byte interval!\");\n    return bytes_end<T>(Parent->getBoostEndianOrder());\n  }\n\n  /// \\brief Get an iterator past the last byte in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the block.\n  /// \\param  OutputOrder The endianness you wish to read out from the block.\n  template <typename T>\n  const_bytes_iterator<T> bytes_end(\n      boost::endian::order InputOrder,\n      boost::endian::order OutputOrder = boost::endian::order::native) const {\n    assert(Parent && \"Block has no byte interval!\");\n    return Parent->bytes_begin<T>(InputOrder, OutputOrder) + getOffset() + Size;\n  }\n\n  /// \\brief Get a range of the bytes in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  template <typename T> const_bytes_range<T> bytes() const {\n    assert(Parent && \"Block has no byte interval!\");\n    return bytes<T>(Parent->getBoostEndianOrder());\n  }\n\n  /// \\brief Get a range of the bytes in this block.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type that satisfies Boost's EndianReversible concept.\n  ///\n  /// \\param  InputOrder  The endianness of the data in the block.\n  /// \\param  OutputOrder The endianness you wish to read out from the block.\n  template <typename T>\n  const_bytes_range<T>\n  bytes(boost::endian::order InputOrder,\n        boost::endian::order OutputOrder = boost::endian::order::native) const {\n    assert(Parent && \"Block has no byte interval!\");\n    return const_bytes_range<T>(bytes_begin<T>(InputOrder, OutputOrder),\n                                bytes_end<T>(InputOrder, OutputOrder));\n  }\n\n  /// \\brief Return the raw data underlying this block's byte vector.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// Much like \\ref std::vector::data, this function is low-level and\n  /// potentially unsafe. This pointer refers to valid memory only where an\n  /// iterator would be valid to point to. Modifying the size of the byte\n  /// vector may invalidate this pointer. Any endian conversions will not be\n  /// performed.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type.\n  ///\n  /// \\retrurn A pointer to raw data.\n  template <typename T> T* rawBytes() {\n    assert(Parent && \"Block has no byte interval!\");\n    return reinterpret_cast<T*>(Parent->rawBytes<uint8_t>() + getOffset());\n  }\n\n  /// \\brief Return the raw data underlying this block's byte vector.\n  ///\n  /// If this block is not associated with any \\ref ByteInterval, than the\n  /// behavior of this function is undefined.\n  ///\n  /// Much like \\ref std::vector::data, this function is low-level and\n  /// potentially unsafe. This pointer refers to valid memory only where an\n  /// iterator would be valid to point to. Modifying the size of the byte\n  /// vector may invalidate this pointer. Any endian conversions will not be\n  /// performed.\n  ///\n  /// \\tparam T The type of data stored in this block's byte vector. Must be\n  /// a POD type.\n  ///\n  /// \\retrurn A pointer to raw data.\n  template <typename T> const T* rawBytes() const {\n    assert(Parent && \"Block has no byte interval!\");\n    return reinterpret_cast<const T*>(Parent->rawBytes<uint8_t>() +\n                                      getOffset());\n  }\n\n  /// @cond INTERNAL\n  static bool classof(const Node* N) { return N->getKind() == Kind::DataBlock; }\n  /// @endcond\n\nprivate:\n  ByteInterval* Parent{nullptr};\n  DataBlockObserver* Observer{nullptr};\n  uint64_t Size{0};\n\n  void setParent(ByteInterval* BI, DataBlockObserver* O) {\n    Parent = BI;\n    Observer = O;\n  }\n\n  /// \\brief The protobuf message type used for serializing DataBlock.\n  using MessageType = proto::DataBlock;\n\n  /// \\brief Serialize into a protobuf message.\n  ///\n  /// \\param[out] Message   Serialize into this message.\n  ///\n  /// \\return void\n  void toProtobuf(MessageType* Message) const;\n\n  /// \\brief Construct a DataBlock from a protobuf message.\n  ///\n  /// \\param C   The Context in which the deserialized DataBlock will be held.\n  /// \\param Message  The protobuf message from which to deserialize.\n  ///\n  /// \\return The deserialized DataBlock object, or null on failure.\n  static ErrorOr<DataBlock*> fromProtobuf(Context& C,\n                                          const MessageType& Message);\n\n  // Present for testing purposes only.\n  void save(std::ostream& Out) const;\n\n  // Present for testing purposes only.\n  static DataBlock* load(Context& C, std::istream& In);\n\n  friend class Context;      // Enables Context::Create\n  friend class ByteInterval; // Enables to/fromProtobuf, setByteInterval\n  friend class SerializationTestHarness; // Testing support.\n};\n} // namespace gtirb\n\n#endif // GTIRB_DataBlock_H\n"
  },
  {
    "path": "include/gtirb/DecodeMode.hpp",
    "content": "//===- DecodeMode.hpp --------------------------------------------*- C++-*-===//\n//\n//  Copyright (C) 2024 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_DECODE_MODE_H\n#define GTIRB_DECODE_MODE_H\n\n#include <gtirb/proto/CodeBlock.pb.h>\n#include <cstdint>\n\nnamespace gtirb {\n\n/// \\enum DecodeMode\n///\n/// \\brief Variations on decoding a particular ISA\nenum class DecodeMode : uint8_t {\n  Default = proto::All_Default, ///< Default decode mode for all ISAs\n  Thumb = proto::ARM_Thumb,     ///< Thumb decode mode for ARM32\n};\n\n} // namespace gtirb\n\n#endif // GTIRB_DECODE_MODE_H\n"
  },
  {
    "path": "include/gtirb/ErrorOr.hpp",
    "content": "//===- ErrorOr.hpp ----------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===-Addition License Information-----------------------------------------===//\n//\n// This file was initially written for the LLVM Compiler Infrastructure\n// project where it is distributed under the Apache License v2.0 with LLVM\n// Exceptions. See the LICENSE file in the project root for license terms.\n//\n//===----------------------------------------------------------------------===//\n\n#ifndef GTIRB_ERROROR_H\n#define GTIRB_ERROROR_H\n\n#include <gtirb/Export.hpp>\n#include <cassert>\n#include <iostream>\n#include <system_error>\n#include <type_traits>\n#include <utility>\n\nnamespace gtirb {\n\n/// A small struct to hold an error code\n/// along with a string holding additional details\nstruct GTIRB_EXPORT_API ErrorInfo {\n  std::error_code ErrorCode;\n  std::string Msg;\n  ErrorInfo() = default;\n  ErrorInfo(const std::error_code& EC, const std::string& S)\n      : ErrorCode(EC), Msg(S){};\n  std::string message() const;\n};\n\ntemplate <typename CharT, typename Traits>\nstd::ostream& operator<<(std::basic_ostream<CharT, Traits>& os,\n                         const ErrorInfo& Info) {\n  os << Info.ErrorCode.message() << \" \" << Info.Msg;\n  return os;\n}\n\n/// Represents either an error or a value T.\n///\n/// ErrorOr<T> is a pointer-like class that represents the result of an\n/// operation. The result is either an error, or a value of type T. This is\n/// designed to emulate the usage of returning a pointer where nullptr indicates\n/// failure. However instead of just knowing that the operation failed, we also\n/// have an error_code and optional user data that describes why it failed.\n///\n/// It is used like the following.\n/// \\code\n///   ErrorOr<Buffer> getBuffer();\n///\n///   auto buffer = getBuffer();\n///   if (error_code ec = buffer.getError())\n///     return ec;\n///   buffer->write(\"adena\");\n/// \\endcode\n///\n///\n/// Implicit conversion to bool returns true if there is a usable value. The\n/// unary * and -> operators provide pointer like access to the value. Accessing\n/// the value when there is an error has undefined behavior.\n///\n/// When T is a reference type the behavior is slightly different. The reference\n/// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and\n/// there is special handling to make operator -> work as if T was not a\n/// reference.\n///\n/// T cannot be a rvalue reference.\ntemplate <class T> class ErrorOr {\n  template <class OtherT> friend class ErrorOr;\n\n  static constexpr bool isRef = std::is_reference<T>::value;\n\n  using wrap = std::reference_wrapper<std::remove_reference_t<T>>;\n\npublic:\n  using storage_type = std::conditional_t<isRef, wrap, T>;\n\nprivate:\n  using reference = std::remove_reference_t<T>&;\n  using const_reference = const std::remove_reference_t<T>&;\n  using pointer = std::remove_reference_t<T>*;\n  using const_pointer = const std::remove_reference_t<T>*;\n\npublic:\n  template <class E>\n  ErrorOr(E ErrorCode, const std::string& Msg = \"\",\n          std::enable_if_t<std::is_error_code_enum<E>::value ||\n                               std::is_error_condition_enum<E>::value,\n                           void*> = nullptr)\n      : HasError(true) {\n    new (getErrorStorage()) ErrorInfo{make_error_code(ErrorCode), Msg};\n  }\n\n  ErrorOr(std::error_code EC, const std::string& Msg = \"\") : HasError(true) {\n    new (getErrorStorage()) ErrorInfo{EC, Msg};\n  }\n\n  ErrorOr(const ErrorInfo& EI) : HasError(true) {\n    new (getErrorStorage()) ErrorInfo(EI);\n  }\n\n  template <class OtherT>\n  ErrorOr(OtherT&& Val,\n          std::enable_if_t<std::is_convertible<OtherT, T>::value>* = nullptr)\n      : HasError(false) {\n    new (getStorage()) storage_type(std::forward<OtherT>(Val));\n  }\n\n  ErrorOr(const ErrorOr& Other) { copyConstruct(Other); }\n\n  template <class OtherT>\n  ErrorOr(const ErrorOr<OtherT>& Other,\n          std::enable_if_t<std::is_convertible<OtherT, T>::value>* = nullptr) {\n    copyConstruct(Other);\n  }\n\n  template <class OtherT>\n  explicit ErrorOr(\n      const ErrorOr<OtherT>& Other,\n      std::enable_if_t<!std::is_convertible<OtherT, const T&>::value>* =\n          nullptr) {\n    copyConstruct(Other);\n  }\n\n  ErrorOr(ErrorOr&& Other) { moveConstruct(std::move(Other)); }\n\n  template <class OtherT>\n  ErrorOr(ErrorOr<OtherT>&& Other,\n          std::enable_if_t<std::is_convertible<OtherT, T>::value>* = nullptr) {\n    moveConstruct(std::move(Other));\n  }\n\n  // This might eventually need SFINAE but it's more complex than is_convertible\n  // & I'm too lazy to write it right now.\n  template <class OtherT>\n  explicit ErrorOr(\n      ErrorOr<OtherT>&& Other,\n      std::enable_if_t<!std::is_convertible<OtherT, T>::value>* = nullptr) {\n    moveConstruct(std::move(Other));\n  }\n\n  ErrorOr& operator=(const ErrorOr& Other) {\n    copyAssign(Other);\n    return *this;\n  }\n\n  ErrorOr& operator=(ErrorOr&& Other) {\n    moveAssign(std::move(Other));\n    return *this;\n  }\n\n  ~ErrorOr() {\n    if (!HasError)\n      getStorage()->~storage_type();\n  }\n\n  /// Return false if there is an error.\n  explicit operator bool() const { return !HasError; }\n\n  reference get() { return *getStorage(); }\n  const_reference get() const { return const_cast<ErrorOr<T>*>(this)->get(); }\n\n  ErrorInfo getError() const {\n    return HasError ? *getErrorStorage() : ErrorInfo();\n  }\n\n  pointer operator->() { return toPointer(getStorage()); }\n\n  const_pointer operator->() const { return toPointer(getStorage()); }\n\n  reference operator*() { return *getStorage(); }\n\n  const_reference operator*() const { return *getStorage(); }\n\nprivate:\n  template <class OtherT> void copyConstruct(const ErrorOr<OtherT>& Other) {\n    if (!Other.HasError) {\n      // Get the other value.\n      HasError = false;\n      new (getStorage()) storage_type(*Other.getStorage());\n    } else {\n      // Get other's error.\n      HasError = true;\n      new (getErrorStorage()) ErrorInfo(Other.getError());\n    }\n  }\n\n  template <class T1>\n  static bool compareThisIfSameType(const T1& a, const T1& b) {\n    return &a == &b;\n  }\n\n  template <class T1, class T2>\n  static bool compareThisIfSameType(const T1&, const T2&) {\n    return false;\n  }\n\n  template <class OtherT> void copyAssign(const ErrorOr<OtherT>& Other) {\n    if (compareThisIfSameType(*this, Other))\n      return;\n\n    this->~ErrorOr();\n    new (this) ErrorOr(Other);\n  }\n\n  template <class OtherT> void moveConstruct(ErrorOr<OtherT>&& Other) {\n    if (!Other.HasError) {\n      // Get the other value.\n      HasError = false;\n      new (getStorage()) storage_type(std::move(*Other.getStorage()));\n    } else {\n      // Get other's error.\n      HasError = true;\n      new (getErrorStorage()) ErrorInfo(std::move(*Other.getErrorStorage()));\n    }\n  }\n\n  template <class OtherT> void moveAssign(ErrorOr<OtherT>&& Other) {\n    if (compareThisIfSameType(*this, Other))\n      return;\n\n    this->~ErrorOr();\n    new (this) ErrorOr(std::move(Other));\n  }\n\n  pointer toPointer(pointer Val) { return Val; }\n\n  const_pointer toPointer(const_pointer Val) const { return Val; }\n\n  pointer toPointer(wrap* Val) { return &Val->get(); }\n\n  const_pointer toPointer(const wrap* Val) const { return &Val->get(); }\n\n  storage_type* getStorage() {\n    assert(!HasError && \"Cannot get value when an error exists!\");\n    return reinterpret_cast<storage_type*>(TStorage);\n  }\n\n  const storage_type* getStorage() const {\n    assert(!HasError && \"Cannot get value when an error exists!\");\n    return reinterpret_cast<const storage_type*>(TStorage);\n  }\n\n  ErrorInfo* getErrorStorage() {\n    assert(HasError && \"Cannot get error when a value exists!\");\n    return reinterpret_cast<ErrorInfo*>(ErrorStorage);\n  }\n\n  const ErrorInfo* getErrorStorage() const {\n    return const_cast<ErrorOr<T>*>(this)->getErrorStorage();\n  }\n\n  union {\n    alignas(storage_type) char TStorage[sizeof(storage_type)];\n    alignas(ErrorInfo) char ErrorStorage[sizeof(ErrorInfo)];\n  };\n  bool HasError : 1;\n};\n\ntemplate <class T, class E>\nstd::enable_if_t<std::is_error_code_enum<E>::value ||\n                     std::is_error_condition_enum<E>::value,\n                 bool>\noperator==(const ErrorOr<T>& Err, E Code) {\n  return Err.getError().ErrorCode == Code;\n}\n} // end namespace gtirb\n\n#endif // GTIRB_ERROROR_H\n"
  },
  {
    "path": "include/gtirb/Export.hpp",
    "content": "//===- Export.hpp -----------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_EXPORT_H\n#define GTIRB_EXPORT_H\n\n/// @cond INTERNAL\n#ifndef __has_declspec_attribute\n#define __has_declspec_attribute(x) 0\n#endif\n\n#ifndef __has_attribute\n#define __has_attribute(x) 0\n#endif\n/// @endcond\n\n/// \\def GTIRB_EXPORT_API\n/// \\brief This macro controls the visibility of exported symbols (i.e. classes)\n/// in shared libraries. When producing the library, selects symbols to export,\n/// and when consuming the library, selects symbols to import.\n#if defined(_MSC_VER) || __has_declspec_attribute(dllexport)\n// Defined by the build system (CMake or SCons). This should only be defined by\n// the build system which generates the GTIRB library. Users of the library\n// should NOT define this.\n#ifdef GTIRB_gtirb_EXPORTS\n#define GTIRB_EXPORT_API _declspec(dllexport)\n#else\n// Note: We do not have clients explicitly dllimport from the gtirb\n// library. GTIRB exports no data symbols. And using dllimport is\n// optional for function symbols (dllimport provides only a very\n// slight performance improvement on function calls). Using dllimport\n// creates a certain amount of headache for Windows clients that may\n// want to sometimes statically and sometimes dynamically link against\n// GTIRB. The confusion and frustration this creates generally\n// outweighs the performance benefit.\n#define GTIRB_EXPORT_API\n#endif // GTIRB_gtirb_EXPORTS\n#elif defined(__GNUC__) || __has_attribute(visibility)\n#define GTIRB_EXPORT_API __attribute__((visibility(\"default\")))\n#else\n#define GTIRB_EXPORT_API\n#endif\n\n#endif // GTIRB_EXPORT_H\n"
  },
  {
    "path": "include/gtirb/IR.hpp",
    "content": "//===- IR.hpp ---------------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2021 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_IR_H\n#define GTIRB_IR_H\n\n#include <gtirb/Addr.hpp>\n#include <gtirb/AuxData.hpp>\n#include <gtirb/AuxDataContainer.hpp>\n#include <gtirb/CFG.hpp>\n#include <gtirb/ErrorOr.hpp>\n#include <gtirb/Module.hpp>\n#include <gtirb/Node.hpp>\n#include <gtirb/Observer.hpp>\n#include <gtirb/Utility.hpp>\n#include <gtirb/version.h>\n#include <boost/iterator/indirect_iterator.hpp>\n#include <boost/multi_index_container.hpp>\n#include <boost/range/iterator_range.hpp>\n#include <map>\n#include <string>\n#include <vector>\n\n/// \\file IR.hpp\n/// \\brief Class gtirb::IR.\n\nnamespace gtirb {\nnamespace proto {\nclass IR;\n}\n/// \\class IR\n///\n/// \\brief A complete internal representation consisting of Modules\n/// (\\ref Module).\n///\n/// \\dot\n/// digraph example {\n///     node [shape=record, fontname=Helvetica, fontsize=10];\n///\n///     ir [ label=\"IR\" URL=\"\\ref IR\"];\n///     module [ label=\"Module\" URL=\"\\ref Module\"];\n///     auxData [ label=\"AuxData\" URL=\"\\ref AuxData\"];\n///     imageByteMap [label=\"ImageByteMap\" URL=\"\\ref ImageByteMap\"]\n///     blocks [label=\"Block\" URL=\"\\ref Block\"]\n///     data [label=\"DataBlock\"  URL=\"\\ref DataBlock\"]\n///     symbolicExpressions  [label=\"SymbolicExpression\"\n///                           URL=\"\\ref SymbolicExpression\"]\n///     sections [label=\"Section\" URL=\"\\ref Section\"]\n///     symbols [label=\"Symbol\" URL=\"\\ref Symbol\"]\n///     cfg [label=\"CFG\" URL=\"\\ref CFG\"]\n///\n///     ir -> module;\n///     ir -> auxData;\n///     module -> cfg;\n///     module -> data\n///     module -> imageByteMap;\n///     module -> sections\n///     module -> symbols;\n///     module -> symbolicExpressions\n///     cfg -> blocks;\n/// }\n/// \\enddot\n///\n\nclass GTIRB_EXPORT_API IR : public AuxDataContainer {\n  IR(Context& C);\n  IR(Context& C, const UUID& U);\n\n  static IR* Create(Context& C, const UUID& U) { return C.Create<IR>(C, U); }\n\n  struct by_name {};\n  struct by_pointer {};\n\n  using ModuleSet = boost::multi_index::multi_index_container<\n      Module*, boost::multi_index::indexed_by<\n                   boost::multi_index::ordered_non_unique<\n                       boost::multi_index::tag<by_name>,\n                       boost::multi_index::const_mem_fun<\n                           Module, const std::string&, &Module::getName>>,\n                   boost::multi_index::hashed_unique<\n                       boost::multi_index::tag<by_pointer>,\n                       boost::multi_index::identity<Module*>>>>;\n\n  class ModuleObserverImpl;\n\npublic:\n  /// \\brief Create an IR object in its default state.\n  ///\n  /// \\param C  The Context in which this object will be held.\n  ///\n  /// \\return The newly created object.\n  static IR* Create(Context& C) { return C.Create<IR>(C); }\n\n  /// \\brief Get the associated Control Flow Graph (\\ref CFG).\n  ///\n  /// \\return The associated CFG.\n  const CFG& getCFG() const { return Cfg; }\n\n  /// \\brief Get a const reference to the associated Control Flow Graph\n  /// (\\ref CFG).\n  ///\n  /// \\return The associated CFG.\n  CFG& getCFG() { return Cfg; }\n\n  /// \\name Module-Related Public Types and Functions\n  /// @{\n  /// \\brief Iterator over \\ref Module \"Modules\".\n  ///\n  /// Modules are returned in name order. If more than one module has the same\n  /// name, the order in which they are returned is unspecified.\n  using module_iterator = boost::indirect_iterator<ModuleSet::iterator>;\n  /// \\brief Constant iterator over \\ref Module \"Modules\".\n  ///\n  /// Modules are returned in name order. If more than one module has the same\n  /// name, the order in which they are returned is unspecified.\n  using const_module_iterator =\n      boost::indirect_iterator<ModuleSet::const_iterator, const Module>;\n\n  /// \\brief Returns an iterator to the first Module.\n  module_iterator modules_begin() { return Modules.begin(); }\n  /// \\brief Returns an iterator to the element following the last Module.\n  module_iterator modules_end() { return Modules.end(); }\n  /// \\brief Returns a constant iterator to the first Module.\n  const_module_iterator modules_begin() const { return Modules.begin(); }\n  /// \\brief Returns a constant iterator to the element following the last\n  /// Module.\n  const_module_iterator modules_end() const { return Modules.end(); }\n\n  /// \\brief Range of \\ref Module \"Modules\".\n  ///\n  /// Modules are returned in name order. If more than one module has the same\n  /// name, the order in which they are returned is unspecified.\n  using module_range = boost::iterator_range<module_iterator>;\n  /// \\brief Constant range of \\ref Module \"Modules\".\n  ///\n  /// Modules are returned in name order. If more than one module has the same\n  /// name, the order in which they are returned is unspecified.\n  using const_module_range = boost::iterator_range<const_module_iterator>;\n\n  /// \\brief Returns a range of the \\ref Module \"Modules\".\n  module_range modules() {\n    return boost::make_iterator_range(modules_begin(), modules_end());\n  }\n  /// \\brief Returns a constant range of the \\ref Module \"Modules\".\n  const_module_range modules() const {\n    return boost::make_iterator_range(modules_begin(), modules_end());\n  }\n\n  /// \\brief Iterator over modules \\ref Module \"Modules\".\n  ///\n  /// This iterator returns modules in name order. If two modules have the same\n  /// name, their order is unspecified.\n  using module_name_iterator =\n      boost::indirect_iterator<ModuleSet::index<by_name>::type::iterator>;\n  /// \\brief Range of modules \\ref Module \"Modules\".\n  ///\n  /// This range returns modules in name order. If two modules have the same\n  /// name, their order is unspecified.\n  using module_name_range = boost::iterator_range<module_name_iterator>;\n  /// \\brief Constant iterator over modules \\ref Module \"Modules\".\n  ///\n  /// This iterator returns modules in name order. If two modules have the same\n  /// name, their order is unspecified.\n  using const_module_name_iterator =\n      boost::indirect_iterator<ModuleSet::index<by_name>::type::const_iterator,\n                               const Module>;\n  /// \\brief Constant range of modules \\ref Module \"Modules\".\n  ///\n  /// This range returns modules in name order. If two modules have the same\n  /// name, their order is unspecified.\n  using const_module_name_range =\n      boost::iterator_range<const_module_name_iterator>;\n\n  /// \\brief Remove a \\ref Module object located in this IR.\n  ///\n  /// \\param S The \\ref Module object to remove.\n  ///\n  /// \\return Whether or not the operation succeeded. This operation can\n  /// fail if the node to remove is not actually part of this node to begin\n  /// with.\n  bool removeModule(Module* M) {\n    auto& Index = Modules.get<by_pointer>();\n    if (auto Iter = Index.find(M); Iter != Index.end()) {\n      MO->removeProxyBlocks(M, M->proxy_blocks());\n      MO->removeCodeBlocks(M, M->code_blocks());\n      Index.erase(Iter);\n      M->setParent(nullptr, nullptr);\n      return true;\n    }\n    return false;\n  }\n\n  /// \\brief Move a \\ref Module object to be located in this IR.\n  ///\n  /// \\param S The \\ref Module object to add.\n  Module* addModule(Module* M) {\n    if (M->getIR()) {\n      M->getIR()->removeModule(M);\n    }\n\n    MO->addProxyBlocks(M, M->proxy_blocks());\n    MO->addCodeBlocks(M, M->code_blocks());\n    Modules.emplace(M);\n    M->setParent(this, MO.get());\n    return M;\n  }\n\n  /// \\brief Creates a new \\ref Module in this IR.\n  ///\n  /// \\tparam Args  The arguments to construct a \\ref Module.\n  // FIXME: this API may wind up getting removed because we perhaps want to\n  // support creating a Module that is not hooked up to any IR object and then\n  // set the parent on the module later. Personally, I think that is a\n  // dangerous design choice, but we can argue the merits of both approaches in\n  // a code review.\n  template <typename... Args> Module* addModule(Context& C, Args... A) {\n    return addModule(Module::Create(C, A...));\n  }\n\n  /// \\brief Find modules by name\n  ///\n  /// \\param N The name to look up.\n  ///\n  /// \\return A possibly empty range of all the modules with the\n  /// given name.\n  module_name_range findModules(const std::string& N) {\n    auto Found = Modules.get<by_name>().equal_range(N);\n    return boost::make_iterator_range(Found.first, Found.second);\n  }\n\n  /// \\brief Find modules by name\n  ///\n  /// \\param N The name to look up.\n  ///\n  /// \\return A possibly empty constant range of all the modules with the\n  /// given name.\n  const_module_name_range findModules(const std::string& N) const {\n    auto Found = Modules.get<by_name>().equal_range(N);\n    return boost::make_iterator_range(Found.first, Found.second);\n  }\n\n  /// @}\n  // (end Module-Related Public Types and Functions)\n\n  /// \\brief Serialize to an output stream in binary format.\n  ///\n  /// \\param Out The output stream.\n  ///\n  /// \\return void\n  void save(std::ostream& Out) const;\n\n  /// \\brief Serialize to an output stream in JSON format.\n  ///\n  /// \\param Out The output stream.\n  ///\n  /// \\return void\n  void saveJSON(std::ostream& Out) const;\n\n  /// \\enum load_error\n  ///\n  /// \\brief Specifies various failure modes when loading an IR.\n  enum class load_error {\n    IncorrectVersion = 1, ///< The version number in the file does not match.\n    CorruptFile, ///< The content of the file could not be deserialized.\n    CorruptModule,\n    CorruptSection,\n    CorruptByteInterval,\n    CorruptCFG,  ///< The control flow graph could not be deserialized\n    BadUUID,     ///< An object had an incorrectly formatted UUID\n    MissingUUID, ///< A UUID did not refer to an object in the loading Context\n    NotGTIRB,    ///< Indicates the GTIRB magic number was not found\n  };\n\n  /// \\brief Deserialize binary format from an input stream.\n  ///\n  /// \\param C   The Context in which this IR will be loaded.\n  /// \\param In  The input stream.\n  ///\n  /// \\return The deserialized IR object or an error.\n  static ErrorOr<IR*> load(Context& C, std::istream& In);\n\n  /// \\brief Deserialize JSON format from an input stream.\n  ///\n  /// \\param C   The Context in which this IR will be loaded.\n  /// \\param In  The input stream.\n  ///\n  /// \\return The deserialized IR object or an error.\n  static ErrorOr<IR*> loadJSON(Context& C, std::istream& In);\n\n  /// \\name ProxyBlock-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over \\ref ProxyBlock objects.\n  using proxy_block_iterator = MergeSortedIterator<Module::proxy_block_iterator,\n                                                   ArbitraryLess<ProxyBlock>>;\n  /// \\brief Range over \\ref ProxyBlock objects.\n  using proxy_block_range = boost::iterator_range<proxy_block_iterator>;\n  /// \\brief Iterator over \\ref ProxyBlock objects.\n  using const_proxy_block_iterator =\n      MergeSortedIterator<Module::const_proxy_block_iterator,\n                          ArbitraryLess<ProxyBlock>>;\n  /// \\brief Range over \\ref ProxyBlock objects.\n  using const_proxy_block_range =\n      boost::iterator_range<const_proxy_block_iterator>;\n\n  /// \\brief Return an iterator to the first \\ref ProxyBlock.\n  proxy_block_iterator proxy_blocks_begin() {\n    return proxy_block_iterator(\n        boost::make_transform_iterator(this->modules_begin(),\n                                       NodeToProxyBlockRange<Module>()),\n        boost::make_transform_iterator(this->modules_end(),\n                                       NodeToProxyBlockRange<Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// ProxyBlock.\n  proxy_block_iterator proxy_blocks_end() { return proxy_block_iterator(); }\n\n  /// \\brief Return a range of all the \\ref ProxyBlock objects.\n  proxy_block_range proxy_blocks() {\n    return boost::make_iterator_range(proxy_blocks_begin(), proxy_blocks_end());\n  }\n\n  /// \\brief Return an iterator to the first \\ref ProxyBlock.\n  const_proxy_block_iterator proxy_blocks_begin() const {\n    return const_proxy_block_iterator(\n        boost::make_transform_iterator(this->modules_begin(),\n                                       NodeToProxyBlockRange<const Module>()),\n        boost::make_transform_iterator(this->modules_end(),\n                                       NodeToProxyBlockRange<const Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// ProxyBlock.\n  const_proxy_block_iterator proxy_blocks_end() const {\n    return const_proxy_block_iterator();\n  }\n\n  /// \\brief Return an iterator to the first \\ref ProxyBlock.\n  const_proxy_block_range proxy_blocks() const {\n    return boost::make_iterator_range(proxy_blocks_begin(), proxy_blocks_end());\n  }\n  /// @}\n  // (end ProxyBlock-Related Public Types and Functions)\n\n  /// \\name Symbol-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over \\ref Symbol objects.\n  ///\n  /// This iterator returns symbols in an arbitrary order.\n  using symbol_iterator =\n      MergeSortedIterator<Module::symbol_iterator, ArbitraryLess<Symbol>>;\n  /// \\brief Range of \\ref Symbol objects.\n  ///\n  /// This range returns symbols in an arbitrary order.\n  using symbol_range = boost::iterator_range<symbol_iterator>;\n  /// \\brief Iterator over \\ref Symbol objects.\n  ///\n  /// This iterator returns symbols in an arbitrary order.\n  using const_symbol_iterator =\n      MergeSortedIterator<Module::const_symbol_iterator, ArbitraryLess<Symbol>>;\n  /// \\brief Range of \\ref Symbol objects.\n  ///\n  /// This range returns symbols in an arbitrary order.\n  using const_symbol_range = boost::iterator_range<const_symbol_iterator>;\n\n  /// \\brief Return an iterator to the first \\ref Symbol.\n  symbol_iterator symbols_begin() {\n    return symbol_iterator(\n        boost::make_transform_iterator(this->modules_begin(),\n                                       NodeToSymbolRange<Module>()),\n        boost::make_transform_iterator(this->modules_end(),\n                                       NodeToSymbolRange<Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref Symbol.\n  symbol_iterator symbols_end() { return symbol_iterator(); }\n\n  /// \\brief Return a range of the \\ref Symbol objects.\n  symbol_range symbols() {\n    return boost::make_iterator_range(symbols_begin(), symbols_end());\n  }\n\n  /// \\brief Return an iterator to the first \\ref Symbol.\n  const_symbol_iterator symbols_begin() const {\n    return const_symbol_iterator(\n        boost::make_transform_iterator(this->modules_begin(),\n                                       NodeToSymbolRange<const Module>()),\n        boost::make_transform_iterator(this->modules_end(),\n                                       NodeToSymbolRange<const Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref Symbol.\n  const_symbol_iterator symbols_end() const { return const_symbol_iterator(); }\n\n  /// \\brief Return a range of the \\ref Symbol objects.\n  const_symbol_range symbols() const {\n    return boost::make_iterator_range(symbols_begin(), symbols_end());\n  }\n  /// @}\n  // (end Symbol-Related Public Types and Functions)\n\n  /// \\name Section-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over \\ref Section objects.\n  using section_iterator =\n      MergeSortedIterator<Module::section_iterator, AddressLess>;\n  /// \\brief Range of \\ref Section objects.\n  using section_range = boost::iterator_range<section_iterator>;\n  /// \\brief Sub-range of \\ref Section objects overlapping an address.\n  using section_subrange = boost::iterator_range<\n      MergeSortedIterator<Module::section_subrange::iterator, AddressLess>>;\n  /// \\brief Iterator over \\ref Section objects.\n  using const_section_iterator =\n      MergeSortedIterator<Module::const_section_iterator, AddressLess>;\n  /// \\brief Range of \\ref Section objects.\n  using const_section_range = boost::iterator_range<const_section_iterator>;\n  /// \\brief Sub-range of \\ref Section objects overlapping an address.\n  using const_section_subrange = boost::iterator_range<MergeSortedIterator<\n      Module::const_section_subrange::iterator, AddressLess>>;\n  /// \\brief Iterator over \\ref Section objects.\n  using section_name_iterator =\n      MergeSortedIterator<Module::section_name_iterator, AddressLess>;\n  /// \\brief Range of \\ref Section objects.\n  using section_name_range = boost::iterator_range<section_name_iterator>;\n  /// \\brief Iterator over \\ref Section objects.\n  using const_section_name_iterator =\n      MergeSortedIterator<Module::const_section_name_iterator, AddressLess>;\n  /// \\brief Range of \\ref Section objects.\n  using const_section_name_range =\n      boost::iterator_range<const_section_name_iterator>;\n\n  /// \\brief Return an iterator to the first \\ref Section.\n  section_iterator sections_begin() {\n    return section_iterator(\n        boost::make_transform_iterator(this->modules_begin(),\n                                       NodeToSectionRange<Module>()),\n        boost::make_transform_iterator(this->modules_end(),\n                                       NodeToSectionRange<Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref Section.\n  section_iterator sections_end() { return section_iterator(); }\n\n  /// \\brief Return a range of all the \\ref Section objects.\n  section_range sections() {\n    return boost::make_iterator_range(sections_begin(), sections_end());\n  }\n\n  /// \\brief Return an iterator to the first \\ref Section.\n  const_section_iterator sections_begin() const {\n    return const_section_iterator(\n        boost::make_transform_iterator(this->modules_begin(),\n                                       NodeToSectionRange<const Module>()),\n        boost::make_transform_iterator(this->modules_end(),\n                                       NodeToSectionRange<const Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref Section.\n  const_section_iterator sections_end() const {\n    return const_section_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref Section objects.\n  const_section_range sections() const {\n    return boost::make_iterator_range(sections_begin(), sections_end());\n  }\n\n  /// \\brief Find a Section containing an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return The range of Sections containing the address.\n  section_subrange findSectionsOn(Addr A) {\n    return section_subrange(\n        section_subrange::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindSectionsIn<Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindSectionsIn<Module>(A))),\n        section_subrange::iterator());\n  }\n\n  /// \\brief Find a Section containing an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return The range of Sections containing the address.\n  const_section_subrange findSectionsOn(Addr A) const {\n    return const_section_subrange(\n        const_section_subrange::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindSectionsIn<const Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindSectionsIn<const Module>(A))),\n        const_section_subrange::iterator());\n  }\n\n  /// \\brief Find all the sections that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Section objects that are at the address \\p A.\n  section_range findSectionsAt(Addr A) {\n    return section_range(\n        section_range::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindSectionsAt<Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindSectionsAt<Module>(A))),\n        section_range::iterator());\n  }\n\n  /// \\brief Find all the sections that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref Section objects that are between the addresses.\n  section_range findSectionsAt(Addr Low, Addr High) {\n    return section_range(\n        section_range::iterator(\n            boost::make_transform_iterator(\n                this->modules_begin(), FindSectionsBetween<Module>(Low, High)),\n            boost::make_transform_iterator(\n                this->modules_end(), FindSectionsBetween<Module>(Low, High))),\n        section_range::iterator());\n  }\n\n  /// \\brief Find all the sections that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Section objects that are at the address \\p A.\n  const_section_range findSectionsAt(Addr A) const {\n    return const_section_range(\n        const_section_range::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindSectionsAt<const Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindSectionsAt<const Module>(A))),\n        const_section_range::iterator());\n  }\n\n  /// \\brief Find all the sections that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref Section objects that are between the addresses.\n  const_section_range findSectionsAt(Addr Low, Addr High) const {\n    return const_section_range(\n        const_section_range::iterator(\n            boost::make_transform_iterator(\n                this->modules_begin(),\n                FindSectionsBetween<const Module>(Low, High)),\n            boost::make_transform_iterator(\n                this->modules_end(),\n                FindSectionsBetween<const Module>(Low, High))),\n        const_section_range::iterator());\n  }\n  /// \\brief Find all the sections containing a name.\n  ///\n  /// \\param A The string name to look up.\n  ///\n  /// \\return A range of \\ref Section objects containing the name.\n  section_name_range findSections(const std::string& X) {\n    return section_name_range(\n        section_name_range::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindSections<Module>(X)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindSections<Module>(X))),\n        section_name_range::iterator());\n  }\n\n  /// \\brief Find all the sections containing a name.\n  ///\n  /// \\param A The string name to look up.\n  ///\n  /// \\return A range of \\ref Section objects containing the name.\n  const_section_name_range findSections(const std::string& X) const {\n    return const_section_name_range(\n        const_section_name_range::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindSections<const Module>(X)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindSections<const Module>(X))),\n        const_section_name_range::iterator());\n  }\n  /// @}\n  // (end Section-Related Public Types and Functions)\n\n  /// \\name ByteInterval-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over \\ref ByteInterval objects.\n  using byte_interval_iterator =\n      MergeSortedIterator<Module::byte_interval_iterator, AddressLess>;\n  /// \\brief Range of \\ref ByteInterval objects.\n  using byte_interval_range = boost::iterator_range<byte_interval_iterator>;\n  /// \\brief Sub-range of \\ref ByteInterval objects overlapping addresses.\n  using byte_interval_subrange = boost::iterator_range<MergeSortedIterator<\n      Module::byte_interval_subrange::iterator, AddressLess>>;\n  /// \\brief Const iterator over \\ref ByteInterval objects.\n  using const_byte_interval_iterator =\n      MergeSortedIterator<Module::const_byte_interval_iterator, AddressLess>;\n  /// \\brief Const range of \\ref ByteInterval objects.\n  using const_byte_interval_range =\n      boost::iterator_range<const_byte_interval_iterator>;\n  /// \\brief Sub-range of \\ref ByteInterval objects overlapping addresses.\n  using const_byte_interval_subrange =\n      boost::iterator_range<MergeSortedIterator<\n          Module::const_byte_interval_subrange::iterator, AddressLess>>;\n\n  /// \\brief Return an iterator to the first \\ref ByteInterval.\n  byte_interval_iterator byte_intervals_begin() {\n    return byte_interval_iterator(\n        boost::make_transform_iterator(this->modules_begin(),\n                                       NodeToByteIntervalRange<Module>()),\n        boost::make_transform_iterator(this->modules_end(),\n                                       NodeToByteIntervalRange<Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// ByteInterval.\n  byte_interval_iterator byte_intervals_end() {\n    return byte_interval_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref ByteInterval objects.\n  byte_interval_range byte_intervals() {\n    return boost::make_iterator_range(byte_intervals_begin(),\n                                      byte_intervals_end());\n  }\n\n  /// \\brief Return an iterator to the first \\ref ByteInterval.\n  const_byte_interval_iterator byte_intervals_begin() const {\n    return const_byte_interval_iterator(\n        boost::make_transform_iterator(this->modules_begin(),\n                                       NodeToByteIntervalRange<const Module>()),\n        boost::make_transform_iterator(\n            this->modules_end(), NodeToByteIntervalRange<const Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// ByteInterval.\n  const_byte_interval_iterator byte_intervals_end() const {\n    return const_byte_interval_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref ByteInterval objects.\n  const_byte_interval_range byte_intervals() const {\n    return boost::make_iterator_range(byte_intervals_begin(),\n                                      byte_intervals_end());\n  }\n\n  /// \\brief Find all the intervals that have bytes that lie within the address\n  /// specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that intersect the address \\p\n  /// A.\n  byte_interval_subrange findByteIntervalsOn(Addr A) {\n    return byte_interval_subrange(\n        byte_interval_subrange::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindByteIntervalsIn<Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindByteIntervalsIn<Module>(A))),\n        byte_interval_subrange::iterator());\n  }\n\n  /// \\brief Find all the intervals that have bytes that lie within the address\n  /// specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that intersect the address \\p\n  /// A.\n  const_byte_interval_subrange findByteIntervalsOn(Addr A) const {\n    return const_byte_interval_subrange(\n        const_byte_interval_subrange::iterator(\n            boost::make_transform_iterator(\n                this->modules_begin(), FindByteIntervalsIn<const Module>(A)),\n            boost::make_transform_iterator(\n                this->modules_end(), FindByteIntervalsIn<const Module>(A))),\n        const_byte_interval_subrange::iterator());\n  }\n\n  /// \\brief Find all the intervals that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that are at the address \\p A.\n  byte_interval_range findByteIntervalsAt(Addr A) {\n    return byte_interval_range(\n        byte_interval_range::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindByteIntervalsAt<Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindByteIntervalsAt<Module>(A))),\n        byte_interval_range::iterator());\n  }\n\n  /// \\brief Find all the intervals that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that are between the\n  /// addresses.\n  byte_interval_range findByteIntervalsAt(Addr Low, Addr High) {\n    return byte_interval_range(\n        byte_interval_range::iterator(\n            boost::make_transform_iterator(\n                this->modules_begin(),\n                FindByteIntervalsBetween<Module>(Low, High)),\n            boost::make_transform_iterator(\n                this->modules_end(),\n                FindByteIntervalsBetween<Module>(Low, High))),\n        byte_interval_range::iterator());\n  }\n\n  /// \\brief Find all the intervals that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that are at the address \\p A.\n  const_byte_interval_range findByteIntervalsAt(Addr A) const {\n    return const_byte_interval_range(\n        const_byte_interval_range::iterator(\n            boost::make_transform_iterator(\n                this->modules_begin(), FindByteIntervalsAt<const Module>(A)),\n            boost::make_transform_iterator(\n                this->modules_end(), FindByteIntervalsAt<const Module>(A))),\n        const_byte_interval_range::iterator());\n  }\n\n  /// \\brief Find all the intervals that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that are between the\n  /// addresses.\n  const_byte_interval_range findByteIntervalsAt(Addr Low, Addr High) const {\n    return const_byte_interval_range(\n        const_byte_interval_range::iterator(\n            boost::make_transform_iterator(\n                this->modules_begin(),\n                FindByteIntervalsBetween<const Module>(Low, High)),\n            boost::make_transform_iterator(\n                this->modules_end(),\n                FindByteIntervalsBetween<const Module>(Low, High))),\n        const_byte_interval_range::iterator());\n  }\n  /// @}\n  // (end group of ByteInterval-related types and functions)\n\n  /// \\name Block-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over blocks.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using block_iterator =\n      MergeSortedIterator<Module::block_iterator, BlockAddressLess>;\n  /// \\brief Range of blocks.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using block_range = boost::iterator_range<block_iterator>;\n  /// \\brief Sub-range of blocks overlapping an address or range of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using block_subrange = boost::iterator_range<\n      MergeSortedIterator<Module::block_subrange::iterator, BlockAddressLess>>;\n  /// \\brief Iterator over blocks.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_block_iterator =\n      MergeSortedIterator<Module::const_block_iterator, BlockAddressLess>;\n  /// \\brief Range of blocks.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_block_range = boost::iterator_range<const_block_iterator>;\n  /// \\brief Sub-range of blocks overlapping an address or range of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_block_subrange = boost::iterator_range<MergeSortedIterator<\n      Module::const_block_subrange::iterator, BlockAddressLess>>;\n\n  /// \\brief Return an iterator to the first block.\n  block_iterator blocks_begin() {\n    return block_iterator(\n        boost::make_transform_iterator(this->modules_begin(),\n                                       NodeToBlockRange<Module>()),\n        boost::make_transform_iterator(this->modules_end(),\n                                       NodeToBlockRange<Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last block.\n  block_iterator blocks_end() { return block_iterator(); }\n\n  /// \\brief Return a range of all the blocks.\n  block_range blocks() {\n    return boost::make_iterator_range(blocks_begin(), blocks_end());\n  }\n\n  /// \\brief Return an iterator to the first block.\n  const_block_iterator blocks_begin() const {\n    return const_block_iterator(\n        boost::make_transform_iterator(this->modules_begin(),\n                                       NodeToBlockRange<const Module>()),\n        boost::make_transform_iterator(this->modules_end(),\n                                       NodeToBlockRange<const Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last block.\n  const_block_iterator blocks_end() const { return const_block_iterator(); }\n\n  /// \\brief Return a range of all the blocks.\n  const_block_range blocks() const {\n    return boost::make_iterator_range(blocks_begin(), blocks_end());\n  }\n\n  /// \\brief Find all the blocks that have bytes that lie within the address\n  /// specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that intersect the address \\p A.\n  block_subrange findBlocksOn(Addr A) {\n    return block_subrange(\n        block_subrange::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindBlocksIn<Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindBlocksIn<Module>(A))),\n        block_subrange::iterator());\n  }\n\n  /// \\brief Find all the blocks that have bytes that lie within the address\n  /// specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that intersect the address \\p A.\n  const_block_subrange findBlocksOn(Addr A) const {\n    return const_block_subrange(\n        const_block_subrange::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindBlocksIn<const Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindBlocksIn<const Module>(A))),\n        const_block_subrange::iterator());\n  }\n\n  /// \\brief Find all the blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are at the address \\p A.\n  block_range findBlocksAt(Addr A) {\n    return block_range(block_range::iterator(\n                           boost::make_transform_iterator(\n                               this->modules_begin(), FindBlocksAt<Module>(A)),\n                           boost::make_transform_iterator(\n                               this->modules_end(), FindBlocksAt<Module>(A))),\n                       block_range::iterator());\n  }\n\n  /// \\brief Find all the blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are between the addresses.\n  block_range findBlocksAt(Addr Low, Addr High) {\n    return block_range(\n        block_range::iterator(\n            boost::make_transform_iterator(\n                this->modules_begin(), FindBlocksBetween<Module>(Low, High)),\n            boost::make_transform_iterator(\n                this->modules_end(), FindBlocksBetween<Module>(Low, High))),\n        block_range::iterator());\n  }\n\n  /// \\brief Find all the blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are at the address \\p A.\n  const_block_range findBlocksAt(Addr A) const {\n    return const_block_range(\n        const_block_range::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindBlocksAt<const Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindBlocksAt<const Module>(A))),\n        const_block_range::iterator());\n  }\n\n  /// \\brief Find all the blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are between the addresses.\n  const_block_range findBlocksAt(Addr Low, Addr High) const {\n    return const_block_range(\n        const_block_range::iterator(\n            boost::make_transform_iterator(\n                this->modules_begin(),\n                FindBlocksBetween<const Module>(Low, High)),\n            boost::make_transform_iterator(\n                this->modules_end(),\n                FindBlocksBetween<const Module>(Low, High))),\n        const_block_range::iterator());\n  }\n  /// @}\n  // (end group of Block-related types and functions)\n\n  /// \\name CodeBlock-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using code_block_iterator =\n      MergeSortedIterator<Module::code_block_iterator, AddressLess>;\n  /// \\brief Range of \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using code_block_range = boost::iterator_range<code_block_iterator>;\n  /// \\brief Sub-range of \\ref CodeBlock objects overlapping an address or range\n  /// of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using code_block_subrange = boost::iterator_range<\n      MergeSortedIterator<Module::code_block_subrange::iterator, AddressLess>>;\n  /// \\brief Iterator over \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_code_block_iterator =\n      MergeSortedIterator<Module::const_code_block_iterator, AddressLess>;\n  /// \\brief Range of \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_code_block_range =\n      boost::iterator_range<const_code_block_iterator>;\n  /// \\brief Sub-range of \\ref CodeBlock objects overlapping an address or range\n  /// of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending.\n  using const_code_block_subrange = boost::iterator_range<MergeSortedIterator<\n      Module::const_code_block_subrange::iterator, AddressLess>>;\n\n  /// \\brief Return an iterator to the first \\ref CodeBlock.\n  code_block_iterator code_blocks_begin() {\n    return code_block_iterator(\n        boost::make_transform_iterator(this->modules_begin(),\n                                       NodeToCodeBlockRange<Module>()),\n        boost::make_transform_iterator(this->modules_end(),\n                                       NodeToCodeBlockRange<Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// CodeBlock.\n  code_block_iterator code_blocks_end() { return code_block_iterator(); }\n\n  /// \\brief Return a range of all the \\ref CodeBlock objects.\n  code_block_range code_blocks() {\n    return boost::make_iterator_range(code_blocks_begin(), code_blocks_end());\n  }\n\n  /// \\brief Return an iterator to the first \\ref CodeBlock.\n  const_code_block_iterator code_blocks_begin() const {\n    return const_code_block_iterator(\n        boost::make_transform_iterator(this->modules_begin(),\n                                       NodeToCodeBlockRange<const Module>()),\n        boost::make_transform_iterator(this->modules_end(),\n                                       NodeToCodeBlockRange<const Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// CodeBlock.\n  const_code_block_iterator code_blocks_end() const {\n    return const_code_block_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref CodeBlock objects.\n  const_code_block_range code_blocks() const {\n    return boost::make_iterator_range(code_blocks_begin(), code_blocks_end());\n  }\n\n  /// \\brief Find all the code blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeNode object that intersect the address \\p A.\n  code_block_subrange findCodeBlocksOn(Addr A) {\n    return code_block_subrange(\n        code_block_subrange::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindCodeBlocksIn<Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindCodeBlocksIn<Module>(A))),\n        code_block_subrange::iterator());\n  }\n\n  /// \\brief Find all the code blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeNode object that intersect the address \\p A.\n  const_code_block_subrange findCodeBlocksOn(Addr A) const {\n    return const_code_block_subrange(\n        const_code_block_subrange::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindCodeBlocksIn<const Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindCodeBlocksIn<const Module>(A))),\n        const_code_block_subrange::iterator());\n  }\n\n  /// \\brief Find all the code blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are at the address \\p A.\n  code_block_range findCodeBlocksAt(Addr A) {\n    return code_block_range(\n        code_block_range::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindCodeBlocksAt<Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindCodeBlocksAt<Module>(A))),\n        code_block_range::iterator());\n  }\n\n  /// \\brief Find all the code blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are between the addresses.\n  code_block_range findCodeBlocksAt(Addr Low, Addr High) {\n    return code_block_range(\n        code_block_range::iterator(\n            boost::make_transform_iterator(\n                this->modules_begin(),\n                FindCodeBlocksBetween<Module>(Low, High)),\n            boost::make_transform_iterator(\n                this->modules_end(), FindCodeBlocksBetween<Module>(Low, High))),\n        code_block_range::iterator());\n  }\n\n  /// \\brief Find all the code blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are at the address \\p A.\n  const_code_block_range findCodeBlocksAt(Addr A) const {\n    return const_code_block_range(\n        const_code_block_range::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindCodeBlocksAt<const Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindCodeBlocksAt<const Module>(A))),\n        const_code_block_range::iterator());\n  }\n\n  /// \\brief Find all the code blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are between the addresses.\n  const_code_block_range findCodeBlocksAt(Addr Low, Addr High) const {\n    return const_code_block_range(\n        const_code_block_range::iterator(\n            boost::make_transform_iterator(\n                this->modules_begin(),\n                FindCodeBlocksBetween<const Module>(Low, High)),\n            boost::make_transform_iterator(\n                this->modules_end(),\n                FindCodeBlocksBetween<const Module>(Low, High))),\n        const_code_block_range::iterator());\n  }\n  /// @}\n  // (end group of CodeBlock-related types and functions)\n\n  /// \\name DataBlock-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using data_block_iterator =\n      MergeSortedIterator<Module::data_block_iterator, AddressLess>;\n  /// \\brief Range of \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using data_block_range = boost::iterator_range<data_block_iterator>;\n  /// \\brief Sub-range of \\ref DataBlock objects overlapping an address or range\n  /// of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using data_block_subrange = boost::iterator_range<\n      MergeSortedIterator<Module::data_block_subrange::iterator, AddressLess>>;\n  /// \\brief Iterator over \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_data_block_iterator =\n      MergeSortedIterator<Module::const_data_block_iterator, AddressLess>;\n  /// \\brief Range of \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending.\n  using const_data_block_range =\n      boost::iterator_range<const_data_block_iterator>;\n  /// \\brief Sub-range of \\ref DataBlock objects overlapping an address or range\n  /// of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_data_block_subrange = boost::iterator_range<MergeSortedIterator<\n      Module::const_data_block_subrange::iterator, AddressLess>>;\n\n  /// \\brief Return an iterator to the first \\ref DataBlock.\n  data_block_iterator data_blocks_begin() {\n    return data_block_iterator(\n        boost::make_transform_iterator(this->modules_begin(),\n                                       NodeToDataBlockRange<Module>()),\n        boost::make_transform_iterator(this->modules_end(),\n                                       NodeToDataBlockRange<Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// DataBlock.\n  data_block_iterator data_blocks_end() { return data_block_iterator(); }\n\n  /// \\brief Return a range of all the \\ref DataBlock objects.\n  data_block_range data_blocks() {\n    return boost::make_iterator_range(data_blocks_begin(), data_blocks_end());\n  }\n\n  /// \\brief Return an iterator to the first \\ref DataBlock.\n  const_data_block_iterator data_blocks_begin() const {\n    return const_data_block_iterator(\n        boost::make_transform_iterator(this->modules_begin(),\n                                       NodeToDataBlockRange<const Module>()),\n        boost::make_transform_iterator(this->modules_end(),\n                                       NodeToDataBlockRange<const Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// DataBlock.\n  const_data_block_iterator data_blocks_end() const {\n    return const_data_block_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref DataBlock objects.\n  const_data_block_range data_blocks() const {\n    return boost::make_iterator_range(data_blocks_begin(), data_blocks_end());\n  }\n\n  /// \\brief Find all the data blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataNode object that intersect the address \\p A.\n  data_block_subrange findDataBlocksOn(Addr A) {\n    return data_block_subrange(\n        data_block_subrange::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindDataBlocksIn<Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindDataBlocksIn<Module>(A))),\n        data_block_subrange::iterator());\n  }\n\n  /// \\brief Find all the data blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataNode object that intersect the address \\p A.\n  const_data_block_subrange findDataBlocksOn(Addr A) const {\n    return const_data_block_subrange(\n        const_data_block_subrange::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindDataBlocksIn<const Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindDataBlocksIn<const Module>(A))),\n        const_data_block_subrange::iterator());\n  }\n\n  /// \\brief Find all the data blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are at the address \\p A.\n  data_block_range findDataBlocksAt(Addr A) {\n    return data_block_range(\n        data_block_range::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindDataBlocksAt<Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindDataBlocksAt<Module>(A))),\n        data_block_range::iterator());\n  }\n\n  /// \\brief Find all the data blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are between the addresses.\n  data_block_range findDataBlocksAt(Addr Low, Addr High) {\n    return data_block_range(\n        data_block_range::iterator(\n            boost::make_transform_iterator(\n                this->modules_begin(),\n                FindDataBlocksBetween<Module>(Low, High)),\n            boost::make_transform_iterator(\n                this->modules_end(), FindDataBlocksBetween<Module>(Low, High))),\n        data_block_range::iterator());\n  }\n\n  /// \\brief Find all the data blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are at the address \\p A.\n  const_data_block_range findDataBlocksAt(Addr A) const {\n    return const_data_block_range(\n        const_data_block_range::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindDataBlocksAt<const Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindDataBlocksAt<const Module>(A))),\n        const_data_block_range::iterator());\n  }\n\n  /// \\brief Find all the data blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are between the addresses.\n  const_data_block_range findDataBlocksAt(Addr Low, Addr High) const {\n    return const_data_block_range(\n        const_data_block_range::iterator(\n            boost::make_transform_iterator(\n                this->modules_begin(),\n                FindDataBlocksBetween<const Module>(Low, High)),\n            boost::make_transform_iterator(\n                this->modules_end(),\n                FindDataBlocksBetween<const Module>(Low, High))),\n        const_data_block_range::iterator());\n  }\n  /// @}\n  // (end group of DataBlock-related types and functions)\n\n  /// \\name SymbolicExpression-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in address order, ascending.\n  using symbolic_expression_iterator =\n      MergeSortedIterator<Module::symbolic_expression_iterator,\n                          ByteInterval::SymbolicExpressionElement::AddressLess>;\n  /// \\brief Range of \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in address order, ascending.\n  using symbolic_expression_range =\n      boost::iterator_range<symbolic_expression_iterator>;\n  /// \\brief Iterator over \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in address order, ascending.\n  using const_symbolic_expression_iterator = MergeSortedIterator<\n      Module::const_symbolic_expression_iterator,\n      ByteInterval::ConstSymbolicExpressionElement::AddressLess>;\n  /// \\brief Range of \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in address order, ascending.\n  using const_symbolic_expression_range =\n      boost::iterator_range<const_symbolic_expression_iterator>;\n\n  /// \\brief Return an iterator to the first \\ref SymbolicExpression.\n  symbolic_expression_iterator symbolic_expressions_begin() {\n    return symbolic_expression_iterator(\n        boost::make_transform_iterator(this->modules_begin(),\n                                       NodeToSymbolicExpressionRange<Module>()),\n        boost::make_transform_iterator(\n            this->modules_end(), NodeToSymbolicExpressionRange<Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// SymbolicExpression.\n  symbolic_expression_iterator symbolic_expressions_end() {\n    return symbolic_expression_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref SymbolicExpression objects.\n  symbolic_expression_range symbolic_expressions() {\n    return boost::make_iterator_range(symbolic_expressions_begin(),\n                                      symbolic_expressions_end());\n  }\n\n  /// \\brief Return an iterator to the first \\ref SymbolicExpression.\n  const_symbolic_expression_iterator symbolic_expressions_begin() const {\n    return const_symbolic_expression_iterator(\n        boost::make_transform_iterator(\n            this->modules_begin(),\n            NodeToSymbolicExpressionRange<const Module>()),\n        boost::make_transform_iterator(\n            this->modules_end(),\n            NodeToSymbolicExpressionRange<const Module>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// SymbolicExpression.\n  const_symbolic_expression_iterator symbolic_expressions_end() const {\n    return const_symbolic_expression_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref SymbolicExpression objects.\n  const_symbolic_expression_range symbolic_expressions() const {\n    return boost::make_iterator_range(symbolic_expressions_begin(),\n                                      symbolic_expressions_end());\n  }\n\n  /// \\brief Find all the symbolic expressions that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are at the address\n  /// \\p A.\n  symbolic_expression_range findSymbolicExpressionsAt(Addr A) {\n    return symbolic_expression_range(\n        symbolic_expression_range::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindSymExprsAt<Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindSymExprsAt<Module>(A))),\n        symbolic_expression_range::iterator());\n  }\n\n  /// \\brief Find all the symbolic expressions that start between a range of\n  /// addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are between the\n  /// addresses.\n  symbolic_expression_range findSymbolicExpressionsAt(Addr Low, Addr High) {\n    return symbolic_expression_range(\n        symbolic_expression_range::iterator(\n            boost::make_transform_iterator(\n                this->modules_begin(), FindSymExprsBetween<Module>(Low, High)),\n            boost::make_transform_iterator(\n                this->modules_end(), FindSymExprsBetween<Module>(Low, High))),\n        symbolic_expression_range::iterator());\n  }\n\n  /// \\brief Find all the symbolic expressions that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are at the address\n  /// \\p A.\n  const_symbolic_expression_range findSymbolicExpressionsAt(Addr A) const {\n    return const_symbolic_expression_range(\n        const_symbolic_expression_range::iterator(\n            boost::make_transform_iterator(this->modules_begin(),\n                                           FindSymExprsAt<const Module>(A)),\n            boost::make_transform_iterator(this->modules_end(),\n                                           FindSymExprsAt<const Module>(A))),\n        const_symbolic_expression_range::iterator());\n  }\n\n  /// \\brief Find all the symbolic expressions that start between a range of\n  /// addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are between the\n  /// addresses.\n  const_symbolic_expression_range findSymbolicExpressionsAt(Addr Low,\n                                                            Addr High) const {\n    return const_symbolic_expression_range(\n        const_symbolic_expression_range::iterator(\n            boost::make_transform_iterator(\n                this->modules_begin(),\n                FindSymExprsBetween<const Module>(Low, High)),\n            boost::make_transform_iterator(\n                this->modules_end(),\n                FindSymExprsBetween<const Module>(Low, High))),\n        const_symbolic_expression_range::iterator());\n  }\n  /// @}\n  // (end group of SymbolicExpression-related types and functions)\n\n  /// \\cond INTERNAL\n  static bool classof(const Node* N) { return N->getKind() == Kind::IR; }\n  /// \\endcond\n\n  /// \\brief Get the version of the Protobuf used when creating this IR.\n  ///\n  /// Backwards-incompatible changes to the Protobuf structure of GTIRB cause\n  /// this verison number to increment.\n  uint32_t getVersion() const { return Version; }\n\n  /// \\brief Set the version of the Protobuf used when creating this IR.\n  ///\n  /// Backwards-incompatible changes to the Protobuf structure of GTIRB cause\n  /// this verison number to increment. This function is useful when, for\n  /// example, migrating GTIRB from old versions to new versions of the Protobuf\n  /// format.\n  void setVersion(uint32_t V) { Version = V; }\n\nprivate:\n  /// @cond INTERNAL\n  /// \\brief The protobuf message type used for serializing IR.\n  using MessageType = proto::IR;\n\n  /// \\brief Serialize into a protobuf message.\n  ///\n  /// \\param[out] Message   Serialize into this message.\n  ///\n  /// \\return void\n  void toProtobuf(MessageType* Message) const;\n\n  /// \\brief Construct a IR from a protobuf message.\n  ///\n  /// \\param C   The Context in which the deserialized IR will be held.\n  /// \\param Message  The protobuf message from which to deserialize.\n  ///\n  /// \\return The deserialized IR object, or null on failure.\n  static ErrorOr<IR*> fromProtobuf(Context& C, const MessageType& Message);\n  /// @endcond\n\n  ModuleSet Modules;\n  uint32_t Version{GTIRB_PROTOBUF_VERSION};\n  CFG Cfg;\n\n  std::unique_ptr<ModuleObserver> MO;\n\n  friend class Context; // Allow Context to construct new IRs.\n};\n\n/// \\brief The error category used to represent load failures.\n/// \\return The load failure error category.\nGTIRB_EXPORT_API const std::error_category& loadErrorCategory();\n\n/// \\brief Makes an \\ref std::error_code object from an \\ref IR::load_error\n/// object.\n/// \\return The error code.\ninline std::error_code make_error_code(gtirb::IR::load_error e) {\n  return std::error_code(static_cast<int>(e), loadErrorCategory());\n}\n\n} // namespace gtirb\n\nnamespace std {\ntemplate <>\nstruct is_error_code_enum<gtirb::IR::load_error> : std::true_type {};\n} // namespace std\n\n#endif // GTIRB_IR_H\n"
  },
  {
    "path": "include/gtirb/Module.hpp",
    "content": "//===- Module.hpp -----------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2021 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_MODULE_H\n#define GTIRB_MODULE_H\n\n#include <gtirb/Addr.hpp>\n#include <gtirb/AuxDataContainer.hpp>\n#include <gtirb/DataBlock.hpp>\n#include <gtirb/Export.hpp>\n#include <gtirb/Node.hpp>\n#include <gtirb/Observer.hpp>\n#include <gtirb/Section.hpp>\n#include <gtirb/Symbol.hpp>\n#include <gtirb/SymbolicExpression.hpp>\n#include <gtirb/Utility.hpp>\n#include <gtirb/proto/Module.pb.h>\n#include <algorithm>\n#include <boost/icl/interval_map.hpp>\n#include <boost/iterator/indirect_iterator.hpp>\n#include <boost/iterator/iterator_traits.hpp>\n#include <boost/iterator/transform_iterator.hpp>\n#include <boost/multi_index/hashed_index.hpp>\n#include <boost/multi_index/key_extractors.hpp>\n#include <boost/multi_index/mem_fun.hpp>\n#include <boost/multi_index/ordered_index.hpp>\n#include <boost/multi_index_container.hpp>\n#include <boost/range/iterator_range.hpp>\n#include <cstdint>\n#include <functional>\n#include <optional>\n#include <string>\n\n/// \\file Module.hpp\n/// \\brief Class gtirb::Module and related functions and types.\n\nnamespace gtirb {\nclass ByteInterval;\nclass IR;\nclass ModuleObserver;\n\ntemplate <class T> class ErrorOr;\n\n/// \\enum FileFormat\n///\n/// \\brief Identifies an exectuable file format.\nenum class FileFormat : uint8_t {\n  Undefined = proto::Format_Undefined, ///< Default value indicates an\n                                       ///< uninitialized state.\n  COFF = proto::COFF,                  ///< Common Object File Format (COFF)\n  ELF = proto::ELF, ///< Executable and Linkable Format (ELF, formerly named\n                    ///< Extensible Linking Format)\n  PE = proto::PE,   ///< Microsoft Portable Executable (PE) format.\n  IdaProDb32 = proto::IdaProDb32, ///< IDA Pro database file\n  IdaProDb64 = proto::IdaProDb64, ///< IDA Pro database file\n  XCOFF = proto::XCOFF, ///< Non-COFF (files start with ANON_OBJECT_HEADER*)\n  MACHO = proto::MACHO, ///< Mach object file format\n  RAW = proto::RAW      ///< Raw binary file (no format)\n};\n\n/// \\enum ISAID\n///\n/// \\brief Idenfities an instruction set.\nenum class ISA : uint8_t {\n  Undefined = proto::ISA_Undefined, ///< Default value to indicates an\n                                    ///< uninitialized state.\n  IA32 = proto::IA32,   ///< Intel Architecture, 32-bit. Also known as i386.\n  PPC32 = proto::PPC32, ///< Performance Optimization With Enhanced RISC –\n                        ///< Performance Computing, 32-bit.\n  X64 = proto::X64,     ///< The generic name for the 64-bit\n                        ///< extensions to both Intel's and AMD's 32-bit\n                        ///< x86 instruction set architecture (ISA).\n  ARM = proto::ARM,     ///< Advanced RISC Machine, also known as Acorn RISC\n                        ///< Machine, 32-bit.\n  ValidButUnsupported = proto::ValidButUnsupported,\n  PPC64 = proto::PPC64,   ///< Performance Optimization With Enhanced RISC –\n                          ///< Performance Computing, 64-bit.\n  ARM64 = proto::ARM64,   ///< Advanced RISC Machine, also known as Acorn RISC\n                          ///< Machine, 64-bit.\n  MIPS32 = proto::MIPS32, ///< Microprocessor without Interlocked Pipelined\n                          ///< Stages, 32-bit.\n  MIPS64 = proto::MIPS64  ///< Microprocessor without Interlocked Pipelined\n                          ///< Stages, 64-bit.\n};\n\nenum class ByteOrder : uint8_t {\n  Undefined = proto::ByteOrder_Undefined, ///< Unknown or uninitialized\n                                          ///< endianness.\n  Big = proto::BigEndian,                 ///< Big endian.\n  Little = proto::LittleEndian,           ///< Little endian.\n};\n\n/// \\class Module\n///\n/// \\brief Represents a single binary (library or executable).\nclass GTIRB_EXPORT_API Module : public AuxDataContainer {\n  struct by_address {};\n  struct by_name {};\n  struct by_pointer {};\n  struct by_referent {};\n\n  // Helper function for extracting the referent of a Symbol.\n  static const Node* get_symbol_referent(const Symbol& S) {\n    if (std::optional<const Node*> Res =\n            S.visit([](const Node* N) { return N; })) {\n      return *Res;\n    }\n    return nullptr;\n  }\n\n  using ProxyBlockSet = std::unordered_set<ProxyBlock*>;\n\n  using SectionSet = boost::multi_index::multi_index_container<\n      Section*, boost::multi_index::indexed_by<\n                    boost::multi_index::ordered_non_unique<\n                        boost::multi_index::tag<by_address>,\n                        boost::multi_index::identity<Section*>, AddressLess>,\n                    boost::multi_index::ordered_non_unique<\n                        boost::multi_index::tag<by_name>,\n                        boost::multi_index::const_mem_fun<\n                            Section, const std::string&, &Section::getName>>,\n                    boost::multi_index::hashed_unique<\n                        boost::multi_index::tag<by_pointer>,\n                        boost::multi_index::identity<Section*>>>>;\n  using SectionIntMap =\n      boost::icl::interval_map<Addr, std::set<Section*, AddressLess>>;\n\n  using SymbolSet = boost::multi_index::multi_index_container<\n      Symbol*,\n      boost::multi_index::indexed_by<\n          boost::multi_index::ordered_non_unique<\n              boost::multi_index::tag<by_address>,\n              boost::multi_index::const_mem_fun<Symbol, std::optional<Addr>,\n                                                &Symbol::getAddress>>,\n          boost::multi_index::ordered_non_unique<\n              boost::multi_index::tag<by_name>,\n              boost::multi_index::const_mem_fun<Symbol, const std::string&,\n                                                &Symbol::getName>>,\n          boost::multi_index::hashed_unique<\n              boost::multi_index::tag<by_pointer>,\n              boost::multi_index::identity<Symbol*>>,\n          boost::multi_index::hashed_non_unique<\n              boost::multi_index::tag<by_referent>,\n              boost::multi_index::global_fun<const Symbol&, const Node*,\n                                             &get_symbol_referent>>>>;\n\n  class SectionObserverImpl;\n  class SymbolObserverImpl;\n\n  Module(Context& C, const std::string& N);\n  Module(Context& C, const std::string& N, const UUID& U);\n\n  static Module* Create(Context& C, const std::string& N, const UUID& U) {\n    return C.Create<Module>(C, N, U);\n  }\n\npublic:\n  /// \\brief Create a Module object.\n  ///\n  /// \\param C      The Context in which this object will be held.\n  /// \\param Name   The name of this module.\n  ///\n  /// \\return The newly created object.\n  static Module* Create(Context& C, const std::string& Name) {\n    return C.Create<Module>(C, Name);\n  }\n\n  /// \\brief Get the \\ref IR this module belongs to.\n  const IR* getIR() const { return Parent; }\n  /// \\brief Get the \\ref IR this module belongs to.\n  IR* getIR() { return Parent; }\n\n  /// \\brief Set the location of the corresponding binary on disk.\n  ///\n  /// This is for informational purposes only and will not be used to open\n  /// the image, so it does not need to be the path of an existing file.\n  ///\n  /// \\param X The path name to use.\n  void setBinaryPath(const std::string& X) { BinaryPath = X; }\n\n  /// \\brief Get the location of the corresponding binary on disk.\n  ///\n  /// \\return   The path to the corresponding binary on disk.\n  const std::string& getBinaryPath() const { return BinaryPath; }\n\n  /// \\brief Set the format of the binary pointed to by getBinaryPath().\n  ///\n  /// \\param X   The format of the binary associated with \\c this, as a\n  ///            gtirb::FileFormat enumerator.\n  void setFileFormat(gtirb::FileFormat X) { this->FileFormat = X; }\n\n  /// \\brief Get the format of the binary pointed to by getBinaryPath().\n  ///\n  /// \\return   The format of the binary associated with \\c this, as a\n  ///           gtirb::FileFormat enumerator.\n  gtirb::FileFormat getFileFormat() const { return this->FileFormat; }\n\n  /// \\brief Set the difference between this module's\n  /// \\ref Module::setPreferredAddr \"preferred address\" and the address where it\n  /// was actually loaded.\n  ///\n  /// \\param X The rebase delta.\n  ///\n  /// \\return void\n  void setRebaseDelta(int64_t X) { RebaseDelta = X; }\n\n  /// \\brief Get the difference between this module's\n  /// \\ref Module::setPreferredAddr \"preferred address\" and\n  /// the address where it was actually loaded.\n  ///\n  /// \\return The rebase delta.\n  int64_t getRebaseDelta() const { return RebaseDelta; }\n\n  /// \\brief Set the preferred address for loading this module.\n  ///\n  /// \\param X The address to use.\n  ///\n  /// \\return void\n  /// \\sa setRebaseDelta\n  void setPreferredAddr(gtirb::Addr X) { PreferredAddr = X; }\n\n  /// \\brief Get the preferred address for loading this module.\n  ///\n  /// \\return The preferred address.\n  /// \\sa getRebaseDelta\n  gtirb::Addr getPreferredAddr() const { return PreferredAddr; }\n\n  /// \\brief Has the image been loaded somewhere other than its preferred\n  /// address?\n  ///\n  /// \\return \\c true if the loaded image has been relocated, \\c false\n  /// otherwise.\n  ///\n  /// \\sa getPreferredAddr\n  /// \\sa getRebaseDelta\n  bool isRelocated() const { return RebaseDelta != 0; }\n\n  /// \\brief Set the ISA of the instructions in this Module.\n  ///\n  /// \\param X The ISA ID to set.\n  void setISA(gtirb::ISA X) { Isa = X; }\n\n  /// \\brief Get the ISA of the instructions in this Module.\n  ///\n  /// \\return The ISA ID.\n  gtirb::ISA getISA() const { return Isa; }\n\n  /// \\brief Set the endianness of the instructions in this Module.\n  ///\n  /// \\param X The endianness to set.\n  void setByteOrder(gtirb::ByteOrder X) { ByteOrder = X; }\n\n  /// \\brief Get the endianness of the instructions in this Module.\n  ///\n  /// \\return The endianness.\n  gtirb::ByteOrder getByteOrder() const { return ByteOrder; }\n\n  /// \\brief Get the entry point of this module, or null if not present.\n  const CodeBlock* getEntryPoint() const { return EntryPoint; }\n  /// \\brief Get the entry point of this module, or null if not present.\n  CodeBlock* getEntryPoint() { return EntryPoint; }\n\n  /// \\brief Set the entry point of this module.\n  ///\n  /// \\param CB The entry point of this module, or null if not present.\n  void setEntryPoint(CodeBlock* CB) { EntryPoint = CB; }\n\n  /// \\name ProxyBlock-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over proxy_blocks (\\ref ProxyBlock).\n  using proxy_block_iterator =\n      boost::indirect_iterator<ProxyBlockSet::iterator>;\n  /// \\brief Range of proxy_blocks (\\ref ProxyBlock).\n  using proxy_block_range = boost::iterator_range<proxy_block_iterator>;\n  /// \\brief Constant iterator over proxy_blocks (\\ref ProxyBlock).\n  using const_proxy_block_iterator =\n      boost::indirect_iterator<ProxyBlockSet::const_iterator, const ProxyBlock>;\n  /// \\brief Constant range of proxy_blocks (\\ref ProxyBlock).\n  using const_proxy_block_range =\n      boost::iterator_range<const_proxy_block_iterator>;\n\n  /// \\brief Return an iterator to the first ProxyBlock.\n  proxy_block_iterator proxy_blocks_begin() {\n    return proxy_block_iterator(ProxyBlocks.begin());\n  }\n  /// \\brief Return a constant iterator to the first ProxyBlock.\n  const_proxy_block_iterator proxy_blocks_begin() const {\n    return const_proxy_block_iterator(ProxyBlocks.begin());\n  }\n  /// \\brief Return an iterator to the element following the last ProxyBlock.\n  proxy_block_iterator proxy_blocks_end() {\n    return proxy_block_iterator(ProxyBlocks.end());\n  }\n  /// \\brief Return a constant iterator to the element following the last\n  /// ProxyBlock.\n  const_proxy_block_iterator proxy_blocks_end() const {\n    return const_proxy_block_iterator(ProxyBlocks.end());\n  }\n  /// \\brief Return a range of the proxy_blocks (\\ref ProxyBlock).\n  proxy_block_range proxy_blocks() {\n    return boost::make_iterator_range(proxy_blocks_begin(), proxy_blocks_end());\n  }\n  /// \\brief Return a constant range of the proxy_blocks (\\ref ProxyBlock).\n  const_proxy_block_range proxy_blocks() const {\n    return boost::make_iterator_range(proxy_blocks_begin(), proxy_blocks_end());\n  }\n\n  /// \\brief Remove a \\ref ProxyBlock object located in this module.\n  ///\n  /// \\param B The \\ref ProxyBlock object to remove.\n  ///\n  /// \\return Whether the operation succeeded (\\c Accepted), made no change\n  /// (\\c NoChange), or could not be completed (\\c Rejected). In particular,\n  /// if the node to remove is not actually part of this node to begin with,\n  /// the result will be \\c NoChange.\n  ChangeStatus removeProxyBlock(ProxyBlock* B);\n\n  /// \\brief Adds a new \\ref ProxyBlock in this module.\n  ///\n  /// \\param PB The \\ref ProxyBlock object to add.\n  ///\n  /// \\return a ChangeStatus indicating whether the insertion took place\n  /// (\\c Accepted), was unnecessary because this node already contained the\n  /// ProxyBlock (\\c NoChange), or could not be completed (\\c Rejected).\n  ChangeStatus addProxyBlock(ProxyBlock* PB);\n\n  /// \\brief Creates a new \\ref ProxyBlock in this module.\n  ///\n  /// \\tparam Args  The arguments to construct a \\ref ProxyBlock.\n  /// \\param  C     The Context in which this object will be held.\n  /// \\param  A     The arguments to construct a \\ref ProxyBlock.\n  ///\n  /// \\return the created ProxyBlock.\n  template <typename... Args>\n  ProxyBlock* addProxyBlock(Context& C, Args&&... A) {\n    ProxyBlock* PB = ProxyBlock::Create(C, std::forward<Args>(A)...);\n    [[maybe_unused]] ChangeStatus status = addProxyBlock(PB);\n    // addProxyBlock(ProxyBlock*) does not currently reject any changes and,\n    // because we just created the ProxyBlock to add, it cannot result in\n    // NoChange.\n    assert(status == ChangeStatus::Accepted &&\n           \"unexpected result when inserting ProxyBlock\");\n    return PB;\n  }\n\n  /// @}\n  // (end of ProxyBlock-Related Public Types and Functions)\n\n  /// \\name Symbol-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over symbols (\\ref Symbol).\n  ///\n  /// This iterator returns symbols in an arbitrary order.\n  using symbol_iterator =\n      boost::indirect_iterator<SymbolSet::index<by_pointer>::type::iterator>;\n  /// \\brief Range of symbols (\\ref Symbol).\n  ///\n  /// This range returns symbols in an arbitrary order.\n  using symbol_range = boost::iterator_range<symbol_iterator>;\n  /// \\brief Constant iterator over symbols (\\ref Symbol).\n  ///\n  /// This iterator returns symbols in an arbitrary order.\n  using const_symbol_iterator = boost::indirect_iterator<\n      SymbolSet::index<by_pointer>::type::const_iterator, const Symbol>;\n  /// \\brief Constant range of symbols (\\ref Symbol).\n  ///\n  /// This range returns symbols in an arbitrary order.\n  using const_symbol_range = boost::iterator_range<const_symbol_iterator>;\n\n  /// \\brief Iterator over symbols (\\ref Symbol).\n  ///\n  /// This iterator returns symbols in name order. If two Symbols have the same\n  /// name, their order is unspecified.\n  using symbol_name_iterator =\n      boost::indirect_iterator<SymbolSet::index<by_name>::type::iterator>;\n  /// \\brief Range of symbols (\\ref Symbol).\n  ///\n  /// This range returns symbols in name order. If two Symbols have the same\n  /// name, their order is unspecified.\n  using symbol_name_range = boost::iterator_range<symbol_name_iterator>;\n  /// \\brief Constant iterator over symbols (\\ref Symbol).\n  ///\n  /// This iterator returns symbols in name order. If two Symbols have the same\n  /// name, their order is unspecified.\n  using const_symbol_name_iterator =\n      boost::indirect_iterator<SymbolSet::index<by_name>::type::const_iterator,\n                               const Symbol>;\n  /// \\brief Constant range of symbols (\\ref Symbol).\n  ///\n  /// This range returns symbols in name order. If two Symbols have the same\n  /// name, their order is unspecified.\n  using const_symbol_name_range =\n      boost::iterator_range<const_symbol_name_iterator>;\n\n  /// \\brief Iterator over symbols (\\ref Symbol).\n  ///\n  /// This iterator returns symbols in address order. If two Symbols have the\n  /// same address, their order is unspecified.\n  using symbol_addr_iterator =\n      boost::indirect_iterator<SymbolSet::index<by_address>::type::iterator>;\n  /// \\brief Range of symbols (\\ref Symbol).\n  ///\n  /// This range returns symbols in address order. If two Symbols have the same\n  /// address, their order is unspecified.\n  using symbol_addr_range = boost::iterator_range<symbol_addr_iterator>;\n  /// \\brief Constant iterator over symbols (\\ref Symbol).\n  ///\n  /// This iterator returns symbols in address order. If two Symbols have the\n  /// same address, their order is unspecified.\n  using const_symbol_addr_iterator = boost::indirect_iterator<\n      SymbolSet::index<by_address>::type::const_iterator, const Symbol>;\n  /// \\brief Constant range of symbols (\\ref Symbol).\n  ///\n  /// This range returns symbols in address order. If two Symbols have the same\n  /// address, their order is unspecified.\n  using const_symbol_addr_range =\n      boost::iterator_range<const_symbol_addr_iterator>;\n\n  /// \\brief Iterator over symbols (\\ref Symbol).\n  ///\n  /// The order in which this iterator returns symbols is not specified.\n  using symbol_ref_iterator =\n      boost::indirect_iterator<SymbolSet::index<by_referent>::type::iterator>;\n  /// \\brief Range of symbols (\\ref Symbol).\n  ///\n  /// The order of the symbols in this range is not specified.\n  using symbol_ref_range = boost::iterator_range<symbol_ref_iterator>;\n  /// \\brief Constant iterator over symbols (\\ref Symbol).\n  ///\n  /// The order in which this iterator returns symbols is not specified.\n  using const_symbol_ref_iterator = boost::indirect_iterator<\n      SymbolSet::index<by_referent>::type::const_iterator, const Symbol>;\n  /// \\brief Constant range of symbols (\\ref Symbol).\n  ///\n  /// The order of the symbols in this range is not specified.\n  using const_symbol_ref_range =\n      boost::iterator_range<const_symbol_ref_iterator>;\n\n  /// \\brief Return an iterator to the first Symbol.\n  symbol_iterator symbols_begin() {\n    return symbol_iterator(Symbols.get<by_pointer>().begin());\n  }\n  /// \\brief Return a constant iterator to the first Symbol.\n  const_symbol_iterator symbols_begin() const {\n    return const_symbol_iterator(Symbols.get<by_pointer>().begin());\n  }\n  /// \\brief Return an iterator to the element following the last Symbol.\n  symbol_iterator symbols_end() {\n    return symbol_iterator(Symbols.get<by_pointer>().end());\n  }\n  /// \\brief Return a constant iterator to the element following the last\n  /// Symbol.\n  const_symbol_iterator symbols_end() const {\n    return const_symbol_iterator(Symbols.get<by_pointer>().end());\n  }\n  /// \\brief Return a range of the symbols (\\ref Symbol).\n  symbol_range symbols() {\n    return boost::make_iterator_range(symbols_begin(), symbols_end());\n  }\n  /// \\brief Return a constant range of the symbols (\\ref Symbol).\n  const_symbol_range symbols() const {\n    return boost::make_iterator_range(symbols_begin(), symbols_end());\n  }\n\n  /// \\brief Return an iterator to the first Symbol, ordered by name.\n  symbol_name_iterator symbols_by_name_begin() {\n    return symbol_name_iterator(Symbols.get<by_name>().begin());\n  }\n  /// \\brief Return a constant iterator to the first Symbol, ordered by name.\n  const_symbol_name_iterator symbols_by_name_begin() const {\n    return const_symbol_name_iterator(Symbols.get<by_name>().begin());\n  }\n  /// \\brief Return an iterator to the element following the last Symbol,\n  /// ordered by name.\n  symbol_name_iterator symbols_by_name_end() {\n    return symbol_name_iterator(Symbols.get<by_name>().end());\n  }\n  /// \\brief Return a constant iterator to the element following the last\n  /// Symbol, ordered by name.\n  const_symbol_name_iterator symbols_by_name_end() const {\n    return const_symbol_name_iterator(Symbols.get<by_name>().end());\n  }\n  /// \\brief Return a range of the symbols (\\ref Symbol), ordered by name.\n  symbol_name_range symbols_by_name() {\n    return boost::make_iterator_range(symbols_by_name_begin(),\n                                      symbols_by_name_end());\n  }\n  /// \\brief Return a constant range of the symbols (\\ref Symbol), ordered by\n  /// name.\n  const_symbol_name_range symbols_by_name() const {\n    return boost::make_iterator_range(symbols_by_name_begin(),\n                                      symbols_by_name_end());\n  }\n\n  /// \\brief Return an iterator to the first Symbol, ordered by address.\n  symbol_addr_iterator symbols_by_addr_begin() {\n    return symbol_addr_iterator(Symbols.get<by_address>().begin());\n  }\n  /// \\brief Return a constant iterator to the first Symbol, ordered by address.\n  const_symbol_addr_iterator symbols_by_addr_begin() const {\n    return const_symbol_addr_iterator(Symbols.get<by_address>().begin());\n  }\n  /// \\brief Return an iterator to the element following the last Symbol,\n  /// ordered by address.\n  symbol_addr_iterator symbols_by_addr_end() {\n    return symbol_addr_iterator(Symbols.get<by_address>().end());\n  }\n  /// \\brief Return a constant iterator to the element following the last\n  /// Symbol, ordered by address.\n  const_symbol_addr_iterator symbols_by_addr_end() const {\n    return const_symbol_addr_iterator(Symbols.get<by_address>().end());\n  }\n  /// \\brief Return a range of the symbols (\\ref Symbol), ordered by address.\n  symbol_addr_range symbols_by_addr() {\n    return boost::make_iterator_range(symbols_by_addr_begin(),\n                                      symbols_by_addr_end());\n  }\n  /// \\brief Return a constant range of the symbols (\\ref Symbol), ordered by\n  /// address.\n  const_symbol_addr_range symbols_by_addr() const {\n    return boost::make_iterator_range(symbols_by_addr_begin(),\n                                      symbols_by_addr_end());\n  }\n\n  /// \\brief Remove a \\ref Symbol object located in this module.\n  ///\n  /// \\param S The \\ref Symbol object to remove.\n  ///\n  /// \\return Whether or not the operation succeeded. This operation can\n  /// fail if the node to remove is not actually part of this node to begin\n  /// with.\n  bool removeSymbol(Symbol* S) {\n    auto& Index = Symbols.get<by_pointer>();\n    if (auto Iter = Index.find(S); Iter != Index.end()) {\n      Index.erase(Iter);\n      S->setParent(nullptr, nullptr);\n      return true;\n    }\n    return false;\n  }\n\n  /// \\brief Move a \\ref Symbol object to be located in this module.\n  ///\n  /// \\param S The \\ref Symbol object to add.\n  Symbol* addSymbol(Symbol* S) {\n    if (S->getModule()) {\n      S->getModule()->removeSymbol(S);\n    }\n    Symbols.emplace(S);\n    S->setParent(this, SymObs.get());\n    return S;\n  }\n\n  /// \\brief Creates a new \\ref Symbol in this module.\n  ///\n  /// \\tparam Args  The arguments to construct a \\ref Symbol.\n  /// \\param  C     The Context in which this object will be held.\n  /// \\param  A     The arguments to construct a \\ref Symbol.\n  template <typename... Args> Symbol* addSymbol(Context& C, Args... A) {\n    return addSymbol(Symbol::Create(C, A...));\n  }\n\n  /// \\brief Find symbols by name\n  ///\n  /// \\param N The name to look up.\n  ///\n  /// \\return A possibly empty range of all the symbols with the\n  /// given name.\n  symbol_name_range findSymbols(const std::string& N) {\n    auto Found = Symbols.get<by_name>().equal_range(N);\n    return boost::make_iterator_range(Found.first, Found.second);\n  }\n\n  /// \\brief Find symbols by name\n  ///\n  /// \\param N The name to look up.\n  ///\n  /// \\return A possibly empty constant range of all the symbols with the\n  /// given name.\n  const_symbol_name_range findSymbols(const std::string& N) const {\n    auto Found = Symbols.get<by_name>().equal_range(N);\n    return boost::make_iterator_range(Found.first, Found.second);\n  }\n\n  /// \\brief Find symbols by address.\n  ///\n  /// \\param X The address to look up.\n  ///\n  /// \\return A possibly empty range of all the symbols with a referent at the\n  /// given address.\n  symbol_addr_range findSymbols(Addr X) {\n    auto Found = Symbols.get<by_address>().equal_range(X);\n    return boost::make_iterator_range(Found.first, Found.second);\n  }\n\n  /// \\brief Find symbols by address.\n  ///\n  /// \\param X The address to look up.\n  ///\n  /// \\return A possibly empty constant range of all the symbols with a referent\n  /// at the given address.\n  const_symbol_addr_range findSymbols(Addr X) const {\n    auto Found = Symbols.get<by_address>().equal_range(X);\n    return boost::make_iterator_range(Found.first, Found.second);\n  }\n\n  /// \\brief Find symbols by a range of addresses.\n  ///\n  /// \\param Lower The lower-bounded address to look up.\n  /// \\param Upper The upper-bounded address to look up.\n  ///\n  /// \\return A possibly empty range of all the symbols within the given\n  /// address range. Searches the range [Lower, Upper).\n  symbol_addr_range findSymbols(Addr Lower, Addr Upper) {\n    auto& Index = Symbols.get<by_address>();\n    return boost::make_iterator_range(Index.lower_bound(Lower),\n                                      Index.lower_bound(Upper));\n  }\n\n  /// \\brief Find symbols by a range of addresses.\n  ///\n  /// \\param Lower The lower-bounded address to look up.\n  /// \\param Upper The upper-bounded address to look up.\n  ///\n  /// \\return A possibly empty constant range of all the symbols within the\n  /// given address range. Searches the range [Lower, Upper).\n  const_symbol_addr_range findSymbols(Addr Lower, Addr Upper) const {\n    auto& Index = Symbols.get<by_address>();\n    return boost::make_iterator_range(Index.lower_bound(Lower),\n                                      Index.lower_bound(Upper));\n  }\n\n  /// \\brief Find symbols by their referent object.\n  ///\n  /// \\param Referent The object the symbol refers to.\n  ///\n  /// \\return A possibly empty range of all the symbols that refer to the given\n  /// object.\n  symbol_ref_range findSymbols(const Node& Referent) {\n    return Symbols.get<by_referent>().equal_range(&Referent);\n  }\n\n  /// \\brief Find symbols by their referent object.\n  ///\n  /// \\param Referent The object the symbol refers to.\n  ///\n  /// \\return A possibly empty range of all the symbols that refer to the given\n  /// object.\n  const_symbol_ref_range findSymbols(const Node& Referent) const {\n    return Symbols.get<by_referent>().equal_range(&Referent);\n  }\n\n  /// @}\n  // (end group of symbol-related type aliases and functions)\n\n  /// \\brief Get the module name.\n  ///\n  /// \\return The name.\n  const std::string& getName() const { return Name; }\n\n  /// \\brief Set the module name.\n  void setName(const std::string& X);\n\n  /// \\name Section-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over sections (\\ref Section).\n  using section_iterator = boost::indirect_iterator<SectionSet::iterator>;\n  /// \\brief Range of sections (\\ref Section).\n  using section_range = boost::iterator_range<section_iterator>;\n  /// \\brief Sub-range of sections overlapping an address (\\ref Section).\n  using section_subrange = boost::iterator_range<\n      boost::indirect_iterator<SectionIntMap::codomain_type::iterator>>;\n  /// \\brief Iterator over sections (\\ref Section).\n  ///\n  /// Sections are returned in name order. If two Sections have the same name,\n  /// their order is not specified.\n  using section_name_iterator =\n      boost::indirect_iterator<SectionSet::index<by_name>::type::iterator>;\n  /// \\brief Range of sections (\\ref Section).\n  ///\n  /// Sections are returned in name order. If two Sections have the same name,\n  /// their order is not specified.\n  using section_name_range = boost::iterator_range<section_name_iterator>;\n  /// \\brief Constant iterator over sections (\\ref Section).\n  ///\n  /// Sections are returned in address order. If two Sections start at the\n  /// same address, the smaller one is returned first. If two Sections have\n  /// the same address and the same size, their order is not specified.\n  using const_section_iterator =\n      boost::indirect_iterator<SectionSet::const_iterator, const Section&>;\n  /// \\brief Constant range of sections (\\ref Section).\n  ///\n  /// Sections are returned in address order. If two Sections start at the\n  /// same address, the smaller one is returned first. If two Sections have\n  /// the same address and the same size, their order is not specified.\n  using const_section_range = boost::iterator_range<const_section_iterator>;\n  /// \\brief Sub-range of sections overlapping an address (\\ref Section).\n  using const_section_subrange = boost::iterator_range<boost::indirect_iterator<\n      SectionIntMap::codomain_type::const_iterator, const Section&>>;\n  /// \\brief Constant iterator over sections (\\ref Section).\n  ///\n  /// Sections are returned in name order. If two Sections have the same name,\n  /// their order is not specified.\n  using const_section_name_iterator =\n      boost::indirect_iterator<SectionSet::index<by_name>::type::const_iterator,\n                               const Section&>;\n  /// \\brief Constant range of sections (\\ref Section).\n  ///\n  /// Sections are returned in name order. If two Sections have the same name,\n  /// their order is not specified.\n  using const_section_name_range =\n      boost::iterator_range<const_section_name_iterator>;\n\n  /// \\brief Return an iterator to the first Section.\n  section_iterator sections_begin() { return Sections.begin(); }\n  /// \\brief Return a constant iterator to the first Section.\n  const_section_iterator sections_begin() const { return Sections.begin(); }\n  /// \\brief Return an iterator to the first Section.\n  section_name_iterator sections_by_name_begin() {\n    return Sections.get<by_name>().begin();\n  }\n  /// \\brief Return a constant iterator to the first Section.\n  const_section_name_iterator sections_by_name_begin() const {\n    return Sections.get<by_name>().begin();\n  }\n  /// \\brief Return an iterator to the element following the last Section.\n  section_iterator sections_end() { return Sections.end(); }\n  /// \\brief Return a constant iterator to the element following the last\n  /// Section.\n  const_section_iterator sections_end() const { return Sections.end(); }\n  /// \\brief Return an iterator to the element following the last Section.\n  section_name_iterator sections_by_name_end() {\n    return Sections.get<by_name>().end();\n  }\n  /// \\brief Return a constant iterator to the element following the last\n  /// Section.\n  const_section_name_iterator sections_by_name_end() const {\n    return Sections.get<by_name>().end();\n  }\n  /// \\brief Return a range of the sections (\\ref Section).\n  section_range sections() {\n    return boost::make_iterator_range(sections_begin(), sections_end());\n  }\n  /// \\brief Return a constant range of the sections (\\ref Section).\n  const_section_range sections() const {\n    return boost::make_iterator_range(sections_begin(), sections_end());\n  }\n\n  /// \\brief Remove a \\ref Section object located in this module.\n  ///\n  /// \\param S The \\ref Section object to remove.\n  ///\n  /// \\return Whether the operation succeeded (\\c Accepted), made no change\n  /// (\\c NoChange), or could not be completed (\\c Rejected). In particular,\n  /// if the node to remove is not actually part of this node to begin with,\n  /// the result will be \\c NoChange.\n  ChangeStatus removeSection(Section* S);\n\n  /// \\brief Move a \\ref Section object to be located in this module.\n  ///\n  /// \\param S The \\ref Section object to add.\n  ///\n  /// \\return a ChangeStatus indicating whether the insertion took place\n  /// (\\c Accepted), was unnecessary because this node already contained the\n  // Section (\\c NoChange), or could not be completed (\\c Rejected).\n  ChangeStatus addSection(Section* S);\n\n  /// \\brief Creates a new \\ref Section in this module.\n  ///\n  /// \\tparam Args  The arguments to construct a \\ref Section.\n  /// \\param  C     The Context in which this object will be held.\n  /// \\param  A     The arguments to construct a \\ref Section.\n  ///\n  /// \\return the created Section.\n  template <typename... Args> Section* addSection(Context& C, Args&&... A) {\n    Section* S = Section::Create(C, std::forward<Args>(A)...);\n    [[maybe_unused]] ChangeStatus status = addSection(S);\n    // addSection(Section*) does not currently reject any changes and, because\n    // we just created the Section to add, it cannot result in NoChange.\n    assert(status == ChangeStatus::Accepted &&\n           \"unexpected result when inserting Section\");\n    return S;\n  }\n\n  /// \\brief Find a Section containing an address.\n  ///\n  /// \\param X The address to look up.\n  ///\n  /// \\return The range of Sections containing the address.\n  section_subrange findSectionsOn(Addr X) {\n    if (auto It = SectionAddrs.find(X); It != SectionAddrs.end()) {\n      return boost::make_iterator_range(It->second.begin(), It->second.end());\n    }\n    return {};\n  }\n\n  /// \\brief Find a Section containing an address.\n  ///\n  /// \\param X The address to look up.\n  ///\n  /// \\return The range of Sections containing the address.\n  const_section_subrange findSectionsOn(Addr X) const {\n    if (auto It = SectionAddrs.find(X); It != SectionAddrs.end()) {\n      return boost::make_iterator_range(It->second.begin(), It->second.end());\n    }\n    return {};\n  }\n\n  /// \\brief Find all the sections that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Section objects that are at the address \\p A.\n  section_range findSectionsAt(Addr A) {\n    auto Pair = Sections.get<by_address>().equal_range(A);\n    return boost::make_iterator_range(section_iterator(Pair.first),\n                                      section_iterator(Pair.second));\n  }\n\n  /// \\brief Find all the sections that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref Section objects that are between the addresses.\n  section_range findSectionsAt(Addr Low, Addr High) {\n    auto& Index = Sections.get<by_address>();\n    return boost::make_iterator_range(\n        section_iterator(Index.lower_bound(Low)),\n        section_iterator(Index.lower_bound(High)));\n  }\n\n  /// \\brief Find all the sections that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Section objects that are at the address \\p A.\n  const_section_range findSectionsAt(Addr A) const {\n    auto Pair = Sections.get<by_address>().equal_range(A);\n    return boost::make_iterator_range(const_section_iterator(Pair.first),\n                                      const_section_iterator(Pair.second));\n  }\n\n  /// \\brief Find all the sections that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref Section objects that are between the addresses.\n  const_section_range findSectionsAt(Addr Low, Addr High) const {\n    auto& Index = Sections.get<by_address>();\n    return boost::make_iterator_range(\n        const_section_iterator(Index.lower_bound(Low)),\n        const_section_iterator(Index.lower_bound(High)));\n  }\n\n  /// \\brief Find a Section by name.\n  ///\n  /// \\param X The name to look up.\n  ///\n  /// \\return A range of \\ref Section objects with the requested name.\n\n  section_name_range findSections(const std::string& X) {\n    auto Pair = Sections.get<by_name>().equal_range(X);\n    return boost::make_iterator_range(section_name_iterator(Pair.first),\n                                      section_name_iterator(Pair.second));\n  }\n\n  /// \\brief Find a Section by name.\n  ///\n  /// \\param X The name to look up.\n  ///\n  /// \\return A range of \\ref Section objects with the requested name.\n  const_section_name_range findSections(const std::string& X) const {\n    auto Pair = Sections.get<by_name>().equal_range(X);\n    return boost::make_iterator_range(const_section_name_iterator(Pair.first),\n                                      const_section_name_iterator(Pair.second));\n  }\n\n  /// @}\n  // (end group of Section-related types and functions)\n\n  /// \\name ByteInterval-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over \\ref ByteInterval objects.\n  using byte_interval_iterator =\n      MergeSortedIterator<Section::byte_interval_iterator, AddressLess>;\n  /// \\brief Range of \\ref ByteInterval objects.\n  using byte_interval_range = boost::iterator_range<byte_interval_iterator>;\n  /// \\brief Sub-range of \\ref ByteInterval objects overlapping addresses.\n  using byte_interval_subrange = boost::iterator_range<MergeSortedIterator<\n      Section::byte_interval_subrange::iterator, AddressLess>>;\n  /// \\brief Const iterator over \\ref ByteInterval objects.\n  using const_byte_interval_iterator =\n      MergeSortedIterator<Section::const_byte_interval_iterator, AddressLess>;\n  /// \\brief Const range of \\ref ByteInterval objects.\n  using const_byte_interval_range =\n      boost::iterator_range<const_byte_interval_iterator>;\n  /// \\brief Sub-range of \\ref ByteInterval objects overlapping addresses.\n  using const_byte_interval_subrange =\n      boost::iterator_range<MergeSortedIterator<\n          Section::const_byte_interval_subrange::iterator, AddressLess>>;\n\n  /// \\brief Return an iterator to the first \\ref ByteInterval.\n  byte_interval_iterator byte_intervals_begin() {\n    return byte_interval_iterator(\n        boost::make_transform_iterator(this->sections_begin(),\n                                       NodeToByteIntervalRange<Section>()),\n        boost::make_transform_iterator(this->sections_end(),\n                                       NodeToByteIntervalRange<Section>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// ByteInterval.\n  byte_interval_iterator byte_intervals_end() {\n    return byte_interval_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref ByteInterval objects.\n  byte_interval_range byte_intervals() {\n    return boost::make_iterator_range(byte_intervals_begin(),\n                                      byte_intervals_end());\n  }\n\n  /// \\brief Return an iterator to the first \\ref ByteInterval.\n  const_byte_interval_iterator byte_intervals_begin() const {\n    return const_byte_interval_iterator(\n        boost::make_transform_iterator(\n            this->sections_begin(), NodeToByteIntervalRange<const Section>()),\n        boost::make_transform_iterator(\n            this->sections_end(), NodeToByteIntervalRange<const Section>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// ByteInterval.\n  const_byte_interval_iterator byte_intervals_end() const {\n    return const_byte_interval_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref ByteInterval objects.\n  const_byte_interval_range byte_intervals() const {\n    return boost::make_iterator_range(byte_intervals_begin(),\n                                      byte_intervals_end());\n  }\n\n  /// \\brief Find all the intervals that contain the address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that intersect the address \\p\n  /// A.\n  byte_interval_subrange findByteIntervalsOn(Addr A) {\n    section_subrange Range = findSectionsOn(A);\n    return byte_interval_subrange(\n        byte_interval_subrange::iterator(\n            boost::make_transform_iterator(Range.begin(),\n                                           FindByteIntervalsIn<Section>(A)),\n            boost::make_transform_iterator(Range.end(),\n                                           FindByteIntervalsIn<Section>(A))),\n        byte_interval_subrange::iterator());\n  }\n\n  /// \\brief Find all the intervals that contain the address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that intersect the address \\p\n  /// A.\n  const_byte_interval_subrange findByteIntervalsOn(Addr A) const {\n    const_section_subrange Range = findSectionsOn(A);\n    return const_byte_interval_subrange(\n        const_byte_interval_subrange::iterator(\n            boost::make_transform_iterator(\n                Range.begin(), FindByteIntervalsIn<const Section>(A)),\n            boost::make_transform_iterator(\n                Range.end(), FindByteIntervalsIn<const Section>(A))),\n        const_byte_interval_subrange::iterator());\n  }\n\n  /// \\brief Find all the intervals that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that are at the address \\p A.\n  byte_interval_range findByteIntervalsAt(Addr A) {\n    section_subrange Range = findSectionsOn(A);\n    return byte_interval_range(\n        byte_interval_range::iterator(\n            boost::make_transform_iterator(Range.begin(),\n                                           FindByteIntervalsAt<Section>(A)),\n            boost::make_transform_iterator(Range.end(),\n                                           FindByteIntervalsAt<Section>(A))),\n        byte_interval_range::iterator());\n  }\n\n  /// \\brief Find all the intervals that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that are between the\n  /// addresses.\n  byte_interval_range findByteIntervalsAt(Addr Low, Addr High) {\n    std::vector<Section::byte_interval_range> Ranges;\n    for (Section& S : findSectionsOn(Low))\n      Ranges.push_back(S.findByteIntervalsAt(Low, High));\n    for (Section& S : findSectionsAt(Low + 1, High))\n      Ranges.push_back(S.findByteIntervalsAt(Low, High));\n    return byte_interval_range(byte_interval_iterator(Ranges),\n                               byte_interval_iterator());\n  }\n\n  /// \\brief Find all the intervals that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that are at the address \\p A.\n  const_byte_interval_range findByteIntervalsAt(Addr A) const {\n    const_section_subrange Range = findSectionsOn(A);\n    return const_byte_interval_range(\n        const_byte_interval_range::iterator(\n            boost::make_transform_iterator(\n                Range.begin(), FindByteIntervalsAt<const Section>(A)),\n            boost::make_transform_iterator(\n                Range.end(), FindByteIntervalsAt<const Section>(A))),\n        const_byte_interval_range::iterator());\n  }\n\n  /// \\brief Find all the intervals that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that are between the\n  /// addresses.\n  const_byte_interval_range findByteIntervalsAt(Addr Low, Addr High) const {\n    std::vector<Section::const_byte_interval_range> Ranges;\n    for (const Section& S : findSectionsOn(Low))\n      Ranges.push_back(S.findByteIntervalsAt(Low, High));\n    for (const Section& S : findSectionsAt(Low + 1, High))\n      Ranges.push_back(S.findByteIntervalsAt(Low, High));\n    return const_byte_interval_range(const_byte_interval_iterator(Ranges),\n                                     const_byte_interval_iterator());\n  }\n  /// @}\n  // (end group of ByteInterval-related types and functions)\n\n  /// \\name Block-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over blocks.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using block_iterator =\n      MergeSortedIterator<Section::block_iterator, BlockAddressLess>;\n  /// \\brief Range of blocks.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using block_range = boost::iterator_range<block_iterator>;\n  /// \\brief Sub-range of blocks overlapping an address or range of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using block_subrange = boost::iterator_range<\n      MergeSortedIterator<Section::block_subrange::iterator, BlockAddressLess>>;\n  /// \\brief Iterator over blocks.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_block_iterator =\n      MergeSortedIterator<Section::const_block_iterator, BlockAddressLess>;\n  /// \\brief Range of blocks.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_block_range = boost::iterator_range<const_block_iterator>;\n  /// \\brief Sub-range of blocks overlapping an address or range of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending.\n  using const_block_subrange = boost::iterator_range<MergeSortedIterator<\n      Section::const_block_subrange::iterator, BlockAddressLess>>;\n\n  /// \\brief Return an iterator to the first block.\n  block_iterator blocks_begin() {\n    return block_iterator(\n        boost::make_transform_iterator(this->sections_begin(),\n                                       NodeToBlockRange<Section>()),\n        boost::make_transform_iterator(this->sections_end(),\n                                       NodeToBlockRange<Section>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last block.\n  block_iterator blocks_end() { return block_iterator(); }\n\n  /// \\brief Return a range of all the blocks.\n  block_range blocks() {\n    return boost::make_iterator_range(blocks_begin(), blocks_end());\n  }\n\n  /// \\brief Return an iterator to the first block.\n  const_block_iterator blocks_begin() const {\n    return const_block_iterator(\n        boost::make_transform_iterator(this->sections_begin(),\n                                       NodeToBlockRange<const Section>()),\n        boost::make_transform_iterator(this->sections_end(),\n                                       NodeToBlockRange<const Section>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last block.\n  const_block_iterator blocks_end() const { return const_block_iterator(); }\n\n  /// \\brief Return a range of all the blocks.\n  const_block_range blocks() const {\n    return boost::make_iterator_range(blocks_begin(), blocks_end());\n  }\n\n  /// \\brief Find all the blocks that have bytes that lie within the address\n  /// specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that intersect the address \\p A.\n  block_subrange findBlocksOn(Addr A) {\n    section_subrange SectionRange = findSectionsOn(A);\n    return block_subrange(\n        block_subrange::iterator(\n            boost::make_transform_iterator(SectionRange.begin(),\n                                           FindBlocksIn<Section>(A)),\n            boost::make_transform_iterator(SectionRange.end(),\n                                           FindBlocksIn<Section>(A))),\n        block_subrange::iterator());\n  }\n\n  /// \\brief Find all the blocks that have bytes that lie within the address\n  /// specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that intersect the address \\p A.\n  const_block_subrange findBlocksOn(Addr A) const {\n    const_section_subrange SectionRange = findSectionsOn(A);\n    return const_block_subrange(\n        const_block_subrange::iterator(\n            boost::make_transform_iterator(SectionRange.begin(),\n                                           FindBlocksIn<const Section>(A)),\n            boost::make_transform_iterator(SectionRange.end(),\n                                           FindBlocksIn<const Section>(A))),\n        const_block_subrange::iterator());\n  }\n\n  /// \\brief Find all the blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are at the address \\p A.\n  block_range findBlocksAt(Addr A) {\n    section_subrange SectionRange = findSectionsOn(A);\n    return block_range(block_range::iterator(\n                           boost::make_transform_iterator(\n                               SectionRange.begin(), FindBlocksAt<Section>(A)),\n                           boost::make_transform_iterator(\n                               SectionRange.end(), FindBlocksAt<Section>(A))),\n                       block_range::iterator());\n  }\n\n  /// \\brief Find all the blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are between the addresses.\n  block_range findBlocksAt(Addr Low, Addr High) {\n    std::vector<Section::block_range> Ranges;\n    for (Section& S : findSectionsOn(Low))\n      Ranges.push_back(S.findBlocksAt(Low, High));\n    for (Section& S : findSectionsAt(Low + 1, High))\n      Ranges.push_back(S.findBlocksAt(Low, High));\n    return block_range(block_iterator(Ranges), block_iterator());\n  }\n\n  /// \\brief Find all the blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are at the address \\p A.\n  const_block_range findBlocksAt(Addr A) const {\n    const_section_subrange SectionRange = findSectionsOn(A);\n    return const_block_range(\n        const_block_range::iterator(\n            boost::make_transform_iterator(SectionRange.begin(),\n                                           FindBlocksAt<const Section>(A)),\n            boost::make_transform_iterator(SectionRange.end(),\n                                           FindBlocksAt<const Section>(A))),\n        const_block_range::iterator());\n  }\n\n  /// \\brief Find all the blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are between the addresses.\n  const_block_range findBlocksAt(Addr Low, Addr High) const {\n    std::vector<Section::const_block_range> Ranges;\n    for (const Section& S : findSectionsOn(Low))\n      Ranges.push_back(S.findBlocksAt(Low, High));\n    for (const Section& S : findSectionsAt(Low + 1, High))\n      Ranges.push_back(S.findBlocksAt(Low, High));\n    return const_block_range(const_block_iterator(Ranges),\n                             const_block_iterator());\n  }\n  /// @}\n  // (end group of Block-related types and functions)\n\n  /// \\name CodeBlock-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using code_block_iterator =\n      MergeSortedIterator<Section::code_block_iterator, AddressLess>;\n  /// \\brief Range of \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using code_block_range = boost::iterator_range<code_block_iterator>;\n  /// \\brief Sub-range of \\ref CodeBlock objects overlapping an address or range\n  /// of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using code_block_subrange = boost::iterator_range<\n      MergeSortedIterator<Section::code_block_subrange::iterator, AddressLess>>;\n  /// \\brief Iterator over \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_code_block_iterator =\n      MergeSortedIterator<Section::const_code_block_iterator, AddressLess>;\n  /// \\brief Range of \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_code_block_range =\n      boost::iterator_range<const_code_block_iterator>;\n  /// \\brief Sub-range of \\ref CodeBlock objects overlapping an address or range\n  /// of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_code_block_subrange = boost::iterator_range<MergeSortedIterator<\n      Section::const_code_block_subrange::iterator, AddressLess>>;\n\nprivate:\n  code_block_range makeCodeBlockRange(SectionSet::iterator Begin,\n                                      SectionSet::iterator End) {\n    NodeToCodeBlockRange<Section> Transformer;\n    return boost::make_iterator_range(\n        code_block_iterator(\n            boost::make_transform_iterator(section_iterator(Begin),\n                                           Transformer),\n            boost::make_transform_iterator(section_iterator(End), Transformer)),\n        code_block_iterator());\n  }\n\npublic:\n  /// \\brief Return an iterator to the first \\ref CodeBlock.\n  code_block_iterator code_blocks_begin() {\n    return code_block_iterator(\n        boost::make_transform_iterator(this->sections_begin(),\n                                       NodeToCodeBlockRange<Section>()),\n        boost::make_transform_iterator(this->sections_end(),\n                                       NodeToCodeBlockRange<Section>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// CodeBlock.\n  code_block_iterator code_blocks_end() { return code_block_iterator(); }\n\n  /// \\brief Return a range of all the \\ref CodeBlock objects.\n  code_block_range code_blocks() {\n    return boost::make_iterator_range(code_blocks_begin(), code_blocks_end());\n  }\n\n  /// \\brief Return an iterator to the first \\ref CodeBlock.\n  const_code_block_iterator code_blocks_begin() const {\n    return const_code_block_iterator(\n        boost::make_transform_iterator(this->sections_begin(),\n                                       NodeToCodeBlockRange<const Section>()),\n        boost::make_transform_iterator(this->sections_end(),\n                                       NodeToCodeBlockRange<const Section>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// CodeBlock.\n  const_code_block_iterator code_blocks_end() const {\n    return const_code_block_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref CodeBlock objects.\n  const_code_block_range code_blocks() const {\n    return boost::make_iterator_range(code_blocks_begin(), code_blocks_end());\n  }\n\n  /// \\brief Find all the code blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeNode object that intersect the address \\p A.\n  code_block_subrange findCodeBlocksOn(Addr A) {\n    section_subrange Range = findSectionsOn(A);\n    return code_block_subrange(\n        code_block_subrange::iterator(\n            boost::make_transform_iterator(Range.begin(),\n                                           FindCodeBlocksIn<Section>(A)),\n            boost::make_transform_iterator(Range.end(),\n                                           FindCodeBlocksIn<Section>(A))),\n        code_block_subrange::iterator());\n  }\n\n  /// \\brief Find all the code blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that intersect the address \\p A.\n  const_code_block_subrange findCodeBlocksOn(Addr A) const {\n    const_section_subrange Range = findSectionsOn(A);\n    return const_code_block_subrange(\n        const_code_block_subrange::iterator(\n            boost::make_transform_iterator(Range.begin(),\n                                           FindCodeBlocksIn<const Section>(A)),\n            boost::make_transform_iterator(Range.end(),\n                                           FindCodeBlocksIn<const Section>(A))),\n        const_code_block_subrange::iterator());\n  }\n\n  /// \\brief Find all the code blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are at the address \\p A.\n  code_block_range findCodeBlocksAt(Addr A) {\n    section_subrange Range = findSectionsOn(A);\n    return code_block_range(\n        code_block_range::iterator(\n            boost::make_transform_iterator(Range.begin(),\n                                           FindCodeBlocksAt<Section>(A)),\n            boost::make_transform_iterator(Range.end(),\n                                           FindCodeBlocksAt<Section>(A))),\n        code_block_range::iterator());\n  }\n\n  /// \\brief Find all the code blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are between the addresses.\n  code_block_range findCodeBlocksAt(Addr Low, Addr High) {\n    std::vector<Section::code_block_range> Ranges;\n    for (Section& S : findSectionsOn(Low))\n      Ranges.push_back(S.findCodeBlocksAt(Low, High));\n    for (Section& S : findSectionsAt(Low + 1, High))\n      Ranges.push_back(S.findCodeBlocksAt(Low, High));\n    return code_block_range(code_block_iterator(Ranges), code_block_iterator());\n  }\n\n  /// \\brief Find all the code blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are at the address \\p A.\n  const_code_block_range findCodeBlocksAt(Addr A) const {\n    const_section_subrange Range = findSectionsOn(A);\n    return const_code_block_range(\n        const_code_block_range::iterator(\n            boost::make_transform_iterator(Range.begin(),\n                                           FindCodeBlocksAt<const Section>(A)),\n            boost::make_transform_iterator(Range.end(),\n                                           FindCodeBlocksAt<const Section>(A))),\n        const_code_block_range::iterator());\n  }\n\n  /// \\brief Find all the code blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are between the addresses.\n  const_code_block_range findCodeBlocksAt(Addr Low, Addr High) const {\n    std::vector<Section::const_code_block_range> Ranges;\n    for (const Section& S : findSectionsOn(Low))\n      Ranges.push_back(S.findCodeBlocksAt(Low, High));\n    for (const Section& S : findSectionsAt(Low + 1, High))\n      Ranges.push_back(S.findCodeBlocksAt(Low, High));\n    return const_code_block_range(const_code_block_iterator(Ranges),\n                                  const_code_block_iterator());\n  }\n  /// @}\n  // (end group of CodeBlock-related types and functions)\n\n  /// \\name DataBlock-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using data_block_iterator =\n      MergeSortedIterator<Section::data_block_iterator, AddressLess>;\n  /// \\brief Range of \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using data_block_range = boost::iterator_range<data_block_iterator>;\n  /// \\brief Sub-range of \\ref DataBlock objects overlapping an address or range\n  /// of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using data_block_subrange = boost::iterator_range<\n      MergeSortedIterator<Section::data_block_subrange::iterator, AddressLess>>;\n  /// \\brief Iterator over \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_data_block_iterator =\n      MergeSortedIterator<Section::const_data_block_iterator, AddressLess>;\n  /// \\brief Range of \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_data_block_range =\n      boost::iterator_range<const_data_block_iterator>;\n  /// \\brief Sub-range of \\ref DataBlock objects overlapping an address or range\n  /// of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_data_block_subrange = boost::iterator_range<MergeSortedIterator<\n      Section::const_data_block_subrange::iterator, AddressLess>>;\n\n  /// \\brief Return an iterator to the first \\ref DataBlock.\n  data_block_iterator data_blocks_begin() {\n    return data_block_iterator(\n        boost::make_transform_iterator(this->sections_begin(),\n                                       NodeToDataBlockRange<Section>()),\n        boost::make_transform_iterator(this->sections_end(),\n                                       NodeToDataBlockRange<Section>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// DataBlock.\n  data_block_iterator data_blocks_end() { return data_block_iterator(); }\n\n  /// \\brief Return a range of all the \\ref DataBlock objects.\n  data_block_range data_blocks() {\n    return boost::make_iterator_range(data_blocks_begin(), data_blocks_end());\n  }\n\n  /// \\brief Return an iterator to the first \\ref DataBlock.\n  const_data_block_iterator data_blocks_begin() const {\n    return const_data_block_iterator(\n        boost::make_transform_iterator(this->sections_begin(),\n                                       NodeToDataBlockRange<const Section>()),\n        boost::make_transform_iterator(this->sections_end(),\n                                       NodeToDataBlockRange<const Section>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// DataBlock.\n  const_data_block_iterator data_blocks_end() const {\n    return const_data_block_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref DataBlock objects.\n  const_data_block_range data_blocks() const {\n    return boost::make_iterator_range(data_blocks_begin(), data_blocks_end());\n  }\n\n  /// \\brief Find all the data blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataNode object that intersect the address \\p A.\n  data_block_subrange findDataBlocksOn(Addr A) {\n    section_subrange Range = findSectionsOn(A);\n    return data_block_subrange(\n        data_block_subrange::iterator(\n            boost::make_transform_iterator(Range.begin(),\n                                           FindDataBlocksIn<Section>(A)),\n            boost::make_transform_iterator(Range.end(),\n                                           FindDataBlocksIn<Section>(A))),\n        data_block_subrange::iterator());\n  }\n\n  /// \\brief Find all the data blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataNode object that intersect the address \\p A.\n  const_data_block_subrange findDataBlocksOn(Addr A) const {\n    const_section_subrange Range = findSectionsOn(A);\n    return const_data_block_subrange(\n        const_data_block_subrange::iterator(\n            boost::make_transform_iterator(Range.begin(),\n                                           FindDataBlocksIn<const Section>(A)),\n            boost::make_transform_iterator(Range.end(),\n                                           FindDataBlocksIn<const Section>(A))),\n        const_data_block_subrange::iterator());\n  }\n\n  /// \\brief Find all the data blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are at the address \\p A.\n  data_block_range findDataBlocksAt(Addr A) {\n    section_subrange Range = findSectionsOn(A);\n    return data_block_range(\n        data_block_range::iterator(\n            boost::make_transform_iterator(Range.begin(),\n                                           FindDataBlocksAt<Section>(A)),\n            boost::make_transform_iterator(Range.end(),\n                                           FindDataBlocksAt<Section>(A))),\n        data_block_range::iterator());\n  }\n\n  /// \\brief Find all the data blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are between the addresses.\n  data_block_range findDataBlocksAt(Addr Low, Addr High) {\n    std::vector<Section::data_block_range> Ranges;\n    for (Section& S : findSectionsOn(Low))\n      Ranges.push_back(S.findDataBlocksAt(Low, High));\n    for (Section& S : findSectionsAt(Low + 1, High))\n      Ranges.push_back(S.findDataBlocksAt(Low, High));\n    return data_block_range(data_block_iterator(Ranges), data_block_iterator());\n  }\n\n  /// \\brief Find all the data blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are at the address \\p A.\n  const_data_block_range findDataBlocksAt(Addr A) const {\n    const_section_subrange Range = findSectionsOn(A);\n    return const_data_block_range(\n        const_data_block_range::iterator(\n            boost::make_transform_iterator(Range.begin(),\n                                           FindDataBlocksAt<const Section>(A)),\n            boost::make_transform_iterator(Range.end(),\n                                           FindDataBlocksAt<const Section>(A))),\n        const_data_block_range::iterator());\n  }\n\n  /// \\brief Find all the data blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are between the addresses.\n  const_data_block_range findDataBlocksAt(Addr Low, Addr High) const {\n    std::vector<Section::const_data_block_range> Ranges;\n    for (const Section& S : findSectionsOn(Low))\n      Ranges.push_back(S.findDataBlocksAt(Low, High));\n    for (const Section& S : findSectionsAt(Low + 1, High))\n      Ranges.push_back(S.findDataBlocksAt(Low, High));\n    return const_data_block_range(const_data_block_iterator(Ranges),\n                                  const_data_block_iterator());\n  }\n  /// @}\n  // (end group of DataBlock-related types and functions)\n\n  /// \\name SymbolicExpression-Related Public Types and Functions\n  /// @{\n\n  /// \\brief Iterator over \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in address order, ascending.\n  using symbolic_expression_iterator =\n      MergeSortedIterator<Section::symbolic_expression_iterator,\n                          ByteInterval::SymbolicExpressionElement::AddressLess>;\n  /// \\brief Range of \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in address order, ascending.\n  using symbolic_expression_range =\n      boost::iterator_range<symbolic_expression_iterator>;\n  /// \\brief Iterator over \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in address order, ascending.\n  using const_symbolic_expression_iterator = MergeSortedIterator<\n      Section::const_symbolic_expression_iterator,\n      ByteInterval::ConstSymbolicExpressionElement::AddressLess>;\n  /// \\brief Range of \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in address order, ascending.\n  using const_symbolic_expression_range =\n      boost::iterator_range<const_symbolic_expression_iterator>;\n\n  /// \\brief Return an iterator to the first \\ref SymbolicExpression.\n  symbolic_expression_iterator symbolic_expressions_begin() {\n    return symbolic_expression_iterator(\n        boost::make_transform_iterator(\n            this->sections_begin(), NodeToSymbolicExpressionRange<Section>()),\n        boost::make_transform_iterator(\n            this->sections_end(), NodeToSymbolicExpressionRange<Section>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// SymbolicExpression.\n  symbolic_expression_iterator symbolic_expressions_end() {\n    return symbolic_expression_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref SymbolicExpression objects.\n  symbolic_expression_range symbolic_expressions() {\n    return boost::make_iterator_range(symbolic_expressions_begin(),\n                                      symbolic_expressions_end());\n  }\n\n  /// \\brief Return an iterator to the first \\ref SymbolicExpression.\n  const_symbolic_expression_iterator symbolic_expressions_begin() const {\n    return const_symbolic_expression_iterator(\n        boost::make_transform_iterator(\n            this->sections_begin(),\n            NodeToSymbolicExpressionRange<const Section>()),\n        boost::make_transform_iterator(\n            this->sections_end(),\n            NodeToSymbolicExpressionRange<const Section>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// SymbolicExpression.\n  const_symbolic_expression_iterator symbolic_expressions_end() const {\n    return const_symbolic_expression_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref SymbolicExpression objects.\n  const_symbolic_expression_range symbolic_expressions() const {\n    return boost::make_iterator_range(symbolic_expressions_begin(),\n                                      symbolic_expressions_end());\n  }\n\n  /// \\brief Find all the symbolic expressions that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are at the address\n  /// \\p A.\n  symbolic_expression_range findSymbolicExpressionsAt(Addr A) {\n    return symbolic_expression_range(\n        symbolic_expression_range::iterator(\n            boost::make_transform_iterator(this->sections_begin(),\n                                           FindSymExprsAt<Section>(A)),\n            boost::make_transform_iterator(this->sections_end(),\n                                           FindSymExprsAt<Section>(A))),\n        symbolic_expression_range::iterator());\n  }\n\n  /// \\brief Find all the symbolic expressions that start between a range of\n  /// addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are between the\n  /// addresses.\n  symbolic_expression_range findSymbolicExpressionsAt(Addr Low, Addr High) {\n    return symbolic_expression_range(\n        symbolic_expression_range::iterator(\n            boost::make_transform_iterator(\n                this->sections_begin(),\n                FindSymExprsBetween<Section>(Low, High)),\n            boost::make_transform_iterator(\n                this->sections_end(), FindSymExprsBetween<Section>(Low, High))),\n        symbolic_expression_range::iterator());\n  }\n\n  /// \\brief Find all the symbolic expressions that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are at the address\n  /// \\p A.\n  const_symbolic_expression_range findSymbolicExpressionsAt(Addr A) const {\n    return const_symbolic_expression_range(\n        const_symbolic_expression_range::iterator(\n            boost::make_transform_iterator(this->sections_begin(),\n                                           FindSymExprsAt<const Section>(A)),\n            boost::make_transform_iterator(this->sections_end(),\n                                           FindSymExprsAt<const Section>(A))),\n        const_symbolic_expression_range::iterator());\n  }\n\n  /// \\brief Find all the symbolic expressions that start between a range of\n  /// addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are between the\n  /// addresses.\n  const_symbolic_expression_range findSymbolicExpressionsAt(Addr Low,\n                                                            Addr High) const {\n    return const_symbolic_expression_range(\n        const_symbolic_expression_range::iterator(\n            boost::make_transform_iterator(\n                this->sections_begin(),\n                FindSymExprsBetween<const Section>(Low, High)),\n            boost::make_transform_iterator(\n                this->sections_end(),\n                FindSymExprsBetween<const Section>(Low, High))),\n        const_symbolic_expression_range::iterator());\n  }\n  /// @}\n  // (end group of SymbolicExpression-related types and functions)\n\n  /// @cond INTERNAL\n  static bool classof(const Node* N) { return N->getKind() == Kind::Module; }\n  /// @endcond\n\nprivate:\n  /// \\brief The protobuf message type used for serializing Module.\n  using MessageType = proto::Module;\n\n  /// \\brief Remove a Section from SectionAddrs.\n  void removeSectionAddrs(Section* S);\n\n  /// \\brief Add a Section to SectionAddrs.\n  ///\n  /// The caller is responsible for ensuring that the Section is owned by this\n  /// Module.\n  void insertSectionAddrs(Section* S);\n\n  /// \\brief Serialize into a protobuf message.\n  ///\n  /// \\param[out] Message   Serialize into this message.\n  ///\n  /// \\return void\n  void toProtobuf(MessageType* Message) const;\n\n  /// \\brief Construct a Module from a protobuf message.\n  ///\n  /// \\param C   The Context in which the deserialized Module will be held.\n  /// \\param Message  The protobuf message from which to deserialize.\n  ///\n  /// \\return The deserialized Module object, or null on failure.\n  static ErrorOr<Module*> fromProtobuf(Context& C, const MessageType& Message);\n\n  // Present for testing purposes only.\n  void save(std::ostream& Out) const;\n\n  // Present for testing purposes only.\n  static Module* load(Context& C, std::istream& In);\n\n  void setParent(IR* I, ModuleObserver* O) {\n    Parent = I;\n    Observer = O;\n  }\n\n  IR* Parent{nullptr};\n  ModuleObserver* Observer{nullptr};\n  std::string BinaryPath;\n  Addr PreferredAddr;\n  int64_t RebaseDelta{0};\n  gtirb::FileFormat FileFormat{FileFormat::Undefined};\n  gtirb::ISA Isa{ISA::Undefined};\n  gtirb::ByteOrder ByteOrder{ByteOrder::Undefined};\n  std::string Name;\n  CodeBlock* EntryPoint{nullptr};\n  ProxyBlockSet ProxyBlocks;\n  SectionSet Sections;\n  SectionIntMap SectionAddrs;\n  SymbolSet Symbols;\n\n  std::unique_ptr<SectionObserver> SecObs;\n  std::unique_ptr<SymbolObserver> SymObs;\n\n  friend class Context; // Allow Context to construct new Modules.\n  friend class IR;      // Allow IRs to call setIR, Create, etc.\n  // Allow serialization from IR via containerToProtobuf.\n  template <typename T> friend typename T::MessageType toProtobuf(const T&);\n  friend class SerializationTestHarness; // Testing support.\n};\n\n/// \\class ModuleObserver\n///\n/// \\brief Interface for notifying observers when the Module is updated.\n///\n\nclass GTIRB_EXPORT_API ModuleObserver {\npublic:\n  virtual ~ModuleObserver() = default;\n\n  /// \\brief Notify the parent when this Module's name changes.\n  ///\n  /// Called after the Module updates its internal state.\n  ///\n  /// \\param M        the Module whose name changed.\n  /// \\param OldName  the Module's previous name.\n  /// \\param NewName  the new name of this Module.\n  virtual ChangeStatus nameChange(Module* M, const std::string& OldName,\n                                  const std::string& NewName) = 0;\n\n  /// \\brief Notify the parent when new ProxyBlocks are added to the Module.\n  ///\n  /// Called after the Module updates its internal state.\n  ///\n  /// \\param M       the Module to which the ProxyBlocks were added.\n  /// \\param Blocks  a range containing the new ProxyBlocks.\n  virtual ChangeStatus addProxyBlocks(Module* M,\n                                      Module::proxy_block_range Blocks) = 0;\n\n  /// \\brief Notify the parent when ProxyBlocks are removed from the Module.\n  ///\n  /// Called before the Module updates its internal state.\n  ///\n  /// \\param M       the Module from which ProxyBlocks will be removed.\n  /// \\param Blocks  a range containing ProxyBlocks to remove.\n  virtual ChangeStatus removeProxyBlocks(Module* M,\n                                         Module::proxy_block_range Blocks) = 0;\n\n  /// \\brief Notify the parent when CodeBlocks are added to the Module.\n  ///\n  /// Called after the Module updates its internal state.\n  ///\n  /// \\param M       the Module to which CodeBlocks were added.\n  /// \\param Blocks  a range containing the new CodeBlocks.\n  virtual ChangeStatus addCodeBlocks(Module* M,\n                                     Module::code_block_range Blocks) = 0;\n\n  /// \\brief Notify the parent when CodeBlocks are removed from the Module.\n  ///\n  /// Called before the Module updates its internal state.\n  ///\n  /// \\param M       the Module from which CodeBlocks will be removed.\n  /// \\param Blocks  a range containing the CodeBlocks to remove.\n  virtual ChangeStatus removeCodeBlocks(Module* M,\n                                        Module::code_block_range Blocks) = 0;\n};\n\ninline void Module::setName(const std::string& X) {\n  if (Observer) {\n    std::string OldName = X;\n    std::swap(Name, OldName);\n    [[maybe_unused]] ChangeStatus status =\n        Observer->nameChange(this, OldName, Name);\n    // The known observers do not reject insertions. If that changes, this\n    // method must be updated.\n    assert(status != ChangeStatus::Rejected &&\n           \"recovering from rejected name change is unimplemented\");\n  } else {\n    Name = X;\n  }\n}\n} // namespace gtirb\n\n#endif // GTIRB_MODULE_H\n"
  },
  {
    "path": "include/gtirb/Node.hpp",
    "content": "//===- Node.hpp -------------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_NODE_H\n#define GTIRB_NODE_H\n\n#include <gtirb/Casting.hpp>\n#include <gtirb/Context.hpp>\n#include <gtirb/Export.hpp>\n#include <functional>\n#include <string>\n\n/// \\file Node.hpp\n/// \\brief Class gtirb::Node.\n\nnamespace gtirb {\nclass Node;\n\n/// \\class Node\n///\n/// \\brief Represents the base of the Node class hierarchy.\n///\n/// Objects of Node types can be converted into more specific types by\n/// using the \\ref casting \"casting machinery\" from Casting.hpp. You\n/// can use static_cast<>() and reinterpret_cast<>(), but cast<>() and\n/// dyn_cast<>() are safer alternatives. You cannot use dynamic_cast<>\n/// to cast Node objects.\nclass GTIRB_EXPORT_API Node {\npublic:\n  /// \\cond internal\n\n  // The enum constants below must be grouped according to the inheritance\n  // hierarchy such that all descendants of a type X must appear between the\n  // constant for X and LAST_X. This allows us to quickly check whether a type\n  // is a descendant of X by checking if the enum constant falls in that range.\n  enum class Kind {\n    Node,\n    CfgNode,\n    CodeBlock,\n    ProxyBlock,\n    LAST_CfgNode = ProxyBlock, // Mark last descendant of CfgNode\n    DataBlock,\n    IR,\n    Module,\n    Section,\n    Symbol,\n    ByteInterval,\n    LAST_Node = ByteInterval, // Mark last descendant of Node\n  };\n  /// \\endcond\n\n  /// \\brief Retrieve a node by its UUID.\n  ///\n  /// \\return The Node with the given UUID, or nullptr if none exists.\n  static Node* getByUUID(Context& C, const UUID& Uuid) {\n    return C.findNode(Uuid);\n  }\n\n  /// \\brief Retrieve a node by its UUID.\n  ///\n  /// \\return The Node with the given UUID, or nullptr if none exists.\n  static const Node* getByUUID(const Context& C, const UUID& Uuid) {\n    return C.findNode(Uuid);\n  }\n\n  /// \\brief Create a Node object in its default state.\n  ///\n  /// \\param C  The Context in which this object will be held.\n  ///\n  /// \\return The newly created object.\n  static Node* Create(Context& C) { return C.Create<Node>(C, Kind::Node); }\n\n  /// \\brief Copying Nodes is explicitly disabled.\n  Node(const Node&) = delete;\n\n  /// \\brief Move-constructing Nodes is explicitly disabled.\n  Node(Node&&) = delete;\n\n  /// \\brief Cleans up resources no longer needed by the Node object.\n  ~Node() noexcept;\n\n  /// \\brief Copying Nodes is explicilty disabled.\n  Node& operator=(const Node&) = delete;\n\n  /// \\brief Move-assigning Nodes is explicilty disabled.\n  Node& operator=(Node&&) = delete;\n\n  /// \\brief Get the Universally Unique ID (UUID) for \\c this.\n  ///\n  /// \\return The UUID.\n  const UUID& getUUID() const { return Uuid; }\n\n  /// \\cond INTERNAL\n  Kind getKind() const { return K; }\n  /// \\endcond\n\n  /// \\cond INTERNAL\n  static bool classof(const Node* N) { return classofKind(N->getKind()); }\n  static bool classofKind(Kind K) {\n    return K >= Kind::Node && K <= Kind::LAST_Node;\n  }\n  /// \\endcond\n\nprotected:\n  /// \\cond INTERNAL\n  Node(Context& C, Kind Knd);\n  Node(Context& C, Kind Knd, const UUID& U);\n  /// \\endcond\n\nprivate:\n  Kind K;\n  UUID Uuid;\n  // The Context object can never be null as it can only be passed to the Node\n  // constructor by reference. However, we don't want to store a reference to\n  // the Context object because we want to keep the Node class copyable and\n  // Context needs to own a move-only allocator.\n  Context* Ctx;\n\n  friend class Context; // Enables Context::Create\n};\n\n} // namespace gtirb\n\n#endif // GTIRB_NODE_H\n"
  },
  {
    "path": "include/gtirb/Observer.hpp",
    "content": "//===- Observer.hpp ---------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_OBSERVER_H\n#define GTIRB_OBSERVER_H\n\nnamespace gtirb {\nenum class ChangeStatus {\n  Rejected, //< The requested change cannot be completed and must be rolled\n            //< back.\n  Accepted, //< The requested change was implemented successfully.\n  NoChange  //< The requested change would not alter the data structure.\n};\n}\n\n#endif // GTIRB_OBSERVER_H\n"
  },
  {
    "path": "include/gtirb/Offset.hpp",
    "content": "//===- Offset.hpp ------------------------------------------------*- C++-*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_OFFSET_H\n#define GTIRB_OFFSET_H\n\n#include <gtirb/Context.hpp>\n#include <gtirb/Export.hpp>\n#include <boost/functional/hash.hpp>\n#include <cstdint>\n#include <functional>\n\nnamespace gtirb {\nnamespace proto {\nclass Offset;\n}\n\n/// \\class Offset\n///\n/// \\brief Describes a location inside a node (byte interval, block, etc).\nstruct GTIRB_EXPORT_API Offset {\n  /// \\brief The UUID of the node.\n  UUID ElementId;\n\n  /// \\brief The displacement from the start of the node, in bytes.\n  uint64_t Displacement{0};\n\n  /// \\brief Constructor using a ElemId uuid and a Displacement.\n  Offset(const UUID& ElemId, uint64_t Disp)\n      : ElementId(ElemId), Displacement(Disp) {}\n\n  /// \\brief Default constructor.\n  Offset() = default;\n\n  /// \\brief Equality operator for \\ref Offset.\n  // Note: boost::uuid is not constexpr.\n  friend bool operator==(const Offset& LHS, const Offset& RHS) noexcept {\n    return LHS.ElementId == RHS.ElementId &&\n           LHS.Displacement == RHS.Displacement;\n  }\n\n  /// \\brief Inequality operator for \\ref Offset.\n  friend bool operator!=(const Offset& LHS, const Offset& RHS) noexcept {\n    return !operator==(LHS, RHS);\n  }\n\n  /// \\brief Less-than operator for \\ref Offset.\n  friend constexpr bool operator<(const Offset& LHS,\n                                  const Offset& RHS) noexcept {\n    return std::tie(LHS.ElementId, LHS.Displacement) <\n           std::tie(RHS.ElementId, RHS.Displacement);\n  }\n\n  /// \\brief Greater-than operator for \\ref Offset.\n  friend constexpr bool operator>(const Offset& LHS,\n                                  const Offset& RHS) noexcept {\n    return operator<(RHS, LHS);\n  }\n\n  /// \\brief Less-than-or-equal operator for \\ref Offset.\n  friend constexpr bool operator<=(const Offset& LHS,\n                                   const Offset& RHS) noexcept {\n    return !operator<(RHS, LHS);\n  }\n\n  /// \\brief Greater-than-or-equal operator for \\ref Offset.\n  friend constexpr bool operator>=(const Offset& LHS,\n                                   const Offset& RHS) noexcept {\n    return !operator<(LHS, RHS);\n  }\n\nprivate:\n  /// @cond INTERNAL\n  /// \\brief The protobuf message type used for serializing Offset.\n  using MessageType = proto::Offset;\n\n  /// \\brief Serialize into a protobuf message.\n  ///\n  /// \\param[out] Message   Serialize into this message.\n  ///\n  /// \\return void\n  void toProtobuf(MessageType* Message) const;\n\n  /// \\brief Construct a Offset from a protobuf message.\n  ///\n  /// \\param C  The Context in which the deserialized Offset will be\n  ///           held.\n  /// \\param Message  The protobuf message from which to deserialize.\n  ///\n  /// \\return true if the \\ref Offset could be deserialized, false otherwise.\n  bool fromProtobuf(Context& C, const MessageType& Message);\n  /// @endcond\n\n  // Enables serialization.\n  friend bool fromProtobuf(Context&, Offset&, const MessageType&);\n};\n\n} // namespace gtirb\n\nnamespace std {\n\n/// \\brief Hash operation for \\ref Offset.\ntemplate <> struct hash<gtirb::Offset> {\n  size_t operator()(const gtirb::Offset& X) const {\n    std::size_t Seed = 0;\n    boost::hash_combine(Seed, X.ElementId);\n    boost::hash_combine(Seed, X.Displacement);\n    return Seed;\n  }\n};\n\n} // namespace std\n\n#endif // GTIRB_OFFSET_H\n"
  },
  {
    "path": "include/gtirb/ProxyBlock.hpp",
    "content": "//===- ProxyBlock.hpp -------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_PROX_BLOCK_H\n#define GTIRB_PROX_BLOCK_H\n\n#include <gtirb/CfgNode.hpp>\n#include <gtirb/Node.hpp>\n\n/// \\file ProxyBlock.hpp\n/// \\ingroup CFG_GROUP\n/// \\brief Class gtirb::ProxyBlock.\n/// \\see CFG_GROUP\n\nnamespace gtirb {\nnamespace proto {\nclass ProxyBlock;\n}\n\ntemplate <class T> class ErrorOr;\nclass Module;\n\n/// \\class ProxyBlock\n///\n/// \\brief A placeholder that serves as the endpoint (source or target)\n/// of a CFG edge.\n///\n/// ProxyBlock objects allow the construction of CFG edges to or from\n/// another node. For example, a call to a function in another module\n/// may be represented by an edge that originates at the calling\n/// CodeBlock and targets a ProxyBlock. Another example would be an\n/// edge that represents an indirect jump whose target is not known.\n///\n/// A ProxyBlock does not represent any instructions and so has neither\n/// an address nor a size.\n///\n/// \\see \\ref CFG_GROUP\nclass GTIRB_EXPORT_API ProxyBlock : public CfgNode {\npublic:\n  /// \\brief Create an unitialized ProxyBlock object.\n  /// \\param C        The Context in which this ProxyBlock will be held.\n  /// \\return         The newly created ProxyBlock.\n  static ProxyBlock* Create(Context& C) { return C.Create<ProxyBlock>(C); }\n\n  /// \\brief Get the \\ref Module this block belongs to.\n  Module* getModule() { return Parent; }\n  /// \\brief Get the \\ref Module this block belongs to.\n  const Module* getModule() const { return Parent; }\n\n  static bool classof(const Node* N) {\n    return N->getKind() == Kind::ProxyBlock;\n  }\n  /// @endcond\n\nprivate:\n  ProxyBlock(Context& C) : CfgNode(C, Kind::ProxyBlock) {}\n  ProxyBlock(Context& C, const UUID& U) : CfgNode(C, Kind::ProxyBlock, U) {}\n\n  static ProxyBlock* Create(Context& C, const UUID& U) {\n    return C.Create<ProxyBlock>(C, U);\n  }\n\n  void setModule(Module* M) { Parent = M; }\n\n  /// \\brief The protobuf message type used for serializing Block.\n  using MessageType = proto::ProxyBlock;\n\n  /// \\brief Serialize into a protobuf message.\n  ///\n  /// \\param[out] Message   Serialize into this message.\n  ///\n  /// \\return void\n  void toProtobuf(MessageType* Message) const;\n\n  /// \\brief Construct a Block from a protobuf message.\n  ///\n  /// \\param C  The Context in which the deserialized Block will be held.\n  /// \\param Message  The protobuf message from which to deserialize.\n  ///\n  /// \\return The deserialized Block object, or null on failure.\n  static ErrorOr<ProxyBlock*> fromProtobuf(Context& C,\n                                           const MessageType& Message);\n\n  // Present for testing purposes only.\n  void save(std::ostream& Out) const;\n\n  // Present for testing purposes only.\n  static ProxyBlock* load(Context& C, std::istream& In);\n\n  Module* Parent{nullptr};\n\n  friend class Context; // Allow Context to construct proxies.\n  friend class Module;  // Allow Module to call setModule, Create, etc.\n  // Allows serializaton from Module via sequenceToProtobuf.\n  template <typename T> friend typename T::MessageType toProtobuf(const T&);\n  friend class SerializationTestHarness; // Testing support.\n};\n\n} // namespace gtirb\n\n#endif // GTIRB_PROXY_BLOCK_H\n"
  },
  {
    "path": "include/gtirb/Section.hpp",
    "content": "//===- Section.hpp ----------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_SECTION_H\n#define GTIRB_SECTION_H\n\n#include <gtirb/Addr.hpp>\n#include <gtirb/ByteInterval.hpp>\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/DataBlock.hpp>\n#include <gtirb/Node.hpp>\n#include <gtirb/Observer.hpp>\n#include <gtirb/Utility.hpp>\n#include <gtirb/proto/Section.pb.h>\n#include <algorithm>\n#include <boost/icl/interval_map.hpp>\n#include <boost/iterator/indirect_iterator.hpp>\n#include <boost/iterator/iterator_traits.hpp>\n#include <boost/multi_index/hashed_index.hpp>\n#include <boost/multi_index/key_extractors.hpp>\n#include <boost/multi_index/mem_fun.hpp>\n#include <boost/multi_index/ordered_index.hpp>\n#include <boost/range/iterator_range.hpp>\n#include <cstdint>\n#include <functional>\n#include <set>\n\n/// \\file Section.hpp\n/// \\brief Class gtirb::Section.\n\nnamespace gtirb {\nclass Module; // Forward declared for the backpointer.\nclass SectionObserver;\ntemplate <typename T> class ErrorOr;\n\n/// \\enum SectionFlag\n///\n/// \\brief Idenfities the flags used for a section.\nenum class SectionFlag : uint8_t {\n  Undefined = proto::SectionFlag::Section_Undefined,\n  Readable = proto::SectionFlag::Readable,\n  Writable = proto::SectionFlag::Writable,\n  Executable = proto::SectionFlag::Executable,\n  Loaded = proto::SectionFlag::Loaded,\n  Initialized = proto::SectionFlag::Initialized,\n  ThreadLocal = proto::SectionFlag::ThreadLocal,\n};\n\n/// \\class Section\n///\n/// \\brief Represents a named section of the binary.\n///\n/// Does not directly store the contents of the section, which are kept in\n/// \\ref ImageByteMap.\nclass GTIRB_EXPORT_API Section : public Node {\n  Section(Context& C);\n  Section(Context& C, const std::string& N);\n  Section(Context& C, const std::string& N, const UUID& U);\n\n  static Section* Create(Context& C, const std::string& Name, const UUID& U) {\n    return C.Create<Section>(C, Name, U);\n  }\n\n  struct by_address {};\n  struct by_pointer {};\n\n  using ByteIntervalSet = boost::multi_index::multi_index_container<\n      ByteInterval*,\n      boost::multi_index::indexed_by<\n          boost::multi_index::ordered_non_unique<\n              boost::multi_index::tag<by_address>,\n              boost::multi_index::identity<ByteInterval*>, AddressLess>,\n          boost::multi_index::hashed_unique<\n              boost::multi_index::tag<by_pointer>,\n              boost::multi_index::identity<ByteInterval*>>>>;\n  using ByteIntervalIntMap =\n      boost::icl::interval_map<Addr, std::set<ByteInterval*, AddressLess>>;\n\n  class ByteIntervalObserverImpl;\n\npublic:\n  /// \\brief Create an unitialized Section object.\n  /// \\param C        The Context in which this Section will be held.\n  /// \\return         The newly created Section.\n  static Section* Create(Context& C) { return C.Create<Section>(C); }\n\n  /// \\brief Create a Section object.\n  ///\n  /// \\param C        The Context in which this object will be held.\n  /// \\param Name     The name of the section.\n  ///\n  /// \\return The newly created object.\n  static Section* Create(Context& C, const std::string& Name) {\n    return C.Create<Section>(C, Name);\n  }\n\n  /// \\brief Equality operator overload.\n  bool operator==(const Section& Other) const;\n\n  /// \\brief Inequality operator overload.\n  bool operator!=(const Section& Other) const;\n\n  /// \\brief Get the \\ref Module this section belongs to.\n  Module* getModule() { return Parent; }\n  /// \\brief Get the \\ref Module this section belongs to.\n  const Module* getModule() const { return Parent; }\n\n  /// \\brief Get the name of a Section.\n  ///\n  /// \\return The name.\n  const std::string& getName() const { return Name; }\n\n  /// \\brief Adds the flag to the Section.\n  ///\n  /// \\param F The flag to be added.\n  void addFlag(SectionFlag F) { Flags.insert(F); }\n\n  /// \\brief Adds all of the flags to the Section.\n  /// \\tparam Fs A pack of \\ref SectionFlag flags.\n  /// \\param F The flags to be added to the Section.\n  template <typename... Fs> void addFlags(Fs... F) { (addFlag(F), ...); }\n\n  /// \\brief Removes the flag from the Section.\n  ///\n  /// \\param F The flag to be removed.\n  void removeFlag(SectionFlag F) { Flags.erase(F); }\n\n  /// \\brief Tests whether the given flag is set for the Section.\n  ///\n  /// \\param F The flag to test.\n  /// \\return true if the flag is set, false otherwise.\n  bool isFlagSet(SectionFlag F) const {\n    return std::find(Flags.begin(), Flags.end(), F) != Flags.end();\n  }\n\n  /// \\brief Iterator over \\ref SectionFlag flags.\n  using const_section_flag_iterator = std::set<SectionFlag>::const_iterator;\n  /// \\brief Range of \\ref SectionFlag flags.\n  using const_section_flag_range =\n      boost::iterator_range<const_section_flag_iterator>;\n\n  /// \\brief Return a const iterator to the first \\ref SectionFlag.\n  const_section_flag_iterator flags_begin() const { return Flags.begin(); }\n  /// \\brief Return a const iterator to the element following the last \\ref\n  /// SectionFlag.\n  const_section_flag_iterator flags_end() const { return Flags.end(); }\n  /// \\brief Return a range of the \\ref SectionFlag flags set for the Section.\n  const_section_flag_range flags() const {\n    return boost::make_iterator_range(flags_begin(), flags_end());\n  }\n\n  /// \\brief Iterator over \\ref ByteInterval objects.\n  using byte_interval_iterator =\n      boost::indirect_iterator<ByteIntervalSet::iterator>;\n  /// \\brief Range of \\ref ByteInterval objects.\n  using byte_interval_range = boost::iterator_range<byte_interval_iterator>;\n  /// \\brief Sub-range of \\ref ByteInterval objects overlapping addresses.\n  using byte_interval_subrange = boost::iterator_range<\n      boost::indirect_iterator<ByteIntervalIntMap::codomain_type::iterator>>;\n  /// \\brief Const iterator over \\ref ByteInterval objects.\n  using const_byte_interval_iterator =\n      boost::indirect_iterator<ByteIntervalSet::const_iterator,\n                               const ByteInterval>;\n  /// \\brief Const range of \\ref ByteInterval objects.\n  using const_byte_interval_range =\n      boost::iterator_range<const_byte_interval_iterator>;\n  /// \\brief Const sub-range of \\ref ByteInterval objects overlapping addresses.\n  using const_byte_interval_subrange =\n      boost::iterator_range<boost::indirect_iterator<\n          ByteIntervalIntMap::codomain_type::const_iterator>>;\n\n  /// \\brief Return an iterator to the first \\ref ByteInterval.\n  byte_interval_iterator byte_intervals_begin() {\n    return ByteIntervals.begin();\n  }\n  /// \\brief Return a const iterator to the first \\ref ByteInterval.\n  const_byte_interval_iterator byte_intervals_begin() const {\n    return ByteIntervals.begin();\n  }\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// ByteInterval.\n  byte_interval_iterator byte_intervals_end() { return ByteIntervals.end(); }\n  /// \\brief Return a const iterator to the element following the last\n  /// \\ref ByteInterval.\n  const_byte_interval_iterator byte_intervals_end() const {\n    return ByteIntervals.end();\n  }\n  /// \\brief Return a range of the \\ref ByteInterval objects in this section.\n  byte_interval_range byte_intervals() {\n    return boost::make_iterator_range(byte_intervals_begin(),\n                                      byte_intervals_end());\n  }\n  /// \\brief Return a const range of the \\ref ByteInterval objects in this\n  /// section.\n  const_byte_interval_range byte_intervals() const {\n    return boost::make_iterator_range(byte_intervals_begin(),\n                                      byte_intervals_end());\n  }\n\n  /// \\brief Find all the intervals that have bytes that lie within the address\n  /// specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that intersect the address \\p\n  /// A.\n  byte_interval_subrange findByteIntervalsOn(Addr A) {\n    if (auto It = ByteIntervalAddrs.find(A); It != ByteIntervalAddrs.end()) {\n      return boost::make_iterator_range(\n          boost::make_indirect_iterator(It->second.begin()),\n          boost::make_indirect_iterator(It->second.end()));\n    }\n    return {};\n  }\n\n  /// \\brief Find all the intervals that have bytes that lie within the address\n  /// specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that intersect the address \\p\n  /// A.\n  const_byte_interval_subrange findByteIntervalsOn(Addr A) const {\n    if (auto It = ByteIntervalAddrs.find(A); It != ByteIntervalAddrs.end()) {\n      return boost::make_iterator_range(\n          boost::make_indirect_iterator(It->second.begin()),\n          boost::make_indirect_iterator(It->second.end()));\n    }\n    return {};\n  }\n\n  /// \\brief Find all the intervals that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that are at the address \\p A.\n  byte_interval_range findByteIntervalsAt(Addr A) {\n    auto Pair = ByteIntervals.get<by_address>().equal_range(A);\n    return boost::make_iterator_range(byte_interval_iterator(Pair.first),\n                                      byte_interval_iterator(Pair.second));\n  }\n\n  /// \\brief Find all the intervals that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that are between the\n  /// addresses.\n  byte_interval_range findByteIntervalsAt(Addr Low, Addr High) {\n    auto& Index = ByteIntervals.get<by_address>();\n    if (High < Low) {\n      return boost::make_iterator_range(Index.end(), Index.end());\n    }\n    return boost::make_iterator_range(\n        byte_interval_iterator(Index.lower_bound(Low)),\n        byte_interval_iterator(Index.lower_bound(High)));\n  }\n\n  /// \\brief Find all the intervals that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that are at the address \\p A.\n  const_byte_interval_range findByteIntervalsAt(Addr A) const {\n    auto Pair = ByteIntervals.get<by_address>().equal_range(A);\n    return boost::make_iterator_range(\n        const_byte_interval_iterator(Pair.first),\n        const_byte_interval_iterator(Pair.second));\n  }\n\n  /// \\brief Find all the intervals that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref ByteInterval objects that are between the\n  /// addresses.\n  const_byte_interval_range findByteIntervalsAt(Addr Low, Addr High) const {\n    auto& Index = ByteIntervals.get<by_address>();\n    if (High < Low) {\n      return boost::make_iterator_range(Index.end(), Index.end());\n    }\n    return boost::make_iterator_range(\n        const_byte_interval_iterator(Index.lower_bound(Low)),\n        const_byte_interval_iterator(Index.lower_bound(High)));\n  }\n\n  /// \\brief Return the address of this section, if known.\n  ///\n  /// The address is calculated from the \\ref ByteInterval objects in this\n  /// section. More specifically, if the address of all byte intervals in this\n  /// section are fixed, then it will return the address of the interval lowest\n  /// in memory. If any one interval does not have an address, then this\n  /// function will return \\ref std::nullopt, as the address is not calculable\n  /// in that case. Note that a section with no intervals in it has no address\n  /// or size, so it will return \\ref std::nullopt in that case.\n  std::optional<Addr> getAddress() const {\n    if (Extent) {\n      return Extent->lower();\n    }\n    return std::nullopt;\n  }\n\n  /// \\brief Return the size of this section, if known.\n  ///\n  /// The size is calculated from the \\ref ByteInterval objects in this section.\n  /// More specifically, if the address of all byte intervals in this section\n  /// are fixed, then it will return the difference between the lowest and\n  /// highest address among the intervals. If any one interval does not have an\n  /// address, then this function will return \\ref std::nullopt, as the size is\n  /// not calculable in that case. Note that a section with no intervals in it\n  /// has no address or size, so it will return \\ref std::nullopt in that case.\n  std::optional<uint64_t> getSize() const {\n    if (Extent) {\n      return Extent->size();\n    }\n    return std::nullopt;\n  }\n\n  /// \\brief Remove an interval from this section.\n  ///\n  /// \\return Whether the operation succeeded (\\c Accepted), no change was made\n  /// (\\c NoChange), or the operation could not be completed (\\c Rejected). In\n  /// particular, if the node to remove is not actually part of this node to\n  /// begin with, the result will be \\c NoChange.\n  ChangeStatus removeByteInterval(ByteInterval* N);\n\n  /// \\brief Move an existing \\ref ByteInterval to be a part of this section.\n  ///\n  /// \\return a ChangeStatus indicating whether the insertion took place\n  /// (\\c Accepted), was unnecessary because this node already contained the\n  /// ByteInterval (\\c NoChange), or could not be completed (\\c Rejected).\n  ChangeStatus addByteInterval(ByteInterval* BI);\n\n  /// \\brief Creates a new \\ref ByteInterval in this section.\n  ///\n  /// \\tparam Args  The arguments to construct a \\ref ByteInterval.\n  /// \\param  C     The Context in which this object will be held.\n  /// \\param  A     The arguments to construct a \\ref ByteInterval.\n  template <typename... Args>\n  ByteInterval* addByteInterval(Context& C, Args&&... A) {\n    ByteInterval* BI = ByteInterval::Create(C, std::forward<Args>(A)...);\n    [[maybe_unused]] ChangeStatus status = addByteInterval(BI);\n    // addByteInterval(ByteInterval*) does not currently reject any insertions\n    // and the result cannot be NoChange because we just inserted a newly\n    // created ByteInterval.\n    assert(status == ChangeStatus::Accepted &&\n           \"unexpected result when inserting ByteInterval\");\n    return BI;\n  }\n\n  /// \\brief Set this section's name.\n  void setName(const std::string& N);\n\n  /// \\brief Iterator over blocks.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using block_iterator =\n      MergeSortedIterator<ByteInterval::block_iterator, BlockAddressLess>;\n  /// \\brief Range of blocks.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using block_range = boost::iterator_range<block_iterator>;\n  /// \\brief Sub-range of blocks overlapping an address or range of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using block_subrange = boost::iterator_range<MergeSortedIterator<\n      ByteInterval::block_subrange::iterator, BlockAddressLess>>;\n  /// \\brief Const iterator over blocks.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_block_iterator =\n      MergeSortedIterator<ByteInterval::const_block_iterator, BlockAddressLess>;\n  /// \\brief Const range of blocks.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_block_range = boost::iterator_range<const_block_iterator>;\n  /// \\brief Const sub-range of blocks overlapping an address or range of\n  /// addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_block_subrange = boost::iterator_range<MergeSortedIterator<\n      ByteInterval::const_block_subrange::iterator, BlockAddressLess>>;\n\n  /// \\brief Return an iterator to the first block.\n  block_iterator blocks_begin() {\n    return block_iterator(\n        boost::make_transform_iterator(this->byte_intervals_begin(),\n                                       NodeToBlockRange<ByteInterval>()),\n        boost::make_transform_iterator(this->byte_intervals_end(),\n                                       NodeToBlockRange<ByteInterval>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last block.\n  block_iterator blocks_end() { return block_iterator(); }\n\n  /// \\brief Return a range of all the blocks.\n  block_range blocks() {\n    return boost::make_iterator_range(blocks_begin(), blocks_end());\n  }\n\n  /// \\brief Return an iterator to the first block.\n  const_block_iterator blocks_begin() const {\n    return const_block_iterator(\n        boost::make_transform_iterator(this->byte_intervals_begin(),\n                                       NodeToBlockRange<const ByteInterval>()),\n        boost::make_transform_iterator(this->byte_intervals_end(),\n                                       NodeToBlockRange<const ByteInterval>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last block.\n  const_block_iterator blocks_end() const { return const_block_iterator(); }\n\n  /// \\brief Return a range of all the blocks.\n  const_block_range blocks() const {\n    return boost::make_iterator_range(blocks_begin(), blocks_end());\n  }\n\n  /// \\brief Find all the blocks that have bytes that lie within the address\n  /// specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that intersect the address \\p A.\n  block_subrange findBlocksOn(Addr A) {\n    byte_interval_subrange Intervals = findByteIntervalsOn(A);\n    return block_subrange(\n        block_subrange::iterator(\n            boost::make_transform_iterator(Intervals.begin(),\n                                           FindBlocksIn<ByteInterval>(A)),\n            boost::make_transform_iterator(Intervals.end(),\n                                           FindBlocksIn<ByteInterval>(A))),\n        block_subrange::iterator());\n  }\n\n  /// \\brief Find all the blocks that have bytes that lie within the address\n  /// specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that intersect the address \\p A.\n  const_block_subrange findBlocksOn(Addr A) const {\n    const_byte_interval_subrange Intervals = findByteIntervalsOn(A);\n    return const_block_subrange(\n        const_block_subrange::iterator(\n            boost::make_transform_iterator(Intervals.begin(),\n                                           FindBlocksIn<const ByteInterval>(A)),\n            boost::make_transform_iterator(\n                Intervals.end(), FindBlocksIn<const ByteInterval>(A))),\n        const_block_subrange::iterator());\n  }\n\n  /// \\brief Find all the blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are at the address \\p A.\n  block_range findBlocksAt(Addr A) {\n    byte_interval_subrange Intervals = findByteIntervalsOn(A);\n    return block_range(\n        block_range::iterator(\n            boost::make_transform_iterator(Intervals.begin(),\n                                           FindBlocksAt<ByteInterval>(A)),\n            boost::make_transform_iterator(Intervals.end(),\n                                           FindBlocksAt<ByteInterval>(A))),\n        block_range::iterator());\n  }\n\n  /// \\brief Find all the blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are between the addresses.\n  block_range findBlocksAt(Addr Low, Addr High) {\n    std::vector<ByteInterval::block_range> Ranges;\n    for (ByteInterval& BI : findByteIntervalsOn(Low))\n      Ranges.push_back(BI.findBlocksAt(Low, High));\n    for (ByteInterval& BI : findByteIntervalsAt(Low + 1, High))\n      Ranges.push_back(BI.findBlocksAt(Low, High));\n    return block_range(block_iterator(Ranges), block_iterator());\n  }\n\n  /// \\brief Find all the blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are at the address \\p A.\n  const_block_range findBlocksAt(Addr A) const {\n    const_byte_interval_subrange Intervals = findByteIntervalsOn(A);\n    return const_block_range(\n        const_block_range::iterator(\n            boost::make_transform_iterator(Intervals.begin(),\n                                           FindBlocksAt<const ByteInterval>(A)),\n            boost::make_transform_iterator(\n                Intervals.end(), FindBlocksAt<const ByteInterval>(A))),\n        const_block_range::iterator());\n  }\n\n  /// \\brief Find all the blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref Node objects, which are either \\ref DataBlock\n  /// objects or \\ref CodeBlock objects, that are between the addresses.\n  const_block_range findBlocksAt(Addr Low, Addr High) const {\n    std::vector<ByteInterval::const_block_range> Ranges;\n    for (const ByteInterval& BI : findByteIntervalsOn(Low))\n      Ranges.push_back(BI.findBlocksAt(Low, High));\n    for (const ByteInterval& BI : findByteIntervalsAt(Low + 1, High))\n      Ranges.push_back(BI.findBlocksAt(Low, High));\n    return const_block_range(const_block_iterator(Ranges),\n                             const_block_iterator());\n  }\n\n  /// \\brief Iterator over \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using code_block_iterator =\n      MergeSortedIterator<ByteInterval::code_block_iterator, AddressLess>;\n  /// \\brief Range of \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using code_block_range = boost::iterator_range<code_block_iterator>;\n  /// \\brief Sub-range of \\ref CodeBlock objects overlapping an address or range\n  /// of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using code_block_subrange = boost::iterator_range<MergeSortedIterator<\n      ByteInterval::code_block_subrange::iterator, AddressLess>>;\n  /// \\brief Iterator over \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_code_block_iterator =\n      MergeSortedIterator<ByteInterval::const_code_block_iterator, AddressLess>;\n  /// \\brief Range of \\ref CodeBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_code_block_range =\n      boost::iterator_range<const_code_block_iterator>;\n  /// \\brief Sub-range of \\ref CodeBlock objects overlapping an address or range\n  /// of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_code_block_subrange = boost::iterator_range<MergeSortedIterator<\n      ByteInterval::const_code_block_subrange::iterator, AddressLess>>;\n\nprivate:\n  code_block_range makeCodeBlockRange(ByteIntervalSet::iterator Begin,\n                                      ByteIntervalSet::iterator End) {\n    NodeToCodeBlockRange<ByteInterval> Transformer;\n    return boost::make_iterator_range(\n        code_block_iterator(boost::make_transform_iterator(\n                                byte_interval_iterator(Begin), Transformer),\n                            boost::make_transform_iterator(\n                                byte_interval_iterator(End), Transformer)),\n        code_block_iterator());\n  }\n\npublic:\n  /// \\brief Return an iterator to the first \\ref CodeBlock.\n  code_block_iterator code_blocks_begin() {\n    return code_block_iterator(\n        boost::make_transform_iterator(this->byte_intervals_begin(),\n                                       NodeToCodeBlockRange<ByteInterval>()),\n        boost::make_transform_iterator(this->byte_intervals_end(),\n                                       NodeToCodeBlockRange<ByteInterval>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// CodeBlock.\n  code_block_iterator code_blocks_end() { return code_block_iterator(); }\n\n  /// \\brief Return a range of all the \\ref CodeBlock objects.\n  code_block_range code_blocks() {\n    return boost::make_iterator_range(code_blocks_begin(), code_blocks_end());\n  }\n\n  /// \\brief Return an iterator to the first \\ref CodeBlock.\n  const_code_block_iterator code_blocks_begin() const {\n    return const_code_block_iterator(\n        boost::make_transform_iterator(\n            this->byte_intervals_begin(),\n            NodeToCodeBlockRange<const ByteInterval>()),\n        boost::make_transform_iterator(\n            this->byte_intervals_end(),\n            NodeToCodeBlockRange<const ByteInterval>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// CodeBlock.\n  const_code_block_iterator code_blocks_end() const {\n    return const_code_block_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref CodeBlock objects.\n  const_code_block_range code_blocks() const {\n    return boost::make_iterator_range(code_blocks_begin(), code_blocks_end());\n  }\n\n  /// \\brief Find all the code blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeNode object that intersect the address \\p A.\n  code_block_subrange findCodeBlocksOn(Addr A) {\n    byte_interval_subrange Intervals = findByteIntervalsOn(A);\n    return code_block_subrange(\n        code_block_subrange::iterator(\n            boost::make_transform_iterator(Intervals.begin(),\n                                           FindCodeBlocksIn<ByteInterval>(A)),\n            boost::make_transform_iterator(Intervals.end(),\n                                           FindCodeBlocksIn<ByteInterval>(A))),\n        code_block_subrange::iterator());\n  }\n\n  /// \\brief Find all the code blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that intersect the address \\p A.\n  const_code_block_subrange findCodeBlocksOn(Addr A) const {\n    const_byte_interval_subrange Intervals = findByteIntervalsOn(A);\n    return const_code_block_subrange(\n        const_code_block_subrange::iterator(\n            boost::make_transform_iterator(\n                Intervals.begin(), FindCodeBlocksIn<const ByteInterval>(A)),\n            boost::make_transform_iterator(\n                Intervals.end(), FindCodeBlocksIn<const ByteInterval>(A))),\n        const_code_block_subrange::iterator());\n  }\n\n  /// \\brief Find all the code blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are at the address \\p A.\n  code_block_range findCodeBlocksAt(Addr A) {\n    byte_interval_subrange Intervals = findByteIntervalsOn(A);\n    return code_block_range(\n        code_block_range::iterator(\n            boost::make_transform_iterator(Intervals.begin(),\n                                           FindCodeBlocksAt<ByteInterval>(A)),\n            boost::make_transform_iterator(Intervals.end(),\n                                           FindCodeBlocksAt<ByteInterval>(A))),\n        code_block_range::iterator());\n  }\n\n  /// \\brief Find all the code blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are between the addresses.\n  code_block_range findCodeBlocksAt(Addr Low, Addr High) {\n    std::vector<ByteInterval::code_block_range> Ranges;\n    for (ByteInterval& BI : findByteIntervalsOn(Low))\n      Ranges.push_back(BI.findCodeBlocksAt(Low, High));\n    for (ByteInterval& BI : findByteIntervalsAt(Low + 1, High))\n      Ranges.push_back(BI.findCodeBlocksAt(Low, High));\n    return code_block_range(code_block_iterator(Ranges), code_block_iterator());\n  }\n\n  /// \\brief Find all the code blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are at the address \\p A.\n  const_code_block_range findCodeBlocksAt(Addr A) const {\n    const_byte_interval_subrange Intervals = findByteIntervalsOn(A);\n    return const_code_block_range(\n        const_code_block_range::iterator(\n            boost::make_transform_iterator(\n                Intervals.begin(), FindCodeBlocksAt<const ByteInterval>(A)),\n            boost::make_transform_iterator(\n                Intervals.end(), FindCodeBlocksAt<const ByteInterval>(A))),\n        const_code_block_range::iterator());\n  }\n\n  /// \\brief Find all the code blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref CodeBlock objects that are between the addresses.\n  const_code_block_range findCodeBlocksAt(Addr Low, Addr High) const {\n    std::vector<ByteInterval::const_code_block_range> Ranges;\n    for (const ByteInterval& BI : findByteIntervalsOn(Low))\n      Ranges.push_back(BI.findCodeBlocksAt(Low, High));\n    for (const ByteInterval& BI : findByteIntervalsAt(Low + 1, High))\n      Ranges.push_back(BI.findCodeBlocksAt(Low, High));\n    return const_code_block_range(const_code_block_iterator(Ranges),\n                                  const_code_block_iterator());\n  }\n\n  /// \\brief Iterator over \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using data_block_iterator =\n      MergeSortedIterator<ByteInterval::data_block_iterator, AddressLess>;\n  /// \\brief Range of \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using data_block_range = boost::iterator_range<data_block_iterator>;\n  /// \\brief Sub-range of \\ref DataBlock objects overlapping an address or range\n  /// of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using data_block_subrange = boost::iterator_range<MergeSortedIterator<\n      ByteInterval::data_block_subrange::iterator, AddressLess>>;\n  /// \\brief Iterator over \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_data_block_iterator =\n      MergeSortedIterator<ByteInterval::const_data_block_iterator, AddressLess>;\n  /// \\brief Range of \\ref DataBlock objects.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_data_block_range =\n      boost::iterator_range<const_data_block_iterator>;\n  /// \\brief Sub-range of \\ref DataBlock objects overlapping an address or range\n  /// of addreses.\n  ///\n  /// Blocks are yielded in address order, ascending. For more details, see\n  /// \\ref iteration_order \"the documentation on iteration order\".\n  using const_data_block_subrange = boost::iterator_range<MergeSortedIterator<\n      ByteInterval::const_data_block_subrange::iterator, AddressLess>>;\n\n  /// \\brief Return an iterator to the first \\ref DataBlock.\n  data_block_iterator data_blocks_begin() {\n    return data_block_iterator(\n        boost::make_transform_iterator(this->byte_intervals_begin(),\n                                       NodeToDataBlockRange<ByteInterval>()),\n        boost::make_transform_iterator(this->byte_intervals_end(),\n                                       NodeToDataBlockRange<ByteInterval>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// DataBlock.\n  data_block_iterator data_blocks_end() { return data_block_iterator(); }\n\n  /// \\brief Return a range of all the \\ref DataBlock objects.\n  data_block_range data_blocks() {\n    return boost::make_iterator_range(data_blocks_begin(), data_blocks_end());\n  }\n\n  /// \\brief Return an iterator to the first \\ref DataBlock.\n  const_data_block_iterator data_blocks_begin() const {\n    return const_data_block_iterator(\n        boost::make_transform_iterator(\n            this->byte_intervals_begin(),\n            NodeToDataBlockRange<const ByteInterval>()),\n        boost::make_transform_iterator(\n            this->byte_intervals_end(),\n            NodeToDataBlockRange<const ByteInterval>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// DataBlock.\n  const_data_block_iterator data_blocks_end() const {\n    return const_data_block_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref DataBlock objects.\n  const_data_block_range data_blocks() const {\n    return boost::make_iterator_range(data_blocks_begin(), data_blocks_end());\n  }\n\n  /// \\brief Find all the data blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataNode object that intersect the address \\p A.\n  data_block_subrange findDataBlocksOn(Addr A) {\n    byte_interval_subrange Intervals = findByteIntervalsOn(A);\n    return data_block_subrange(\n        data_block_subrange::iterator(\n            boost::make_transform_iterator(Intervals.begin(),\n                                           FindDataBlocksIn<ByteInterval>(A)),\n            boost::make_transform_iterator(Intervals.end(),\n                                           FindDataBlocksIn<ByteInterval>(A))),\n        data_block_subrange::iterator());\n  }\n\n  /// \\brief Find all the data blocks that have bytes that lie within the\n  /// address specified.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataBlock objects that intersect the address \\p A.\n  const_data_block_subrange findDataBlocksOn(Addr A) const {\n    const_byte_interval_subrange Intervals = findByteIntervalsOn(A);\n    return const_data_block_subrange(\n        const_data_block_subrange::iterator(\n            boost::make_transform_iterator(\n                Intervals.begin(), FindDataBlocksIn<const ByteInterval>(A)),\n            boost::make_transform_iterator(\n                Intervals.end(), FindDataBlocksIn<const ByteInterval>(A))),\n        const_data_block_subrange::iterator());\n  }\n\n  /// \\brief Find all the data blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are at the address \\p A.\n  data_block_range findDataBlocksAt(Addr A) {\n    byte_interval_subrange Intervals = findByteIntervalsOn(A);\n    return data_block_range(\n        data_block_range::iterator(\n            boost::make_transform_iterator(Intervals.begin(),\n                                           FindDataBlocksAt<ByteInterval>(A)),\n            boost::make_transform_iterator(Intervals.end(),\n                                           FindDataBlocksAt<ByteInterval>(A))),\n        data_block_range::iterator());\n  }\n\n  /// \\brief Find all the data blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are between the addresses.\n  data_block_range findDataBlocksAt(Addr Low, Addr High) {\n    std::vector<ByteInterval::data_block_range> Ranges;\n    for (ByteInterval& BI : findByteIntervalsOn(Low))\n      Ranges.push_back(BI.findDataBlocksAt(Low, High));\n    for (ByteInterval& BI : findByteIntervalsAt(Low + 1, High))\n      Ranges.push_back(BI.findDataBlocksAt(Low, High));\n    return data_block_range(data_block_iterator(Ranges), data_block_iterator());\n  }\n\n  /// \\brief Find all the data blocks that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are at the address \\p A.\n  const_data_block_range findDataBlocksAt(Addr A) const {\n    const_byte_interval_subrange Intervals = findByteIntervalsOn(A);\n    return const_data_block_range(\n        const_data_block_range::iterator(\n            boost::make_transform_iterator(\n                Intervals.begin(), FindDataBlocksAt<const ByteInterval>(A)),\n            boost::make_transform_iterator(\n                Intervals.end(), FindDataBlocksAt<const ByteInterval>(A))),\n        const_data_block_range::iterator());\n  }\n\n  /// \\brief Find all the data blocks that start between a range of addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref DataBlock objects that are between the addresses.\n  const_data_block_range findDataBlocksAt(Addr Low, Addr High) const {\n    std::vector<ByteInterval::const_data_block_range> Ranges;\n    for (const ByteInterval& BI : findByteIntervalsOn(Low))\n      Ranges.push_back(BI.findDataBlocksAt(Low, High));\n    for (const ByteInterval& BI : findByteIntervalsAt(Low + 1, High))\n      Ranges.push_back(BI.findDataBlocksAt(Low, High));\n    return const_data_block_range(const_data_block_iterator(Ranges),\n                                  const_data_block_iterator());\n  }\n\n  /// \\brief Iterator over \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in address order, ascending.\n  using symbolic_expression_iterator =\n      MergeSortedIterator<ByteInterval::symbolic_expression_iterator,\n                          ByteInterval::SymbolicExpressionElement::AddressLess>;\n  /// \\brief Range of \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in address order, ascending.\n  using symbolic_expression_range =\n      boost::iterator_range<symbolic_expression_iterator>;\n  /// \\brief Iterator over \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in address order, ascending.\n  using const_symbolic_expression_iterator = MergeSortedIterator<\n      ByteInterval::const_symbolic_expression_iterator,\n      ByteInterval::ConstSymbolicExpressionElement::AddressLess>;\n  /// \\brief Range of \\ref SymbolicExpressionElement objects.\n  ///\n  /// Results are yielded in address order, ascending.\n  using const_symbolic_expression_range =\n      boost::iterator_range<const_symbolic_expression_iterator>;\n\n  /// \\brief Return an iterator to the first \\ref SymbolicExpression.\n  symbolic_expression_iterator symbolic_expressions_begin() {\n    return symbolic_expression_iterator(\n        boost::make_transform_iterator(\n            this->byte_intervals_begin(),\n            NodeToSymbolicExpressionRange<ByteInterval>()),\n        boost::make_transform_iterator(\n            this->byte_intervals_end(),\n            NodeToSymbolicExpressionRange<ByteInterval>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// SymbolicExpression.\n  symbolic_expression_iterator symbolic_expressions_end() {\n    return symbolic_expression_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref SymbolicExpression objects.\n  symbolic_expression_range symbolic_expressions() {\n    return boost::make_iterator_range(symbolic_expressions_begin(),\n                                      symbolic_expressions_end());\n  }\n\n  /// \\brief Return an iterator to the first \\ref SymbolicExpression.\n  const_symbolic_expression_iterator symbolic_expressions_begin() const {\n    return const_symbolic_expression_iterator(\n        boost::make_transform_iterator(\n            this->byte_intervals_begin(),\n            NodeToSymbolicExpressionRange<const ByteInterval>()),\n        boost::make_transform_iterator(\n            this->byte_intervals_end(),\n            NodeToSymbolicExpressionRange<const ByteInterval>()));\n  }\n\n  /// \\brief Return an iterator to the element following the last \\ref\n  /// SymbolicExpression.\n  const_symbolic_expression_iterator symbolic_expressions_end() const {\n    return const_symbolic_expression_iterator();\n  }\n\n  /// \\brief Return a range of all the \\ref SymbolicExpression objects.\n  const_symbolic_expression_range symbolic_expressions() const {\n    return boost::make_iterator_range(symbolic_expressions_begin(),\n                                      symbolic_expressions_end());\n  }\n\n  /// \\brief Find all the symbolic expressions that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are at the address\n  /// \\p A.\n  symbolic_expression_range findSymbolicExpressionsAt(Addr A) {\n    return symbolic_expression_range(\n        symbolic_expression_range::iterator(\n            boost::make_transform_iterator(this->byte_intervals_begin(),\n                                           FindSymExprsAt<ByteInterval>(A)),\n            boost::make_transform_iterator(this->byte_intervals_end(),\n                                           FindSymExprsAt<ByteInterval>(A))),\n        symbolic_expression_range::iterator());\n  }\n\n  /// \\brief Find all the symbolic expressions that start between a range of\n  /// addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are between the\n  /// addresses.\n  symbolic_expression_range findSymbolicExpressionsAt(Addr Low, Addr High) {\n    return symbolic_expression_range(\n        symbolic_expression_range::iterator(\n            boost::make_transform_iterator(\n                this->byte_intervals_begin(),\n                FindSymExprsBetween<ByteInterval>(Low, High)),\n            boost::make_transform_iterator(\n                this->byte_intervals_end(),\n                FindSymExprsBetween<ByteInterval>(Low, High))),\n        symbolic_expression_range::iterator());\n  }\n\n  /// \\brief Find all the symbolic expressions that start at an address.\n  ///\n  /// \\param A The address to look up.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are at the address\n  /// \\p A.\n  const_symbolic_expression_range findSymbolicExpressionsAt(Addr A) const {\n    return const_symbolic_expression_range(\n        const_symbolic_expression_range::iterator(\n            boost::make_transform_iterator(\n                this->byte_intervals_begin(),\n                FindSymExprsAt<const ByteInterval>(A)),\n            boost::make_transform_iterator(\n                this->byte_intervals_end(),\n                FindSymExprsAt<const ByteInterval>(A))),\n        const_symbolic_expression_range::iterator());\n  }\n\n  /// \\brief Find all the symbolic expressions that start between a range of\n  /// addresses.\n  ///\n  /// \\param Low  The low address, inclusive.\n  /// \\param High The high address, exclusive.\n  ///\n  /// \\return A range of \\ref SymbolicExpression objects that are between the\n  /// addresses.\n  const_symbolic_expression_range findSymbolicExpressionsAt(Addr Low,\n                                                            Addr High) const {\n    return const_symbolic_expression_range(\n        const_symbolic_expression_range::iterator(\n            boost::make_transform_iterator(\n                this->byte_intervals_begin(),\n                FindSymExprsBetween<const ByteInterval>(Low, High)),\n            boost::make_transform_iterator(\n                this->byte_intervals_end(),\n                FindSymExprsBetween<const ByteInterval>(Low, High))),\n        const_symbolic_expression_range::iterator());\n  }\n\n  /// @cond INTERNAL\n  static bool classof(const Node* N) { return N->getKind() == Kind::Section; }\n  /// @endcond\n\nprivate:\n  Module* Parent{nullptr};\n  SectionObserver* Observer{nullptr};\n  std::string Name;\n  ByteIntervalSet ByteIntervals;\n  ByteIntervalIntMap ByteIntervalAddrs;\n  std::optional<AddrRange> Extent;\n  std::set<SectionFlag> Flags;\n\n  std::unique_ptr<ByteIntervalObserver> BIO;\n\n  /// \\brief Remove a ByteInterval from ByteIntervalAddrs.\n  void removeByteIntervalAddrs(ByteInterval* BI);\n\n  /// \\brief Add a ByteInterval to ByteIntervalAddrs.\n  ///\n  /// The caller is responsible for ensuring that the ByteInterval is owned\n  /// by this Section.\n  void insertByteIntervalAddrs(ByteInterval* BI);\n\n  /// \\brief Update the extent after adding/removing a ByteInterval.\n  ChangeStatus updateExtent();\n\n  void setParent(Module* M, SectionObserver* O) {\n    Parent = M;\n    Observer = O;\n  }\n\n  /// \\brief The protobuf message type used for serializing Section.\n  using MessageType = proto::Section;\n\n  /// \\brief Serialize into a protobuf message.\n  ///\n  /// \\param[out] Message   Serialize into this message.\n  ///\n  /// \\return void\n  void toProtobuf(MessageType* Message) const;\n\n  /// \\brief Construct a Section from a protobuf message.\n  ///\n  /// \\param C   The Context in which the deserialized Section will be held.\n  /// \\param Message  The protobuf message from which to deserialize.\n  ///\n  /// \\return The deserialized Section object, or null on failure.\n  static ErrorOr<Section*> fromProtobuf(Context& C, const MessageType& Message);\n\n  // Present for testing purposes only.\n  void save(std::ostream& Out) const;\n\n  // Present for testing purposes only.\n  static Section* load(Context& C, std::istream& In);\n\n  friend class Context; // Allow Context to construct sections.\n  friend class Module;  // Allow Module to call setModule, Create, etc.\n  // Allows serializaton from Module via sequenceToProtobuf.\n  template <typename T> friend typename T::MessageType toProtobuf(const T&);\n  friend class SerializationTestHarness; // Testing support.\n};\n\n/// \\class SectionObserver\n///\n/// \\brief Interface for notifying observers when the Section is modified.\n///\n\nclass GTIRB_EXPORT_API SectionObserver {\npublic:\n  virtual ~SectionObserver() = default;\n\n  /// \\brief Notify the parent when this Section's name changes.\n  ///\n  /// Called after the Section updates its internal state.\n  ///\n  /// \\param S        the Section whose name changed.\n  /// \\param OldName  the Section's previous name.\n  /// \\param NewName  the new name of this section.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus nameChange(Section* S, const std::string& OldName,\n                                  const std::string& NewName) = 0;\n\n  /// \\brief Notify the parent when new CodeBlocks are added to the Section.\n  ///\n  /// Called after the Section updates its internal state.\n  ///\n  /// \\param S       the Section to which CodeBlocks were added.\n  /// \\param Blocks  a range containing the new CodeBlocks.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus addCodeBlocks(Section* S,\n                                     Section::code_block_range Blocks) = 0;\n\n  /// \\brief Notify the parent when the addresses of existing CodeBlocks change.\n  ///\n  /// Called after the Section updates its internal state.\n  ///\n  /// \\param S       the Section containing the CodeBlocks.\n  /// \\param Blocks  a range containing the CodeBlocks that moved.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus moveCodeBlocks(Section* S,\n                                      Section::code_block_range Blocks) = 0;\n\n  /// \\brief Notify the parent when CodeBlocks are removed from the Section.\n  ///\n  /// Called before the Section updates its internal state.\n  ///\n  /// \\param S       the Section from which CodeBlocks will be removed.\n  /// \\param Blocks  a range containing the CodeBlocks to remove.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus removeCodeBlocks(Section* S,\n                                        Section::code_block_range Blocks) = 0;\n\n  /// \\brief Notify the parent when new DataBlocks are added to the Section.\n  ///\n  /// Called after the Section updates its internal state.\n  ///\n  /// \\param S       the Section to which DataBlocks were added.\n  /// \\param Blocks  a range containing the new DataBlocks.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus addDataBlocks(Section* S,\n                                     Section::data_block_range Blocks) = 0;\n\n  /// \\brief Notify the parent when the addresses of existing DataBlocks change.\n  ///\n  /// Called after the Section updates its internal state.\n  ///\n  /// \\param S       the Section containing the DataBlocks.\n  /// \\param Blocks  a range containing the DataBlocks that moved.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus moveDataBlocks(Section* S,\n                                      Section::data_block_range Blocks) = 0;\n\n  /// \\brief Notify the parent when DataBlocks are removed from the Section.\n  ///\n  /// Called before the Section updates its internal state.\n  ///\n  /// \\param S       the Section from which DataBlocks will be removed.\n  /// \\param Blocks  a range containing the DataBlocks to remove.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus removeDataBlocks(Section* S,\n                                        Section::data_block_range Blocks) = 0;\n\n  /// \\brief Notify parent when the range of addresses in the Section changes.\n  ///\n  /// Called before the Section's extent changes. This method should invoke the\n  /// callback with \\p S to update its extent.\n  ///\n  /// \\param S         the Section that changed.\n  /// \\param Callback  callable to update the ByteInterval's extent.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus changeExtent(Section* S,\n                                    std::function<void(Section*)> Callback) = 0;\n};\n\ninline void Section::setName(const std::string& X) {\n  if (Observer) {\n    std::string OldName = X;\n    std::swap(Name, OldName);\n    [[maybe_unused]] ChangeStatus status =\n        Observer->nameChange(this, OldName, Name);\n    // The known observers do not reject insertions. If that changes, this\n    // method must be updated.\n    assert(status != ChangeStatus::Rejected &&\n           \"recovering from rejected name change is unimplemented\");\n  } else {\n    Name = X;\n  }\n}\n} // namespace gtirb\n\n#endif // GTIRB_SECTION_H\n"
  },
  {
    "path": "include/gtirb/Symbol.hpp",
    "content": "//===- Symbol.hpp -----------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_SYMBOL_H\n#define GTIRB_SYMBOL_H\n\n#include <gtirb/Addr.hpp>\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/DataBlock.hpp>\n#include <gtirb/Node.hpp>\n#include <gtirb/ProxyBlock.hpp>\n#include <functional>\n#include <optional>\n#include <type_traits>\n#include <variant>\n\n/// \\file Symbol.hpp\n/// \\brief Class gtirb::Symbol.\n\nnamespace gtirb {\nnamespace proto {\nclass Symbol;\n}\n\ntemplate <class T> class ErrorOr;\nclass Module; // Forward declared for the backpointer.\nclass SymbolObserver;\n\n/// \\class Symbol\n///\n/// \\brief Represents a Symbol, which maps a name to an object in the IR.\nclass GTIRB_EXPORT_API Symbol : public Node {\n  template <typename... Ts> struct TypeList {};\n\n  // SFINAE overload handling a Callable with a void return type.\n  template <typename Callable, typename Ty, typename CommonRetTy>\n  auto visit_impl_help(Callable&& Visitor) const\n      -> std::enable_if_t<std::is_void_v<CommonRetTy>, bool> {\n    static_assert(std::is_invocable_v<Callable, Ty*>,\n                  \"Visitor must contain an overloaded function call operator \"\n                  \"for each of the types in supported_types\");\n    if (Node* const* Ptr = std::get_if<Node*>(&Payload)) {\n      if (Ty* Obj = dyn_cast_or_null<Ty>(*Ptr)) {\n        std::invoke(Visitor, Obj);\n        return true;\n      }\n    }\n    return false;\n  }\n\n  // SFINAE overload handling a Callable with a non-void return type.\n  template <typename Callable, typename Ty, typename CommonRetTy>\n  bool\n  visit_impl_help(Callable&& Visitor,\n                  std::enable_if_t<!std::is_void_v<CommonRetTy>,\n                                   std::optional<CommonRetTy>>& Ret) const {\n    static_assert(std::is_invocable_v<Callable, Ty*>,\n                  \"Visitor must contain an overloaded function call operator \"\n                  \"for each of the types in supported_types\");\n    if (Node* const* Ptr = std::get_if<Node*>(&Payload)) {\n      if (Ty* Obj = dyn_cast_or_null<Ty>(*Ptr)) {\n        Ret = std::invoke(Visitor, Obj);\n        return true;\n      }\n    }\n    return false;\n  }\n\n  // Helper type traits used to determine whether all of the Callable object's\n  // return types agree. Note that the return types do not need to be the same,\n  // but do need to be implicitly convertible to the same common type. e.g.,\n  // this class is a valid Callable.\n  //   struct Visitor {\n  //     int operator()(Block*);\n  //     long operator()(DataBlock*);\n  //  };\n  template <typename AlwaysVoid, typename Callable,\n            template <typename...> typename TypeList, typename... Types>\n  struct common_return_type_impl : std::false_type {};\n\n  template <typename Callable, template <typename...> typename TypeList,\n            typename... Types>\n  struct common_return_type_impl<\n      std::void_t<\n          std::common_type_t<std::invoke_result_t<Callable, Types*>...>>,\n      Callable, TypeList, Types...> : std::true_type {\n    using type = std::common_type_t<std::invoke_result_t<Callable, Types*>...>;\n  };\n\n  template <typename Callable, template <typename...> typename TypeList,\n            typename... Types>\n  using common_return_type_t =\n      typename common_return_type_impl<void, Callable, TypeList,\n                                       Types...>::type;\n\n  template <typename Callable, template <typename...> typename TypeList,\n            typename... Types>\n  static constexpr bool common_return_type_v =\n      common_return_type_impl<void, Callable, TypeList, Types...>::value;\n\n  // Helper function to unpack all of the types in the type list and attempt to\n  // visit Callable once per type. Verifies that the Callable objects all share\n  // a compatible return type.\n  //\n  // SFINAE overload handling a Callable where there is a common, non-void\n  // return type. Returns a std::optional<common_type>.\n  template <typename Callable, template <typename...> typename TypeList,\n            typename... Types>\n  auto visit_impl(Callable&& Visitor, TypeList<Types...>) const\n      -> std::enable_if_t<\n          !std::is_void_v<common_return_type_t<Callable, TypeList, Types...>>,\n          std::optional<common_return_type_t<Callable, TypeList, Types...>>> {\n    // If this assertion fails, the return values from the Callable object are\n    // not compatible enough. This can happen if they return incompatible types\n    // or if there is not an overload for each referent type.\n    static_assert(common_return_type_v<Callable, TypeList, Types...>,\n                  \"incompatible return types for the Callable object\");\n    // Instantiate a call to the Visitor once for each of the listed types, but\n    // only issue the call at runtime if the Referent can be dynamically cast to\n    // the given type. In this way, the Visitor needs to be able to handle any\n    // of the supported types, but will only be called once for the concrete\n    // type of the Referent.\n    //\n    // If you get an error about there being no matching overloaded function for\n    // the call to visit_impl_help, that is most likely because there are one\n    // or more overloads missing for each referent type.\n    std::optional<common_return_type_t<Callable, TypeList, Types...>> Res;\n    (... ||\n     visit_impl_help<Callable, Types, typename decltype(Res)::value_type>(\n         std::forward<Callable>(Visitor), Res));\n    return Res;\n  }\n\n  // SFINAE overload handling a Callable where every return type is void.\n  // Returns void.\n  template <typename Callable, template <typename...> typename TypeList,\n            typename... Types>\n  auto visit_impl(Callable&& Visitor, TypeList<Types...>) const\n      -> std::enable_if_t<\n          std::is_void_v<common_return_type_t<Callable, TypeList, Types...>>,\n          void> {\n    // Call each of the overloads on Callable, but there is no value to be\n    // returned from any of the calls.\n    (... ||\n     visit_impl_help<Callable, Types, void>(std::forward<Callable>(Visitor)));\n  }\n\n  // Helper function that determines whether the passed NodeTy is the same as\n  // any of the types in the Types... list.\n  template <typename NodeTy, template <typename...> typename TypeList,\n            typename... Types>\n  static constexpr bool is_supported_type_impl(TypeList<Types...>) {\n    return (... || std::is_same_v<NodeTy, Types>);\n  }\n\npublic:\n  // Helper function that determines whether the passed NodeTy is one of the\n  // supported referent types.\n  template <typename NodeTy> static constexpr bool is_supported_type() {\n    return is_supported_type_impl<NodeTy>(\n        std::decay_t<supported_referent_types>{});\n  }\n\n  /// \\brief The list of supported referent types.\n  using supported_referent_types = TypeList<CodeBlock, DataBlock, ProxyBlock>;\n\n  /// \\brief Visits the symbol's referent, if one is present, by concrete\n  /// referent type.\n  ///\n  /// \\tparam Callable  A callable function type. This type must be able to be\n  /// called with a pointer to all of the types listed in \\ref\n  /// supported_referent_types. All overloaded functions must have a common,\n  /// compatible return type.\n  ///\n  /// \\param Visitor  A callable object that will be called with a nonnull\n  /// symbol referent.\n  ///\n  /// \\return The common type of each of the return types in the \\p Callable\n  /// overload set. Notionally returns:\n  /// std::common_type_t<Overload1(Ty1), Overload2(Ty2), ...>\n  /// which can be void.\n  ///\n  /// For example:\n  ///\n  /// \\code\n  /// struct Visitor {\n  ///   int operator()(CfgNode*) { return 0; }\n  ///   long operator()(DataBlock*) { return 1; }\n  /// };\n  ///\n  /// Context Ctx;\n  /// Symbol* SymB = Symbol::Create(Ctx, Block::Create(Ctx), \"\");\n  /// Symbol* SymD = Symbol::Create(Ctx, DataBlock::Create(Ctx), \"\");\n  /// Symbol* SymX = Symbol::Create(Ctx, Addr(42), \"\");\n  /// Symbol* SymN = Symbol::Create(Ctx);\n  ///\n  /// SymB->visit(Visitor{}); // Will call Visitor::operator()(CfgNode*);\n  /// SymD->visit(Visitor{}); // Will call Visitor::operator()(DataBlock*);\n  /// SymX->visit(Visitor{}); // Will not call any overload\n  /// SymN->visit(Visitor{}); // Will not call any overload\n  /// \\endcode\n  template <typename Callable> auto visit(Callable&& Visitor) const {\n    return visit_impl(std::forward<Callable>(Visitor),\n                      std::decay_t<supported_referent_types>{});\n  }\n\n  /// \\brief Create an unitialized Symbol object.\n  /// \\param C        The Context in which this Symbol will be held.\n  /// \\return         The newly created Symbol.\n  static Symbol* Create(Context& C) { return C.Create<Symbol>(C); }\n\n  /// \\brief Create a Symbol object.\n  ///\n  /// \\param C      The Context in which this object will be held.\n  /// \\param Name   The name of the symbol.\n  /// \\param AtEnd  If true, this symbol points to the end of its referent,\n  ///               rather than at the beginning. Defaults to false.\n  ///\n  /// \\return The newly created object.\n  static Symbol* Create(Context& C, const std::string& Name,\n                        bool AtEnd = false) {\n    return C.Create<Symbol>(C, Name, AtEnd);\n  }\n\n  /// \\brief Create a Symbol object.\n  ///\n  /// \\param C      The Context in which this object will be held.\n  /// \\param X      The address of the symbol.\n  /// \\param Name   The name of the symbol.\n  /// \\param AtEnd  If true, this symbol points to the end of its referent,\n  ///               rather than at the beginning. Defaults to false.\n  ///\n  /// \\return The newly created object.\n  static Symbol* Create(Context& C, Addr X, const std::string& Name,\n                        bool AtEnd = false) {\n    return C.Create<Symbol>(C, X, Name, AtEnd);\n  }\n\n  /// \\brief Create a Symbol object.\n  ///\n  /// \\param C        The Context in which this object will be held.\n  /// \\param Referent The DataBlock this symbol refers to.\n  /// \\param Name     The name of the symbol.\n  /// \\param AtEnd  If true, this symbol points to the end of its referent,\n  ///               rather than at the beginning. Defaults to false.\n  ///\n  /// \\return The newly created object.\n  template <typename NodeTy>\n  static Symbol* Create(Context& C, NodeTy* Referent, const std::string& Name,\n                        bool AtEnd = false) {\n    static_assert(is_supported_type<NodeTy>(), \"unsupported referent type\");\n    return C.Create<Symbol>(C, Referent, Name, AtEnd);\n  }\n\n  /// \\brief Get the \\ref Module this symbol belongs to.\n  Module* getModule() { return Parent; }\n  /// \\brief Get the \\ref Module this symbol belongs to.\n  const Module* getModule() const { return Parent; }\n\n  /// \\brief Get the effective address.\n  ///\n  /// \\return The effective address.\n  std::optional<Addr> getAddress() const;\n\n  /// \\brief Get the name.\n  ///\n  /// \\return The name.\n  const std::string& getName() const { return Name; }\n\n  /// \\brief Get the referent to which this symbol refers.\n  ///\n  /// \\tparam NodeTy A Node type of a supported referent.\n  ///\n  /// \\return The data, dynamically typed as the given \\p NodeTy, or\n  /// null if there is no referent of that type.\n  template <typename NodeTy> NodeTy* getReferent() {\n    if (Node* const* Ptr = std::get_if<Node*>(&Payload))\n      return dyn_cast_or_null<NodeTy>(*Ptr);\n    return nullptr;\n  }\n\n  /// \\brief Get the referent to which this symbol refers.\n  ///\n  /// \\tparam NodeTy A Node type of a supported referent.\n  ///\n  /// \\return The data, dynamically typed as the given \\p NodeTy, or\n  /// null if there is no referent of that type.\n  template <typename NodeTy> const NodeTy* getReferent() const {\n    if (Node* const* Ptr = std::get_if<Node*>(&Payload))\n      return dyn_cast_or_null<NodeTy>(*Ptr);\n    return nullptr;\n  }\n\n  /// \\brief Check if this symbol has a referent.\n  ///\n  /// \\return \\p true if the symbol has a referent, \\p false otherwise.\n  bool hasReferent() const { return std::holds_alternative<Node*>(Payload); }\n\n  /// \\brief Set the name of a symbol.\n  void setName(const std::string& N);\n\n  /// \\brief Set the referent of a symbol.\n  ///\n  /// If the referent of a symbol is set to null, then the value of the\n  /// symbol's payload will be cleared (that is, \\ref hasReference will return\n  /// false).\n  template <typename NodeTy>\n  std::enable_if_t<is_supported_type<NodeTy>()> setReferent(NodeTy* N) {\n    setReferentFromNode(N);\n  }\n\n  /// \\brief Set the address of a symbol.\n  void setAddress(Addr A);\n\n  /// \\brief If true, this symbol is pointing to the end of the referent\n  /// rather than at the beginning.\n  ///\n  /// This value has no meaning for integral symbols.\n  bool getAtEnd() const { return AtEnd; }\n\n  /// \\brief sets whether or not this symbol is pointing to the end of the\n  /// referent rather than at the beginning.\n  ///\n  /// This value has no meaning for integral symbols.\n  void setAtEnd(bool AE) { AtEnd = AE; }\n\n  /// @cond INTERNAL\n  static bool classof(const Node* N) { return N->getKind() == Kind::Symbol; }\n  /// @endcond\n\nprivate:\n  Symbol(Context& C) : Node(C, Kind::Symbol) {}\n  Symbol(Context& C, const std::string& N, bool AE)\n      : Node(C, Kind::Symbol), Name(N), AtEnd(AE) {}\n  Symbol(Context& C, const std::string& N, bool AE, const UUID& U)\n      : Node(C, Kind::Symbol, U), Name(N), AtEnd(AE) {}\n  Symbol(Context& C, Addr X, const std::string& N, bool AE)\n      : Node(C, Kind::Symbol), Payload(X), Name(N), AtEnd(AE) {}\n  template <typename NodeTy>\n  Symbol(Context& C, NodeTy* R, const std::string& N, bool AE)\n      : Node(C, Kind::Symbol), Payload(R), Name(N), AtEnd(AE) {\n    if (!R) {\n      Payload = std::monostate{};\n    }\n  }\n\n  static Symbol* Create(Context& C, const std::string& Name, bool AtEnd,\n                        const UUID& U) {\n    return C.Create<Symbol>(C, Name, AtEnd, U);\n  }\n\n  void setParent(Module* M, SymbolObserver* O) {\n    Parent = M;\n    Observer = O;\n  }\n\n  void setReferentFromNode(Node* N);\n\n  /// \\brief The protobuf message type used for serializing Symbol.\n  using MessageType = proto::Symbol;\n\n  /// \\brief Serialize into a protobuf message.\n  ///\n  /// \\param[out] Message   Serialize into this message.\n  ///\n  /// \\return void\n  void toProtobuf(MessageType* Message) const;\n\n  /// \\brief Construct a Symbol from a protobuf message.\n  ///\n  /// \\param C   The Context in which the deserialized Symbol will be held.\n  /// \\param Message  The protobuf message from which to deserialize.\n  ///\n  /// \\return The deserialized Symbol object, or null on failure.\n  static ErrorOr<Symbol*> fromProtobuf(Context& C, const MessageType& Message);\n\n  // Present for testing purposes only.\n  void save(std::ostream& Out) const;\n\n  // Present for testing purposes only.\n  static Symbol* load(Context& C, std::istream& In);\n\n  Module* Parent{nullptr};\n  SymbolObserver* Observer{nullptr};\n  std::variant<std::monostate, Addr, Node*> Payload;\n  std::string Name;\n  bool AtEnd = false;\n\n  friend class Context; // Allow Context to construct Symbols.\n  friend class Module;  // Allow Module to call setModule, Create, etc.\n  // Allows serializaton from Module via containerToProtobuf.\n  template <typename T> friend typename T::MessageType toProtobuf(const T&);\n  friend class SerializationTestHarness; // Testing support.\n};\n\n/// \\class SymbolObserver\n///\n/// \\brief Interface for notifying observers when the Symbol is updated.\n///\n\nclass GTIRB_EXPORT_API SymbolObserver {\npublic:\n  virtual ~SymbolObserver() = default;\n\n  /// \\brief Notify parent when the Symbol's name changes.\n  ///\n  /// Called after the Symbol updates its internal state.\n  ///\n  /// \\param S        the Symbol whose name changed.\n  /// \\param OldName  the Symbol's previous name.\n  /// \\param NewName  the new name of the Symbol.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus nameChange(Symbol* S, const std::string& OldName,\n                                  const std::string& NewName) = 0;\n\n  /// \\brief Notify parent when the Symbol's referent (Node or Addr) changes.\n  ///\n  /// Called after the Symbol updates its internal state.\n  ///\n  /// \\param S            the Symbol whose referent changed.\n  /// \\param OldReferent  the Symbol's previous referent.\n  /// \\param NewReferent  the new value the Symbol refers to.\n  ///\n  /// \\return indication of whether the observer accepts the change.\n  virtual ChangeStatus\n  referentChange(Symbol* S,\n                 std::variant<std::monostate, Addr, Node*> OldReferent,\n                 std::variant<std::monostate, Addr, Node*> NewReferent) = 0;\n};\n\ninline void Symbol::setName(const std::string& N) {\n  if (Observer) {\n    std::string OldName(N);\n    std::swap(Name, OldName);\n    [[maybe_unused]] ChangeStatus Status =\n        Observer->nameChange(this, OldName, Name);\n    assert(Status != ChangeStatus::Rejected &&\n           \"recovering from rejected name change is unsupported\");\n  } else {\n    Name = N;\n  }\n}\n\ninline void Symbol::setAddress(Addr A) {\n  if (Observer) {\n    std::variant<std::monostate, Addr, Node*> OldValue = Payload;\n    Payload = A;\n    [[maybe_unused]] ChangeStatus Status =\n        Observer->referentChange(this, OldValue, Payload);\n    assert(Status != ChangeStatus::Rejected &&\n           \"recovering from rejected address change is unsupported\");\n  } else {\n    Payload = A;\n  }\n}\n\ninline void Symbol::setReferentFromNode(Node* N) {\n  std::variant<std::monostate, Addr, Node*> OldValue = Payload;\n  if (N) {\n    Payload = N;\n  } else {\n    Payload = std::monostate{};\n  }\n  if (Observer) {\n    [[maybe_unused]] ChangeStatus Status =\n        Observer->referentChange(this, OldValue, Payload);\n    assert(Status != ChangeStatus::Rejected &&\n           \"recovering from rejected referent change is unsupported\");\n  }\n}\n\n} // namespace gtirb\n\n#endif // GTIRB_SYMBOL_H\n"
  },
  {
    "path": "include/gtirb/SymbolicExpression.hpp",
    "content": "//===- SymbolicExpression.hpp -----------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_SYMBOLICEXPRESSION_H\n#define GTIRB_SYMBOLICEXPRESSION_H\n\n#include <gtirb/Addr.hpp>\n#include <gtirb/proto/SymbolicExpression.pb.h>\n#include <bitset>\n#include <boost/range/iterator_range.hpp>\n#include <cstdint>\n#include <functional>\n#include <map>\n#include <string>\n#include <variant>\n\n/// \\file SymbolicExpression.hpp\n/// \\ingroup SYMBOLIC_EXPRESSION_GROUP\n/// \\brief Types and operations for symbolic expressions.\n///\n/// \\see \\ref SYMBOLIC_EXPRESSION_GROUP.\nnamespace gtirb {\nclass Symbol; // Forward refernece for Sym, Sym1, Sym2, etc.\n\n/// \\defgroup SYMBOLIC_EXPRESSION_GROUP Symbolic Expressions and Operands\n/// \\brief Represent data values or instruction operands which\n/// should be intepreted as referring to symbols.\n/// @{\n\n/// \\enum SymAttribute\n///\n/// \\brief The space of attributes that can be applied to a symbolic\n/// expression.\n///\n/// See doc/general/SymbolicExpression.md for more details.\nenum class SymAttribute : uint16_t {\n  // Common ELF relocation labels.\n  GOT = proto::SymAttribute::GOT,\n  GOTPC = proto::SymAttribute::GOTPC,\n  GOTOFF = proto::SymAttribute::GOTOFF,\n  GOTREL = proto::SymAttribute::GOTREL,\n  PLT = proto::SymAttribute::PLT,\n  PLTOFF = proto::SymAttribute::PLTOFF,\n  PCREL = proto::SymAttribute::PCREL,\n  SECREL = proto::SymAttribute::SECREL,\n  TLS = proto::SymAttribute::TLS,\n  TLSGD = proto::SymAttribute::TLSGD,\n  TLSLD = proto::SymAttribute::TLSLD,\n  TLSLDM = proto::SymAttribute::TLSLDM,\n  TLSCALL = proto::SymAttribute::TLSCALL,\n  TLSDESC = proto::SymAttribute::TLSDESC,\n  TPREL = proto::SymAttribute::TPREL,\n  TPOFF = proto::SymAttribute::TPOFF,\n  DTPREL = proto::SymAttribute::DTPREL,\n  DTPOFF = proto::SymAttribute::DTPOFF,\n  DTPMOD = proto::SymAttribute::DTPMOD,\n  NTPOFF = proto::SymAttribute::NTPOFF,\n  PAGE = proto::SymAttribute::PAGE,\n  PAGEOFF = proto::SymAttribute::PAGEOFF,\n  CALL = proto::SymAttribute::CALL,\n  LO = proto::SymAttribute::LO,\n  HI = proto::SymAttribute::HI,\n  HIGHER = proto::SymAttribute::HIGHER,\n  HIGHEST = proto::SymAttribute::HIGHEST,\n\n  // X86-specific relocation labels.\n  GOTNTPOFF = proto::SymAttribute::GOTNTPOFF,\n  INDNTPOFF = proto::SymAttribute::INDNTPOFF,\n\n  // ARM-specific relocation labels.\n  G0 = proto::SymAttribute::G0,\n  G1 = proto::SymAttribute::G1,\n  G2 = proto::SymAttribute::G2,\n  G3 = proto::SymAttribute::G3,\n  UPPER16 = proto::SymAttribute::UPPER16,\n  LOWER16 = proto::SymAttribute::LOWER16,\n  LO12 = proto::SymAttribute::LO12,\n  LO15 = proto::SymAttribute::LO15,\n  LO14 = proto::SymAttribute::LO14,\n  HI12 = proto::SymAttribute::HI12,\n  HI21 = proto::SymAttribute::HI21,\n  S = proto::SymAttribute::S,\n  PG = proto::SymAttribute::PG,\n  NC = proto::SymAttribute::NC,\n  ABS = proto::SymAttribute::ABS,\n  PREL = proto::SymAttribute::PREL,\n  PREL31 = proto::SymAttribute::PREL31,\n  TARGET1 = proto::SymAttribute::TARGET1,\n  TARGET2 = proto::SymAttribute::TARGET2,\n  SBREL = proto::SymAttribute::SBREL,\n  TLSLDO = proto::SymAttribute::TLSLDO,\n\n  // MIPS-specific relocation labels.\n  HI16 = proto::SymAttribute::HI16,\n  LO16 = proto::SymAttribute::LO16,\n  GPREL = proto::SymAttribute::GPREL,\n  DISP = proto::SymAttribute::DISP,\n  OFST = proto::SymAttribute::OFST,\n\n  // PPC\n  H = proto::SymAttribute::H,\n  L = proto::SymAttribute::L,\n  HA = proto::SymAttribute::HA,\n  HIGH = proto::SymAttribute::HIGH,\n  HIGHA = proto::SymAttribute::HIGHA,\n  HIGHERA = proto::SymAttribute::HIGHERA,\n  HIGHESTA = proto::SymAttribute::HIGHESTA,\n  TOCBASE = proto::SymAttribute::TOCBASE,\n  TOC = proto::SymAttribute::TOC,\n  NOTOC = proto::SymAttribute::NOTOC,\n};\n\nusing SymAttributeSet = std::set<SymAttribute>;\n\n/// \\brief Represents a\n/// \\ref SYMBOLIC_EXPRESSION_GROUP \"symbolic operand\" of the form\n/// \"Sym + Offset\".\nstruct SymAddrConst {\n  int64_t Offset; ///< Constant offset.\n  Symbol* Sym;    ///< Symbol representing an address.\n  SymAttributeSet Attributes = SymAttributeSet();\n\n  friend bool operator==(const SymAddrConst& LHS, const SymAddrConst& RHS) {\n    return LHS.Offset == RHS.Offset && LHS.Sym == RHS.Sym &&\n           LHS.Attributes == RHS.Attributes;\n  }\n\n  friend bool operator!=(const SymAddrConst& LHS, const SymAddrConst& RHS) {\n    return !operator==(LHS, RHS);\n  }\n};\n\n/// \\brief Represents a\n/// \\ref SYMBOLIC_EXPRESSION_GROUP \"symbolic operand\" of the form\n/// \"(Sym1 - Sym2) / Scale + Offset\"\nstruct SymAddrAddr {\n  int64_t Scale;  ///< Constant scale factor.\n  int64_t Offset; ///< Constant offset.\n  Symbol* Sym1;   ///< Symbol representing the base address.\n  Symbol* Sym2;   ///< Symbol to subtract from \\p Sym1.\n  SymAttributeSet Attributes = SymAttributeSet();\n\n  friend bool operator==(const SymAddrAddr& LHS, const SymAddrAddr& RHS) {\n    return LHS.Scale == RHS.Scale && LHS.Offset == RHS.Offset &&\n           LHS.Sym1 == RHS.Sym1 && LHS.Sym2 == RHS.Sym2 &&\n           LHS.Attributes == RHS.Attributes;\n  }\n\n  friend bool operator!=(const SymAddrAddr& LHS, const SymAddrAddr& RHS) {\n    return !operator==(LHS, RHS);\n  }\n};\n\n/// \\brief A \\ref SYMBOLIC_EXPRESSION_GROUP \"symbolic expression\".\nusing SymbolicExpression = std::variant<SymAddrConst, SymAddrAddr>;\n\n/// @}\n// (end \\defgroup SYMBOLIC_EXPRESSION_GROUP)\n\n} // namespace gtirb\n\nnamespace std {\ntemplate <> struct hash<gtirb::SymAddrConst> {\n  typedef gtirb::SymAddrConst argument_type;\n  typedef std::size_t result_type;\n\n  result_type operator()(const argument_type& Obj) const noexcept {\n    const result_type Off = std::hash<int64_t>{}(Obj.Offset);\n    const result_type P = std::hash<gtirb::Symbol*>{}(Obj.Sym);\n    return Off ^ (P << 1);\n  }\n};\n\ntemplate <> struct hash<gtirb::SymAddrAddr> {\n  typedef gtirb::SymAddrAddr argument_type;\n  typedef std::size_t result_type;\n\n  result_type operator()(const argument_type& Obj) const noexcept {\n    result_type S = std::hash<int64_t>{}(Obj.Scale);\n    comb(S, std::hash<int64_t>{}(Obj.Offset));\n    comb(S, std::hash<gtirb::Symbol*>{}(Obj.Sym1));\n    comb(S, std::hash<gtirb::Symbol*>{}(Obj.Sym2));\n    return S;\n  }\n\nprivate:\n  void comb(result_type& One, result_type Two) const noexcept {\n    One ^= Two + 0x9e3779b9 + (One << 6) + (One >> 2);\n  }\n};\n} // namespace std\n\n#endif // GTIRB_SYMBOLICEXPRESSION_H\n"
  },
  {
    "path": "include/gtirb/Utility.hpp",
    "content": "//===- Utility.hpp ----------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2021 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_UTILITY_H\n#define GTIRB_UTILITY_H\n\n#include <gtirb/Addr.hpp>\n#include <gtirb/Export.hpp>\n#include <gtirb/Node.hpp>\n#include <algorithm>\n#include <boost/iterator/iterator_categories.hpp>\n#include <boost/iterator/iterator_facade.hpp>\n#include <boost/iterator/iterator_traits.hpp>\n#include <boost/iterator/transform_iterator.hpp>\n#include <boost/range/iterator_range.hpp>\n#include <functional>\n#include <iterator>\n#include <optional>\n#include <type_traits>\n#include <vector>\n\nnamespace gtirb {\n\n/// @cond INTERNAL\n\n/// \\class MergeSortedIterator\n///\n/// \\brief This iterator merges a set of sorted iterators together, producing\n/// a single sorted output iterator.\n///\n/// This iterator is a forward iterator, irrespective of the class of the base\n/// iterator. Iterating over a sequence of N total elements from a combined M\n/// base iterators requires O(N log M) comparisons. Constructing a iterator\n/// with M base iterators requires O(M) comparisons.\n///\n/// \\tparam ForwardIterator The type of forward iterator to be merged. Results\n///                         from these iterators must be in sorted order.\n/// \\tparam Compare         A comparison function object to use to sort results.\n///                         Defaults to std::less.\ntemplate <typename ForwardIterator,\n          typename Compare = std::less<\n              typename std::iterator_traits<ForwardIterator>::value_type>>\nclass MergeSortedIterator\n    : public boost::iterator_facade<\n          MergeSortedIterator<ForwardIterator, Compare>,\n          typename std::iterator_traits<ForwardIterator>::value_type,\n          boost::forward_traversal_tag,\n          typename std::iterator_traits<ForwardIterator>::reference,\n          typename std::iterator_traits<ForwardIterator>::difference_type> {\npublic:\n  /// \\brief Create a MergeSortedIterator representing the end of iteration.\n  ///\n  /// Dereferencing or incrementing this iterator results in undefined behavior.\n  MergeSortedIterator() = default;\n\n  /// \\brief Converting constructor from a MergeSortedIterator with a compatible\n  /// base iterator type.\n  ///\n  /// This allows converting a non-const iterator to a const iterator, for\n  /// example, as long as the base iterators are convertible. The comparison\n  /// types must match exactly.\n  ///\n  /// \\tparam OtherForwardIterator  base iterator type of the\n  /// MergeSortedIterator to convert.\n  ///\n  /// \\param MSI  MergeSortedIterator to convert.\n  template <typename OtherForwardIterator>\n  MergeSortedIterator(\n      const MergeSortedIterator<OtherForwardIterator, Compare>& MSI,\n      std::enable_if_t<\n          std::is_convertible_v<OtherForwardIterator, ForwardIterator>, void*> =\n          0)\n      : Ranges(MSI.Ranges.begin(), MSI.Ranges.end()) {}\n\n  /// \\brief Create a MergeSortedIterator from a range of ranges.\n  ///\n  /// \\tparam RangeIteratorRange Any class fulfilling the Boost concept\n  /// SinglePassRange<SinglePassIterator<SinglePassRange<ForwardIterator>>>.\n  ///\n  /// \\param RangeRange A \\p RangeIteratorRange to build this iterator from.\n  template <typename RangeIteratorRange>\n  explicit MergeSortedIterator(RangeIteratorRange RangeRange) {\n    for (const auto& Range : RangeRange) {\n      if (auto RBegin = Range.begin(), REnd = Range.end(); RBegin != REnd) {\n        Ranges.emplace_back(RBegin, REnd);\n      }\n    }\n    // Establish the heap invariant for Ranges.\n    std::make_heap(Ranges.begin(), Ranges.end(), rangeGreaterThan);\n  }\n\n  /// \\brief Create a MergeSortedIterator from an iterator of ranges.\n  ///\n  /// \\tparam RangeIterator Any class fulfilling the Boost concept\n  /// SinglePassIterator<SinglePassRange<ForwardIterator>>.\n  ///\n  /// \\param Begin The beginning of the ranges to build this iterator from.\n  /// \\param End   The end of the ranges to build this iterator from.\n  template <typename RangeIterator>\n  MergeSortedIterator(RangeIterator Begin, RangeIterator End)\n      : MergeSortedIterator(boost::make_iterator_range(Begin, End)) {}\n\n  // Beginning of functions for iterator facade compatibility.\n  typename std::iterator_traits<ForwardIterator>::reference\n  dereference() const {\n    assert(!Ranges.empty() && \"Attempt to dereference end of iterator!\");\n    return *Ranges.front().first;\n  }\n\n  bool equal(const MergeSortedIterator<ForwardIterator, Compare>& Other) const {\n    return Ranges == Other.Ranges;\n  }\n\n  void increment() {\n    assert(!Ranges.empty() && \"Attempt to increment end of iterator!\");\n    // After incrementing the first range, it may no longer have the lowest\n    // first element. Removing the range, then re-inserting it ensures that the\n    // heap invariant is maintained.\n    std::pop_heap(Ranges.begin(), Ranges.end(), rangeGreaterThan);\n    ++Ranges.back().first;\n    if (Ranges.back().first == Ranges.back().second) {\n      Ranges.pop_back();\n    } else {\n      std::push_heap(Ranges.begin(), Ranges.end(), rangeGreaterThan);\n    }\n  }\n  // End of functions for iterator facade compatibility.\nprivate:\n  template <typename OtherForwardIterator, typename OtherCompare>\n  friend class MergeSortedIterator;\n\n  using RangeType = std::pair<ForwardIterator, ForwardIterator>;\n\n  // Compares two ranges according to the relationship of their first elements\n  // given by \\c Compare. Empty ranges are treated as being greater than any\n  // non-empty range.\n  static bool rangeGreaterThan(const RangeType& R1, const RangeType& R2) {\n    if (R1.first == R1.second)\n      // An empty R1 is greater than every R2.\n      return true;\n    if (R2.first == R2.second)\n      // Any R1 is less than an empty R2.\n      return false;\n    // Flip the comparison to implement \"greater-than\".\n    return Compare()(*R2.first, *R1.first);\n  }\n\n  // Ranges is a heap ordered by \\c rangeGreaterThan. This ensures that the\n  // range with the lowest first element (according to \\c Compare) is always at\n  // the front.\n  std::vector<RangeType> Ranges;\n};\n\n/// \\class AddressLess\n///\n/// \\brief A comparison function object for comparing nodes in address order.\n///\n/// If both nodes have the same address, their sizes are compared. If both\n/// nodes have the same addresses and sizes, their UUIDs are compared.\nstruct GTIRB_EXPORT_API AddressLess {\n  template <typename NodeType> auto key(const NodeType* N) const {\n    return std::make_tuple(N->getAddress(), N->getSize(), N->getUUID());\n  }\n\n  template <typename NodeType>\n  bool operator()(const NodeType* N1, const NodeType* N2) const {\n    return key(N1) < key(N2);\n  }\n\n  template <typename NodeType,\n            typename = std::enable_if_t<!std::is_pointer_v<NodeType>>>\n  bool operator()(const NodeType& N1, const NodeType& N2) const {\n    return operator()(&N1, &N2);\n  }\n\n  /// \\brief Compare a node's address to a query address.\n  template <typename NodeType>\n  bool operator()(const NodeType* N1, const Addr& A2) const {\n    return N1->getAddress() < A2;\n  }\n\n  /// \\brief Compare a node's address to a query address.\n  template <typename NodeType>\n  bool operator()(const Addr& A1, const NodeType* N2) const {\n    return A1 < N2->getAddress();\n  }\n};\n\n/// \\brief Compare CodeBlocks by address, size, decode mode, and UUID.\ntemplate <>\nGTIRB_EXPORT_API bool\nAddressLess::operator()<CodeBlock>(const CodeBlock* B1,\n                                   const CodeBlock* B2) const;\n\n/// \\brief Compare DataBlocks by address, size, and UUID.\n///\n/// Although this mimics the default comparison order, this specialization is\n/// necessary for compatibility with the CodeBlock order so that CodeBlocks\n/// and DataBlocks can be handled uniformly by block_iterator and friends.\ntemplate <>\nGTIRB_EXPORT_API bool\nAddressLess::operator()<DataBlock>(const DataBlock* B1,\n                                   const DataBlock* B2) const;\n\n/// \\class BlockAddressLess\n///\n/// \\brief A comparison function object for comparing blocks (that is, \\ref Node\n/// objects that are either \\ref CodeBlock or \\ref DataBlock objects) in\n/// address order.\nstruct GTIRB_EXPORT_API BlockAddressLess {\n  bool operator()(const Node* N1, const Node* N2) const;\n  bool operator()(const Node& N1, const Node& N2) const {\n    return operator()(&N1, &N2);\n  }\n};\n\n/// \\class BlockOffsetPairLess\n///\n/// \\brief A comparison function object for comparing blocks in a ByteInterval\n/// in offset order.\nstruct GTIRB_EXPORT_API BlockOffsetPairLess {\n  bool operator()(std::pair<uint64_t, const Node*> B1,\n                  std::pair<uint64_t, const Node*> B2) const;\n};\n\n/// \\class ArbitraryLess\n///\n/// \\brief A comparison function object for comparing objects in a manner with\n/// no ordering guarantees.\n///\n/// \\tparam T Any type.\ntemplate <typename T> struct ArbitraryLess {\n  bool operator()(const T& N1, const T& N2) const { return &N1 < &N2; }\n};\n\n/// \\class NodeToChildRange\n///\n/// \\brief A function object for constructing \\ref MergeSortedIterator objects\n/// via Boost transform iterators.\n///\n/// \\tparam T The type to retrieve a range of children nodes from.\n/// \\tparam Method A pointer-to-method type, taking no arguments and retuning\n///                a child node iterator.\n/// \\tparam Begin  A pointer-to-method of the beginning of the child node range.\n/// \\tparam End    A pointer-to-method of the end of the child node range.\ntemplate <typename T, typename Method, Method Begin, Method End>\nstruct NodeToChildRange {\n  boost::iterator_range<decltype((std::declval<T>().*Begin)())>\n  operator()(T& N) const {\n    return boost::make_iterator_range((N.*Begin)(), (N.*End)());\n  }\n};\n\n/// \\class NodeToBlockRange\n///\n/// \\brief A function object for constructing \\ref MergeSortedIterator objects\n/// via Boost transform iterators. Returns ranges of \\ref Node objects, which\n/// are either \\ref CodeBlock objects or \\ref DataBlock objects.\n///\n/// \\tparam T The type to retrieve ranges of blocks from. If const-qualified,\n///           the const iterators on this type are used; else the non-const\n///           iterators are used.\ntemplate <typename T>\nusing NodeToBlockRange = NodeToChildRange<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_block_iterator (T::*)() const,\n                       typename T::block_iterator (T::*)()>,\n    &T::blocks_begin, &T::blocks_end>;\n\n/// \\class NodeToCodeBlockRange\n///\n/// \\brief A function object for constructing \\ref MergeSortedIterator objects\n/// via Boost transform iterators. Returns ranges of \\ref CodeBlock objects.\n///\n/// \\tparam T The type to retrieve ranges of blocks from. If const-qualified,\n///           the const iterators on this type are used; else the non-const\n///           iterators are used.\ntemplate <typename T>\nusing NodeToCodeBlockRange = NodeToChildRange<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_code_block_iterator (T::*)() const,\n                       typename T::code_block_iterator (T::*)()>,\n    &T::code_blocks_begin, &T::code_blocks_end>;\n\n/// \\class NodeToDataBlockRange\n///\n/// \\brief A function object for constructing \\ref MergeSortedIterator objects\n/// via Boost transform iterators. Returns ranges of \\ref DataBlock objects.\n///\n/// \\tparam T The type to retrieve ranges of blocks from. If const-qualified,\n///           the const iterators on this type are used; else the non-const\n///           iterators are used.\ntemplate <typename T>\nusing NodeToDataBlockRange = NodeToChildRange<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_data_block_iterator (T::*)() const,\n                       typename T::data_block_iterator (T::*)()>,\n    &T::data_blocks_begin, &T::data_blocks_end>;\n\n/// \\class NodeToSymbolicExpressionRange\n///\n/// \\brief A function object for constructing \\ref MergeSortedIterator objects\n/// via Boost transform iterators. Returns ranges of \\ref\n/// ByteInterval::SymbolicExpressionElement or \\ref\n/// ByteInterval::ConstSymbolicExpressionElement objects.\n///\n/// \\tparam T The type to retrieve ranges of symbolic expressions from. If\n///           const-qualified, the const iterators on this type are used; else\n///           the non-const iterators are used.\ntemplate <typename T>\nusing NodeToSymbolicExpressionRange = NodeToChildRange<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_symbolic_expression_iterator (T::*)()\n                           const,\n                       typename T::symbolic_expression_iterator (T::*)()>,\n    &T::symbolic_expressions_begin, &T::symbolic_expressions_end>;\n\n/// \\class NodeToByteIntervalRange\n///\n/// \\brief A function object for constructing \\ref MergeSortedIterator objects\n/// via Boost transform iterators. Returns ranges of \\ref ByteInterval objects.\n///\n/// \\tparam T The type to retrieve ranges of intervals from. If const-qualified,\n///           the const iterators on this type are used; else the non-const\n///           iterators are used.\ntemplate <typename T>\nusing NodeToByteIntervalRange = NodeToChildRange<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_byte_interval_iterator (T::*)() const,\n                       typename T::byte_interval_iterator (T::*)()>,\n    &T::byte_intervals_begin, &T::byte_intervals_end>;\n\n/// \\class NodeToSymbolRange\n///\n/// \\brief A function object for constructing \\ref MergeSortedIterator objects\n/// via Boost transform iterators. Returns ranges of \\ref Symbol objects.\n///\n/// \\tparam T The type to retrieve ranges of symbols from. If const-qualified,\n///           the const iterators on this type are used; else the non-const\n///           iterators are used.\ntemplate <typename T>\nusing NodeToSymbolRange = NodeToChildRange<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_symbol_iterator (T::*)() const,\n                       typename T::symbol_iterator (T::*)()>,\n    &T::symbols_begin, &T::symbols_end>;\n\n/// \\class NodeToSectionRange\n///\n/// \\brief A function object for constructing \\ref MergeSortedIterator objects\n/// via Boost transform iterators. Returns ranges of \\ref Section objects.\n///\n/// \\tparam T The type to retrieve ranges of sections from. If const-qualified,\n///           the const iterators on this type are used; else the non-const\n///           iterators are used.\ntemplate <typename T>\nusing NodeToSectionRange = NodeToChildRange<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_section_iterator (T::*)() const,\n                       typename T::section_iterator (T::*)()>,\n    &T::sections_begin, &T::sections_end>;\n\n/// \\class NodeToProxyBlockRange\n///\n/// \\brief A function object for constructing \\ref MergeSortedIterator objects\n/// via Boost transform iterators. Returns ranges of \\ref ProxyBlock objects.\n///\n/// \\tparam T The type to retrieve ranges of blocks from. If const-qualified,\n///           the const iterators on this type are used; else the non-const\n///           iterators are used.\ntemplate <typename T>\nusing NodeToProxyBlockRange = NodeToChildRange<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_proxy_block_iterator (T::*)() const,\n                       typename T::proxy_block_iterator (T::*)()>,\n    &T::proxy_blocks_begin, &T::proxy_blocks_end>;\n\n/// \\class FindNodesAt\n///\n/// \\brief A function object for merging together calls to \"findNodeAt\" style\n/// methods, taking one address parameter.\n///\n/// \\tparam T The type of node to call \\p FindAtMethod on.\n/// \\tparam MethodType The type of \\p Method.\n/// \\tparam Method A pointer to a method on \\p T that takes an\n/// address and returns a range.\ntemplate <typename T, typename MethodType, MethodType Method>\nstruct FindNodesAt {\n  Addr A;\n\n  FindNodesAt(Addr A_) : A{A_} {}\n\n  decltype((std::declval<T>().*Method)(Addr())) operator()(T& N) const {\n    return (N.*Method)(A);\n  }\n};\n\n/// \\class FindNodes\n///\n/// \\brief A function object for merging together calls to \"findNode\" style\n/// methods, taking one string parameter.\n///\n/// \\tparam T The type of node to call \\p FindMethod on.\n/// \\tparam MethodType The type of \\p Method.\n/// \\tparam Method A pointer to a method on \\p T that takes a\n/// string and returns a range.\ntemplate <typename T, typename MethodType, MethodType Method> struct FindNodes {\n  std::string X;\n\n  FindNodes(std::string X_) : X{X_} {}\n\n  decltype((std::declval<T>().*Method)(std::string())) operator()(T& N) const {\n    return (N.*Method)((std::string&)X);\n  }\n};\n\n/// \\class FindNodesBetween\n///\n/// \\brief A function object for merging together calls to \"findNodeAt\" style\n/// methods, taking two address parameters.\n///\n/// \\tparam T The type of node to call \\p FindAtMethod on.\n/// \\tparam MethodType The type of \\p Method.\n/// \\tparam Method A pointer to a method on \\p T that takes two\n/// addresses and returns a range.\ntemplate <typename T, typename MethodType, MethodType Method>\nstruct FindNodesBetween {\n  Addr Low, High;\n\n  FindNodesBetween(Addr Low_, Addr High_) : Low{Low_}, High{High_} {}\n\n  decltype((std::declval<T>().*Method)(Addr(), Addr())) operator()(T& N) const {\n    return (N.*Method)(Low, High);\n  }\n};\n\n/// \\class FindBlocksIn\n///\n/// \\brief A function object for merging together calls to findBlocksOn.\n///\n/// \\tparam T The node to call findBlocksOn from. If const-qualified,\n///           the const functions on this type are used; else the non-const\n///           functions are used.\ntemplate <typename T>\nusing FindBlocksIn = FindNodesAt<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_block_subrange (T::*)(Addr) const,\n                       typename T::block_subrange (T::*)(Addr)>,\n    &T::findBlocksOn>;\n\n/// \\class FindBlocksAt\n///\n/// \\brief A function object for merging together calls to findBlocksAt, taking\n/// one address parameter.\n///\n/// \\tparam T The node to call findBlocksAt from. If const-qualified,\n///           the const functions on this type are used; else the non-const\n///           functions are used.\ntemplate <typename T>\nusing FindBlocksAt = FindNodesAt<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_block_range (T::*)(Addr) const,\n                       typename T::block_range (T::*)(Addr)>,\n    &T::findBlocksAt>;\n\n/// \\class FindBlocksBetween\n///\n/// \\brief A function object for merging together calls to findBlocksAt, taking\n/// two address parameters.\n///\n/// \\tparam T The node to call findBlocksAt from. If const-qualified,\n///           the const functions on this type are used; else the non-const\n///           functions are used.\ntemplate <typename T>\nusing FindBlocksBetween = FindNodesBetween<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_block_range (T::*)(Addr, Addr) const,\n                       typename T::block_range (T::*)(Addr, Addr)>,\n    &T::findBlocksAt>;\n\n/// \\class FindCodeBlocksIn\n///\n/// \\brief A function object for merging together calls to findCodeBlocksOn.\n///\n/// \\tparam T The node to call findCodeBlocksOn from. If const-qualified,\n///           the const functions on this type are used; else the non-const\n///           functions are used.\ntemplate <typename T>\nusing FindCodeBlocksIn = FindNodesAt<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_code_block_subrange (T::*)(Addr) const,\n                       typename T::code_block_subrange (T::*)(Addr)>,\n    &T::findCodeBlocksOn>;\n\n/// \\class FindCodeBlocksAt\n///\n/// \\brief A function object for merging together calls to findCodeBlocksAt,\n/// taking one address parameter.\n///\n/// \\tparam T The node to call findCodeBlocksAt from. If const-qualified,\n///           the const functions on this type are used; else the non-const\n///           functions are used.\ntemplate <typename T>\nusing FindCodeBlocksAt = FindNodesAt<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_code_block_range (T::*)(Addr) const,\n                       typename T::code_block_range (T::*)(Addr)>,\n    &T::findCodeBlocksAt>;\n\n/// \\class FindCodeBlocksBetween\n///\n/// \\brief A function object for merging together calls to findCodeBlocksAt,\n/// taking two address parameters.\n///\n/// \\tparam T The node to call findCodeBlocksAt from. If const-qualified,\n///           the const functions on this type are used; else the non-const\n///           functions are used.\ntemplate <typename T>\nusing FindCodeBlocksBetween = FindNodesBetween<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_code_block_range (T::*)(Addr, Addr)\n                           const,\n                       typename T::code_block_range (T::*)(Addr, Addr)>,\n    &T::findCodeBlocksAt>;\n\n/// \\class FindDataBlocksIn\n///\n/// \\brief A function object for merging together calls to findDataBlocksOn.\n///\n/// \\tparam T The node to call findDataBlocksOn from. If const-qualified,\n///           the const functions on this type are used; else the non-const\n///           functions are used.\ntemplate <typename T>\nusing FindDataBlocksIn = FindNodesAt<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_data_block_subrange (T::*)(Addr) const,\n                       typename T::data_block_subrange (T::*)(Addr)>,\n    &T::findDataBlocksOn>;\n\n/// \\class FindDataBlocksAt\n///\n/// \\brief A function object for merging together calls to findDataBlocksAt,\n/// taking one address parameter.\n///\n/// \\tparam T The node to call findDataBlocksAt from. If const-qualified,\n///           the const functions on this type are used; else the non-const\n///           functions are used.\ntemplate <typename T>\nusing FindDataBlocksAt = FindNodesAt<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_data_block_range (T::*)(Addr) const,\n                       typename T::data_block_range (T::*)(Addr)>,\n    &T::findDataBlocksAt>;\n\n/// \\class FindDataBlocksBetween\n///\n/// \\brief A function object for merging together calls to findDataBlocksAt,\n/// taking two address parameters.\n///\n/// \\tparam T The node to call findDataBlocksAt from. If const-qualified,\n///           the const functions on this type are used; else the non-const\n///           functions are used.\ntemplate <typename T>\nusing FindDataBlocksBetween = FindNodesBetween<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_data_block_range (T::*)(Addr, Addr)\n                           const,\n                       typename T::data_block_range (T::*)(Addr, Addr)>,\n    &T::findDataBlocksAt>;\n\n/// \\class FindSymExprsAt\n///\n/// \\brief A function object for merging together calls to\n/// findSymbolicExpressionsAt, taking one address parameter.\n///\n/// \\tparam T The node to call findSymbolicExpressionsAt from. If\n/// const-qualified, the const functions on this type are used; else the\n/// non-const functions are used.\ntemplate <typename T>\nusing FindSymExprsAt = FindNodesAt<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_symbolic_expression_range (T::*)(Addr)\n                           const,\n                       typename T::symbolic_expression_range (T::*)(Addr)>,\n    &T::findSymbolicExpressionsAt>;\n\n/// \\class FindSymExprsBetween\n///\n/// \\brief A function object for merging together calls to\n/// findSymbolicExpressionsAt, taking two address parameters.\n///\n/// \\tparam T The node to call findSymbolicExpressionsAt from. If\n/// const-qualified, the const functions on this type are used; else the\n/// non-const functions are used.\ntemplate <typename T>\nusing FindSymExprsBetween = FindNodesBetween<\n    T,\n    std::conditional_t<\n        std::is_const_v<T>,\n        typename T::const_symbolic_expression_range (T::*)(Addr, Addr) const,\n        typename T::symbolic_expression_range (T::*)(Addr, Addr)>,\n    &T::findSymbolicExpressionsAt>;\n\n/// \\class FindByteIntervalsIn\n///\n/// \\brief A function object for merging together calls to findByteIntervalsOn.\n///\n/// \\tparam T The node to call findByteIntervalsOn from. If const-qualified,\n///           the const functions on this type are used; else the non-const\n///           functions are used.\ntemplate <typename T>\nusing FindByteIntervalsIn =\n    FindNodesAt<T,\n                std::conditional_t<\n                    std::is_const_v<T>,\n                    typename T::const_byte_interval_subrange (T::*)(Addr) const,\n                    typename T::byte_interval_subrange (T::*)(Addr)>,\n                &T::findByteIntervalsOn>;\n\n/// \\class FindByteIntervalsAt\n///\n/// \\brief A function object for merging together calls to\n/// findByteIntervalsAt, taking one address parameter.\n///\n/// \\tparam T The node to call findByteIntervalsAt from. If\n/// const-qualified, the const functions on this type are used; else the\n/// non-const functions are used.\ntemplate <typename T>\nusing FindByteIntervalsAt = FindNodesAt<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_byte_interval_range (T::*)(Addr) const,\n                       typename T::byte_interval_range (T::*)(Addr)>,\n    &T::findByteIntervalsAt>;\n\n/// \\class FindByteIntervalsBetween\n///\n/// \\brief A function object for merging together calls to\n/// findByteIntervalsAt, taking two address parameters.\n///\n/// \\tparam T The node to call findByteIntervalsAt from. If\n/// const-qualified, the const functions on this type are used; else the\n/// non-const functions are used.\ntemplate <typename T>\nusing FindByteIntervalsBetween = FindNodesBetween<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_byte_interval_range (T::*)(Addr, Addr)\n                           const,\n                       typename T::byte_interval_range (T::*)(Addr, Addr)>,\n    &T::findByteIntervalsAt>;\n\n/// \\class FindSectionsIn\n///\n/// \\brief A function object for merging together calls to findSectionsOn.\n///\n/// \\tparam T The node to call findSectionsOn from. If const-qualified,\n///           the const functions on this type are used; else the non-const\n///           functions are used.\ntemplate <typename T>\nusing FindSectionsIn = FindNodesAt<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_section_subrange (T::*)(Addr) const,\n                       typename T::section_subrange (T::*)(Addr)>,\n    &T::findSectionsOn>;\n\n/// \\class FindSectionsAt\n///\n/// \\brief A function object for merging together calls to\n/// findSectionsAt, taking one address parameter.\n///\n/// \\tparam T The node to call findSectionsAt from. If\n/// const-qualified, the const functions on this type are used; else the\n/// non-const functions are used.\ntemplate <typename T>\nusing FindSectionsAt = FindNodesAt<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_section_range (T::*)(Addr) const,\n                       typename T::section_range (T::*)(Addr)>,\n    &T::findSectionsAt>;\n\n/// \\class FindSections\n///\n/// \\brief A function object for merging together calls to\n/// findSections, taking one string parameter.\n///\n/// \\tparam T The node to call findSections from. If\n/// const-qualified, the const functions on this type are used; else the\n/// non-const functions are used.\ntemplate <typename T>\nusing FindSections = FindNodes<\n    T,\n    std::conditional_t<\n        std::is_const_v<T>,\n        typename T::const_section_name_range (T::*)(const std::string& X) const,\n        typename T::section_name_range (T::*)(const std::string& X)>,\n    &T::findSections>;\n\n/// \\class FindSectionsBetween\n///\n/// \\brief A function object for merging together calls to\n/// findSectionsAt, taking two address parameters.\n///\n/// \\tparam T The node to call findSectionsAt from. If\n/// const-qualified, the const functions on this type are used; else the\n/// non-const functions are used.\ntemplate <typename T>\nusing FindSectionsBetween = FindNodesBetween<\n    T,\n    std::conditional_t<std::is_const_v<T>,\n                       typename T::const_section_range (T::*)(Addr, Addr) const,\n                       typename T::section_range (T::*)(Addr, Addr)>,\n    &T::findSectionsAt>;\n\n/// @endcond\n\n} // namespace gtirb\n\n#endif // GTIRB_UTILITY_H\n"
  },
  {
    "path": "include/gtirb/gtirb.hpp",
    "content": "//===- gtirb.hpp ------------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_GTIRB_H\n#define GTIRB_GTIRB_H\n\n/// \\file gtirb.hpp\n/// \\brief \\c \\#include this file to include all GTIRB API headers.\n\n/// \\namespace gtirb\n/// \\brief Main namespace for the GTIRB API.\n\n#include <gtirb/Addr.hpp>\n#include <gtirb/AuxData.hpp>\n#include <gtirb/AuxDataSchema.hpp>\n#include <gtirb/ByteInterval.hpp>\n#include <gtirb/CFG.hpp>\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/DataBlock.hpp>\n#include <gtirb/Export.hpp>\n#include <gtirb/IR.hpp>\n#include <gtirb/Module.hpp>\n#include <gtirb/Node.hpp>\n#include <gtirb/Section.hpp>\n#include <gtirb/Symbol.hpp>\n#include <gtirb/SymbolicExpression.hpp>\n\n#include <gtirb/version.h>\n\n#endif // GTIRB_GTIRB_H\n"
  },
  {
    "path": "include/gtirb/version.h.in",
    "content": "//===- version.h -------------------------------------------------*- C++-*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n\n#ifndef GTIRB_VERSION_H\n#define GTIRB_VERSION_H\n\n/**@def GTIRB_MAJOR_VERSION\n   Major Version\n*/\n#define GTIRB_MAJOR_VERSION @PROJECT_VERSION_MAJOR@\n\n/**@def GTIRB_MINOR_VERSION\n   Minor Version\n*/\n#define GTIRB_MINOR_VERSION @PROJECT_VERSION_MINOR@\n\n/**@def GTIRB_PATCH_VERSION\n   Patch Version\n*/\n#define GTIRB_PATCH_VERSION @PROJECT_VERSION_PATCH@\n\n/// \\file version.h\n/// \\brief Holds the version macros. Read from version.txt\n\n/**@def GTIRB_VERSION_STRING\n   Full version\n*/\n#define GTIRB_VERSION_STRING                                                   \\\n  \"@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@\"\n\n/**@def GTIRB_PROTOBUF_VERSION\n * The version of the Protobuf files produced by this API.\n*/\n#define GTIRB_PROTOBUF_VERSION @GTIRB_PROTOBUF_VERSION@\n\n#endif\n"
  },
  {
    "path": "java/.gitignore",
    "content": ".idea\n.gradle\ngradle\ngradlew\ngradlew.bat\n"
  },
  {
    "path": "java/CMakeLists.txt",
    "content": "#\n# Cmake configuration for java build\n#\n\n# ---------------------------------------------------------------------------\n# Get upper bound of compatible versions\n# ---------------------------------------------------------------------------\n\nif(\"${Protobuf_VERSION}\" VERSION_LESS 3.21.7)\n  # Before 3.21.7, generated code is incompatible with the 4.* API.\n  set(GTIRB_PROTOBUF_UPPER_BOUND \"4.0.0-rc-1\")\nelse()\n  # Upper bound for 3.21.7 and above is not yet known.\n  set(GTIRB_PROTOBUF_UPPER_BOUND \"\")\nendif()\n\n# ---------------------------------------------------------------------------\n# Building the gtirb protobuf files into java\n# ---------------------------------------------------------------------------\nset(GTIRB_JAVA_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/src)\n\n# Directory containing the *.class files generated from the *.proto files\nset(GTIRB_PROTO_CLASS_DIR \"${GTIRB_JAVA_SOURCE_DIR}/com/grammatech/gtirb/proto\")\n\n# Add commands to compile the *.proto files to *.class files\nforeach(GTIRB_PROTO_FILE ${GTIRB_PROTO_FILES})\n  get_filename_component(GTIRB_PROTO_BASENAME ${GTIRB_PROTO_FILE} NAME_WE)\n  set(GTIRB_PROTO_CLASS_FILE\n      ${GTIRB_PROTO_CLASS_DIR}/${GTIRB_PROTO_BASENAME}OuterClass.java\n  )\n  add_custom_command(\n    OUTPUT ${GTIRB_PROTO_CLASS_FILE}\n    COMMAND ${Protobuf_PROTOC_EXECUTABLE} --java_out=${GTIRB_JAVA_SOURCE_DIR}\n            --proto_path=${GTIRB_PROTO_DIR} ${GTIRB_PROTO_FILE}\n  )\n  list(APPEND GTIRB_PROTOBUF_JAVA ${GTIRB_PROTO_CLASS_FILE})\nendforeach()\n\n# ---------------------------------------------------------------------------\n# Building the gtirb java API\n# ---------------------------------------------------------------------------\nif(GTIRB_RELEASE_VERSION)\n  set(GTIRB_JAVA_SNAPSHOT_SUFFIX \"\")\nelse()\n  set(GTIRB_JAVA_SNAPSHOT_SUFFIX \"-SNAPSHOT\")\nendif()\n\nconfigure_file(\n  ${CMAKE_CURRENT_SOURCE_DIR}/pom.xml.in ${CMAKE_CURRENT_BINARY_DIR}/pom.xml\n  @ONLY\n)\n\nset(GTIRB_API_JAVAS\n    auxdatacodec/BoolCodec\n    auxdatacodec/ByteCodec\n    auxdatacodec/Codec\n    auxdatacodec/FloatCodec\n    auxdatacodec/IntegerCodec\n    auxdatacodec/ListCodec\n    auxdatacodec/LongCodec\n    auxdatacodec/MapCodec\n    auxdatacodec/OffsetCodec\n    auxdatacodec/SetCodec\n    auxdatacodec/ShortCodec\n    auxdatacodec/StringCodec\n    auxdatacodec/Tuple1Codec\n    auxdatacodec/Tuple2Codec\n    auxdatacodec/Tuple3Codec\n    auxdatacodec/Tuple4Codec\n    auxdatacodec/Tuple5Codec\n    auxdatacodec/UuidCodec\n    auxdatacodec/Variant2Codec\n    auxdatacodec/Variant3Codec\n    auxdatacodec/Variant11Codec\n    tuple/Tuple1\n    tuple/Tuple2\n    tuple/Tuple3\n    tuple/Tuple4\n    tuple/Tuple5\n    variant/Token\n    variant/Variant2\n    variant/Variant3\n    variant/Variant11\n    AuxDataContainer\n    AuxDataSchema\n    AuxDataSchemas\n    ByteBlock\n    ByteInterval\n    CFG\n    CfiDirective\n    CodeBlock\n    DataBlock\n    Edge\n    SectionPropertyTuple\n    ElfSymbolInfoTuple\n    ElfSymbolVersionsTable\n    IR\n    Module\n    Node\n    Offset\n    PeExportEntry\n    PeImportEntry\n    PeResourceEntry\n    ProbFuncName\n    ProxyBlock\n    Section\n    SymAddrAddr\n    SymAddrConst\n    SymbolicExpression\n    Symbol\n    TreeListItem\n    TreeListUtils\n    TypeTableEntry\n    Util\n)\n\nforeach(GTIRB_API_JAVA ${GTIRB_API_JAVAS})\n  configure_file(\n    ${CMAKE_CURRENT_SOURCE_DIR}/com/grammatech/gtirb/${GTIRB_API_JAVA}.java\n    ${GTIRB_JAVA_SOURCE_DIR}/com/grammatech/gtirb/${GTIRB_API_JAVA}.java\n    COPYONLY\n  )\nendforeach()\n\n# ---------------------------------------------------------------------------\n# Creating a version file to report version information\n# ---------------------------------------------------------------------------\nconfigure_file(\n  ${CMAKE_CURRENT_SOURCE_DIR}/Version.java.in\n  ${GTIRB_JAVA_SOURCE_DIR}/com/grammatech/gtirb/Version.java @ONLY\n)\n\n# Append generated Version.java\nlist(APPEND GTIRB_API_JAVAS Version)\n\nforeach(GTIRB_API_JAVA ${GTIRB_API_JAVAS})\n  list(\n    APPEND GTIRB_API_SOURCES\n           ${GTIRB_JAVA_SOURCE_DIR}/com/grammatech/gtirb/${GTIRB_API_JAVA}.java\n  )\nendforeach()\n\nset(GTIRB_JAVA_API_VERSION\n    \"${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}\"\n)\nset(TARGET_DIR \"${CMAKE_CURRENT_BINARY_DIR}/target\")\nset(GTIRB_JAVA_APIDOCS_DIR\n    \"${TARGET_DIR}/apidocs\"\n    PARENT_SCOPE\n)\n\nset(GTIRB_JAVA_API_JARS\n    \"${TARGET_DIR}/gtirb_api-${GTIRB_JAVA_API_VERSION}.jar\"\n    \"${TARGET_DIR}/gtirb_api-${GTIRB_JAVA_API_VERSION}-sources.jar\"\n    \"${TARGET_DIR}/gtirb_api-${GTIRB_JAVA_API_VERSION}-javadoc.jar\"\n)\n\nif(NOT GTIRB_DOCUMENTATION)\n  set(MAVEN_PACKAGE_ARGS \"-Dmaven.javadoc.skip=true\")\nendif()\n\nadd_custom_command(\n  OUTPUT ${GTIRB_JAVA_API_JARS} ${GTIRB_JAVA_APIDOCS_DIR}/index.html\n  COMMAND ${MVN} package ${MAVEN_PACKAGE_ARGS}\n  WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}\"\n  DEPENDS ${GTIRB_API_SOURCES} ${GTIRB_PROTOBUF_JAVA}\n)\n\nadd_custom_target(gtirb-java-api ALL DEPENDS ${GTIRB_JAVA_API_JARS})\n\n# ---------------------------------------------------------------------------\n# Building the test code\n# ---------------------------------------------------------------------------\n\nif(GTIRB_ENABLE_TESTS)\n  if(WIN32)\n    set(DIR_SEP \"\\;\")\n  else()\n    set(DIR_SEP \":\")\n  endif()\n\n  execute_process(\n    COMMAND ${MVN} -q exec:exec -Dexec.classpathScope=compile\n            -Dexec.executable=echo -Dexec.args=%classpath\n    WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}\"\n    OUTPUT_VARIABLE JAR_FILE_LIST\n  )\n  string(STRIP ${JAR_FILE_LIST} JAR_FILE_LIST)\n\n  file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/tests/\n       DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/tests\n  )\n\n  set(GTIRB_JAVA_TESTS\n      TestAuxData\n      TestByteIntervals\n      TestIrSanity\n      TestSymbolicExpressions\n      TestModules\n      TestSections\n      TestSymbols\n      TestTuple\n      TestVariant\n  )\n\n  foreach(GTIRB_JAVA_TEST ${GTIRB_JAVA_TESTS})\n    add_custom_command(\n      TARGET gtirb-java-api\n      POST_BUILD\n      COMMAND\n        ${Java_JAVAC_EXECUTABLE} -cp ${JAR_FILE_LIST}:${JUNIT_STANDALONE_JAR} -d\n        ${CMAKE_CURRENT_BINARY_DIR}\n        ${CMAKE_CURRENT_BINARY_DIR}/tests/${GTIRB_JAVA_TEST}.java\n      COMMENT \"Building ${GTIRB_JAVA_TEST}\" DEPENDS\n              ${CMAKE_CURRENT_BINARY_DIR}/tests/${GTIRB_JAVA_TEST}.java\n    )\n  endforeach()\n\n  add_test(\n    NAME JUnitTests\n    COMMAND\n      ${Java_JAVA_EXECUTABLE} -ea -jar ${JUNIT_STANDALONE_JAR} execute\n      --class-path ${CMAKE_CURRENT_BINARY_DIR}:${JAR_FILE_LIST}\n      --scan-class-path\n  )\n\nendif()\n"
  },
  {
    "path": "java/Version.java.in",
    "content": "/*\n *  Copyright (C) 2020 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\npackage com.grammatech.gtirb;\n\n/**\n * The semantic version of this API and version of protobuf this API\n * can read and write from.\n */\npublic class Version {\n        // The semantic version of this API.\n\tpublic static final String gtirbApiVersion =\n            \"@PROJECT_VERSION_MAJOR@.\" +\n            \"@PROJECT_VERSION_MINOR@.\" +\n            \"@PROJECT_VERSION_PATCH@\";\n        // The version of Protobuf this API can read and write from.\n\tpublic static final int gtirbProtobufVersion =\n            @GTIRB_PROTOBUF_VERSION@;\n}\n"
  },
  {
    "path": "java/build.gradle",
    "content": "/* Gradle build for GTIRB Java API\n *\n * NOTE: The supported build system is CMake.\n * This Gradle build exists as a convenience to make it easier to develop in\n * IDEs like IntelliJ, Eclipse, etc.\n *\n * Before running Gradle, generate Protobuf Java sources:\n *   $ protoc --java_out=. --proto-path=proto ../proto/*.proto\n *\n * After IntelliJ import, it may help to add to its .idea/gradle.xml:\n *   <option name=\"resolveModulePerSourceSet\" value=\"false\" />\n */\napply plugin: 'java'\n\nrepositories { mavenCentral() }\n\nsourceSets {\n    main.java.srcDirs = ['com', \"${buildDir}/generated/java\"]\n    test.java.srcDirs = ['tests']\n}\n\ndependencies {\n    implementation 'com.google.protobuf:protobuf-java:4.0.0-rc-2'\n    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.0'\n    testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.0'\n    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.0'\n}\n\ncompileJava {\n    doFirst {\n        def pkg = \"com/grammatech/gtirb\"\n\n        // Read the version information from version.txt\n        def versionTxt = new File(\"${projectDir}/../version.txt\")\n        def versionMap = [:]\n        versionTxt.eachLine { String line ->\n                def (name, value) = line.split()\n                versionMap[name] = value\n        }\n\n        // This version number appears in the output JAR filename\n        version = versionMap[\"VERSION_MAJOR\"] + \".\" +\n            versionMap[\"VERSION_MINOR\"] + \".\" + versionMap[\"VERSION_PATCH\"]\n\n        // Generate Version.java based on the Version.java.in template\n        ant.mkdir(dir: \"${buildDir}/generated/java/${pkg}/gtirb\")\n        def newVersion = new File(\"${buildDir}/generated/java/${pkg}/Version.java\")\n        def templateVersion = new File(\"${projectDir}/Version.java.in\")\n        newVersion.withWriter { def writer ->\n            templateVersion.eachLine { def line ->\n                def newLine = line\n                    .replace(\"@PROJECT_VERSION_MAJOR@\", versionMap[\"VERSION_MAJOR\"])\n                    .replace(\"@PROJECT_VERSION_MINOR@\", versionMap[\"VERSION_MINOR\"])\n                    .replace(\"@PROJECT_VERSION_PATCH@\", versionMap[\"VERSION_PATCH\"])\n                    .replace(\"@GTIRB_PROTOBUF_VERSION@\", versionMap[\"VERSION_PROTOBUF\"])\n                writer.write(newLine + \"\\n\");\n            }\n        }\n    }\n}\n\ntest {\n  useJUnitPlatform()\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/AuxDataContainer.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.google.protobuf.ByteString;\nimport com.grammatech.gtirb.proto.AuxDataOuterClass;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.lang.IllegalArgumentException;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\n\n/**\n * Provides functionality for associating auxiliary\n * data with elements of the intermediate representation.\n */\npublic abstract class AuxDataContainer extends Node {\n\n    /**\n     * Inner class for managing AuxData instances\n     */\n    public static class AuxData {\n\n        // Always populated.\n        private String name;\n        private String typeName;\n\n        // Only populated during serialization events.\n        // This is considered stale if the schema/decoded members are non-empty.\n        private Optional<byte[]> encoded;\n\n        // Only populated if the client adds/gets the AuxData.\n        private Optional<AuxDataSchema> schema;\n        private Optional<Object> decoded;\n\n        /**\n         * Class constructor for AuxData from protobuf {@link AuxData}.\n         * @param  protoAuxData   The {@link AuxData} as serialized into a\n         *     protocol buffer.\n         * @param  name           The name of this {@link AuxData}.\n         */\n        AuxData(String name, AuxDataOuterClass.AuxData protoAuxData) {\n            this.name = name;\n            this.typeName = protoAuxData.getTypeName();\n            this.encoded = Optional.of(protoAuxData.getData().toByteArray());\n            this.schema = Optional.empty();\n            this.decoded = Optional.empty();\n        }\n\n        /**\n         * Class constructor for {@link AuxData} from an in-memory object.\n         * @param schema The {@link AuxDataSchema} for the AuxData entry.\n         * @param value The value to associate with thie AuxData entry.\n         */\n        <T> AuxData(AuxDataSchema<T> schema, T value) {\n            this.name = schema.getName();\n            this.typeName = schema.getCodec().getTypeName();\n            this.encoded = Optional.empty();\n            this.schema = Optional.of(schema);\n            this.decoded = Optional.of(value);\n        }\n\n        /**\n         * Get the {@link AuxData} name.\n         *\n         * @return the name.\n         */\n        public String getName() { return this.name; }\n\n        /**\n         * Get the Type String (schemata).\n         *\n         * @return the type string.\n         */\n        public String getTypeName() { return this.typeName; }\n\n        /**\n         * Get the decoded form of the {@link AuxData}.\n         *\n         * @param sch The schema used for decoding this {@link AuxData}.\n         * @return The decoded data object for this {@link AuxData}.\n         */\n        public <T> T getDecodedData(AuxDataSchema<T> sch) throws IOException {\n            // TODO: Some better way to confirm schema equivalence here.\n            // In particular, one could have the correct name and type\n            // name but still have an inconsistent type for T. Specifically,\n            // we want to test if sch is equivalent to this.schema.get().\n\n            // If this is not true, there's something seriously wrong with\n            // the AuxDataContainer code.\n            assert this.name.equals(sch.getName());\n\n            // This could be incorrect if the client is using inconsistent\n            // schemas with the same schema name.\n            if (!this.typeName.equals(sch.getCodec().getTypeName())) {\n                throw new IllegalArgumentException(\n                    \"Schema type names do not match! \" + this.typeName +\n                    \" vs. \" + sch.getCodec().getTypeName());\n            }\n\n            if (!this.schema.isPresent()) {\n                // If we're here because this is the initial get, and the\n                // AuxData has not been unserialized yet. Do the decoding now.\n                assert this.encoded.isPresent();\n                this.schema = Optional.of(sch);\n                this.decoded = Optional.of(sch.getCodec().decode(\n                    new ByteArrayInputStream(this.encoded.get())));\n            }\n\n            return (T)this.decoded.get();\n        }\n\n        /**\n         * Serialize this AuxData into a protobuf .\n         *\n         * @return AuxData protocol buffer.\n         */\n        AuxDataOuterClass.AuxData.Builder toProtobuf() {\n            // If we have a schema and decoded object, encode first.\n            if (this.schema.isPresent()) {\n                assert this.decoded.isPresent();\n                ByteArrayOutputStream os = new ByteArrayOutputStream();\n\n                // ByteArrayOutputStream shouldn't ever throw, but\n                // because we're passing it through the OutputStream,\n                // we have a syntactic obligation to check for throws.\n                try {\n                    this.schema.get().getCodec().encode(os, this.decoded.get());\n                } catch (Exception e) {\n                    assert false;\n                }\n\n                this.encoded = Optional.of(os.toByteArray());\n            } else {\n                assert this.encoded.isPresent();\n            }\n            AuxDataOuterClass.AuxData.Builder protoAuxData =\n                AuxDataOuterClass.AuxData.newBuilder();\n            protoAuxData.setData(ByteString.copyFrom(this.encoded.get()));\n            protoAuxData.setTypeName(this.typeName);\n            return protoAuxData;\n        }\n    }\n\n    protected HashMap<String, AuxData> auxDataMap;\n\n    /**\n     * Class constructor for an AuxDataContainer from a protobuf AuxData Map.\n     * @param  protoUuid        The UUID of this container.\n     * @param  protoAuxDataMap  A Map of AuxData names to protobuf AuxData\n     * objects.\n     */\n    AuxDataContainer(ByteString protoUuid,\n                     Map<String, AuxDataOuterClass.AuxData> protoAuxDataMap)\n        throws IOException {\n        super(Util.byteStringToUuid(protoUuid));\n        this.auxDataMap = new HashMap<String, AuxData>();\n        if (protoAuxDataMap != null) {\n            for (Map.Entry<String, AuxDataOuterClass.AuxData> entry :\n                 protoAuxDataMap.entrySet()) {\n                AuxData ad = new AuxData(entry.getKey(), entry.getValue());\n                auxDataMap.put(ad.getName(), ad);\n            }\n        }\n    }\n\n    AuxDataContainer() {\n        super();\n        this.auxDataMap = new HashMap<String, AuxData>();\n    }\n\n    /**\n     * Retrieve an arbitrary {@link AuxData} item from this container if it\n     * exists.\n     *\n     * @param schema The schema for the AuxData\n     * @return An {@link AuxData} object, or empty() if not present.\n     */\n    public <T> Optional<T> getAuxData(AuxDataSchema<T> schema) {\n        try {\n            AuxData ad = this.auxDataMap.get(schema.getName());\n\n            if (ad == null) {\n                return Optional.empty();\n            } else {\n                return Optional.of(ad.getDecodedData(schema));\n            }\n        } catch (IOException e) {\n            // This can occur when either the serialized content of the AuxData\n            // was corrupt or if the schema we're using is incompatible with it.\n            // In both cases, treat the the AuxData as not available.\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Adds an arbitrary {@link AuxData} item to this container. If an AuxData\n     * already exists with the given schema, then it is overwritten.\n     *\n     * @param schema The schema to use for the data\n     * @param data The data to add\n     */\n    public <T> void putAuxData(AuxDataSchema<T> schema, T data) {\n        AuxData ad = new AuxData(schema, data);\n        this.auxDataMap.put(schema.getName(), ad);\n    }\n\n    /**\n     * Remove an {@link AuxData} from this container.\n     *\n     * @param schema The schema of the {@link AuxData} to remove.\n     * @return False if the {@link AuxData} was not present in the container.\n     *     True otherwise.\n     */\n    public boolean removeAuxData(AuxDataSchema<?> schema) {\n        return this.removeAuxData(schema.getName());\n    }\n\n    /**\n     * Remove an {@link AuxData} from this container.\n     *\n     * This version of the function can be used for AuxData for which\n     * the schema is not known locally.\n     *\n     * @param name The name of the {@link AuxData} to remove.\n     * @return False if the {@link AuxData} was not present in the container.\n     *     True otherwise.\n     */\n    public boolean removeAuxData(String name) {\n        AuxData ad = this.auxDataMap.remove(name);\n        return ad != null;\n    }\n\n    /**\n     * Remove all {@link AuxData} from this container.\n     */\n    public void clearAuxData() { this.auxDataMap.clear(); }\n\n    /**\n     * Get a view of the {@link AuxData} entries present in this container.\n     *\n     * @return An unmodifiable view of the map of {@link AuxData} entries in\n     *     this container indexed by name.\n     */\n    public Map<String, AuxData> getAuxDataMap() {\n        return Collections.unmodifiableMap(this.auxDataMap);\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/AuxDataSchema.java",
    "content": "package com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.auxdatacodec.Codec;\n\n/**\n * This class mediates encoding and decoding of individual AuxData tables.\n *\n * Generally, a single instance should be created for each type of table. That\n * instance is then used to fetch and store content from/to an {@link\n * AuxDataContainer}.\n */\npublic final class AuxDataSchema<T> {\n    private String name;\n    private Codec<T> codec;\n\n    /**\n     * Constructor.\n     *\n     * @param name The name of the AuxData table. Each schema should have a\n     *     unique name.\n     * @param codec The codec governing encoding and decoding.\n     */\n    public AuxDataSchema(String name, Codec<T> codec) {\n        this.name = name;\n        this.codec = codec;\n    }\n\n    /**\n     * Get the name of the AuxData table.\n     */\n    public String getName() { return this.name; }\n\n    /**\n     * Get the codec to be used in encoding/decoding.\n     */\n    public Codec<T> getCodec() { return this.codec; }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/AuxDataSchemas.java",
    "content": "package com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.auxdatacodec.BoolCodec;\nimport com.grammatech.gtirb.auxdatacodec.ByteCodec;\nimport com.grammatech.gtirb.auxdatacodec.FloatCodec;\nimport com.grammatech.gtirb.auxdatacodec.ListCodec;\nimport com.grammatech.gtirb.auxdatacodec.LongCodec;\nimport com.grammatech.gtirb.auxdatacodec.MapCodec;\nimport com.grammatech.gtirb.auxdatacodec.OffsetCodec;\nimport com.grammatech.gtirb.auxdatacodec.SetCodec;\nimport com.grammatech.gtirb.auxdatacodec.ShortCodec;\nimport com.grammatech.gtirb.auxdatacodec.StringCodec;\nimport com.grammatech.gtirb.auxdatacodec.Tuple1Codec;\nimport com.grammatech.gtirb.auxdatacodec.Tuple2Codec;\nimport com.grammatech.gtirb.auxdatacodec.Tuple3Codec;\nimport com.grammatech.gtirb.auxdatacodec.Tuple4Codec;\nimport com.grammatech.gtirb.auxdatacodec.Tuple5Codec;\nimport com.grammatech.gtirb.auxdatacodec.UuidCodec;\nimport com.grammatech.gtirb.auxdatacodec.Variant11Codec;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.UUID;\n\n/**\n * This class contains schemas for sanctioned and provisional AuxData tables.\n *\n * Refer to AuxData.md for more information.\n */\npublic class AuxDataSchemas {\n\n    /* Sanctioned AuxData tables. */\n\n    /**\n     * The CodeBlock to which a DT_INIT entry in an ELF file's .dynamic section\n     * refers.\n     */\n    public final static AuxDataSchema<UUID> elfDynamicInit =\n        new AuxDataSchema<>(\"elfDynamicInit\", new UuidCodec());\n\n    /**\n     * The CodeBlock to which a DT_FINI entry in an ELF file's .dynamic section\n     * refers.\n     */\n    public final static AuxDataSchema<UUID> elfDynamicFini =\n        new AuxDataSchema<>(\"elfDynamicFini\", new UuidCodec());\n\n    /**\n     * The string value which the DT_SONAME entry in an ELF file's .dynamic\n     * section contains.\n     */\n    public final static AuxDataSchema<String> elfSoname =\n        new AuxDataSchema<>(\"elfSoname\", new StringCodec());\n\n    /**\n     * Stack executable flag specified by PT_GNU_STACK in ELF files.\n     */\n    public final static AuxDataSchema<Boolean> elfStackExec =\n        new AuxDataSchema<>(\"elfStackExec\", new BoolCodec());\n\n    /**\n     * The size of the PT_GNU_STACK segment in ELF files, which may influence\n     * the runtime stack size in certain environments.\n     */\n    public final static AuxDataSchema<Long> elfStackSize =\n        new AuxDataSchema<>(\"elfStackSize\", LongCodec.UINT64);\n\n    /**\n     * This table identifies all of the {@link CodeBlock}s that belong to each\n     * function.\n     */\n    public final static AuxDataSchema<Map<UUID, Set<UUID>>> functionBlocks =\n        new AuxDataSchema<>(\n            \"functionBlocks\",\n            new MapCodec<>(new UuidCodec(),\n                           new SetCodec<>(new UuidCodec(), HashSet::new),\n                           HashMap::new));\n\n    /**\n     * This table identifies all {@link CodeBlock}s that represent entry points\n     * to each function.\n     */\n    public final static AuxDataSchema<Map<UUID, Set<UUID>>> functionEntries =\n        new AuxDataSchema<>(\n            \"functionEntries\",\n            new MapCodec<>(new UuidCodec(),\n                           new SetCodec<>(new UuidCodec(), HashSet::new),\n                           HashMap::new));\n\n    /**\n     * This table identifies a canonical {@link Symbol} to be used for each\n     * function.\n     */\n    public final static AuxDataSchema<Map<UUID, UUID>> functionNames =\n        new AuxDataSchema<>(\n            \"functionNames\",\n            new MapCodec<>(new UuidCodec(), new UuidCodec(), HashMap::new));\n\n    /**\n     * An entry in this table indicates that the given {@link DataBlock}\n     * contains content that exhibits the given C++ type.\n     */\n    public final static AuxDataSchema<Map<UUID, String>> types =\n        new AuxDataSchema<>(\n            \"types\",\n            new MapCodec<>(new UuidCodec(), new StringCodec(), HashMap::new));\n\n    /**\n     * An entry in this table indicates that the given object's address is\n     * required to be evenly divisible by the alignment value.\n     */\n    public final static AuxDataSchema<Map<UUID, Long>> alignment =\n        new AuxDataSchema<>(\n            \"alignment\",\n            new MapCodec<>(new UuidCodec(), LongCodec.UINT64, HashMap::new));\n\n    /**\n     * Comment strings relevant to offsets in the GTIRB entries.\n     */\n    public final static AuxDataSchema<Map<Offset, String>> comments =\n        new AuxDataSchema<>(\n            \"comments\",\n            new MapCodec<>(new OffsetCodec(), new StringCodec(), HashMap::new));\n\n    /**\n     * A mapping of symbols in one module that are bound dynamically to symbols\n     * in another module.\n     */\n    public final static AuxDataSchema<Map<UUID, UUID>> symbolForwarding =\n        new AuxDataSchema<>(\n            \"symbolForwarding\",\n            new MapCodec<>(new UuidCodec(), new UuidCodec(), HashMap::new));\n\n    /**\n     * Locations of unused padding bytes in the binary.\n     */\n    public final static AuxDataSchema<Map<Offset, Long>> padding =\n        new AuxDataSchema<>(\n            \"padding\",\n            new MapCodec<>(new OffsetCodec(), LongCodec.UINT64, HashMap::new));\n\n    /* Provisional AuxData tables. */\n\n    /**\n     * Type descriptors representing what type of binary the GTIRB models (e.g.\n     * executable vs. dynamic library.)\n     */\n    public final static AuxDataSchema<List<String>> binaryType =\n        new AuxDataSchema<>(\"binaryType\",\n                            new ListCodec(new StringCodec(), ArrayList::new));\n\n    /**\n     * Map from Offsets to  vector of cfi directives.\n     */\n    public final static AuxDataSchema<Map<Offset, List<CfiDirective>>>\n        cfiDirectives = new AuxDataSchema<>(\n            \"cfiDirectives\",\n            new MapCodec<>(\n                new OffsetCodec(),\n                new ListCodec<>(\n                    new Tuple3Codec<>(\n                        new StringCodec(),\n                        new ListCodec<>(LongCodec.INT64, ArrayList::new),\n                        new UuidCodec(), CfiDirective::new),\n                    ArrayList::new),\n                HashMap::new));\n\n    /**\n     * Map from section UUIDs to tuples with the ELF section types and flags.\n     */\n    public final static AuxDataSchema<Map<UUID, SectionPropertyTuple>>\n        sectionProperties = new AuxDataSchema<>(\n            \"sectionProperties\",\n            new MapCodec<>(new UuidCodec(),\n                           new Tuple2Codec<>(LongCodec.UINT64, LongCodec.UINT64,\n                                             SectionPropertyTuple::new),\n                           HashMap::new));\n\n    /**\n     * Map from symbols to their type, binding, and visibility categories.\n     */\n    public final static AuxDataSchema<Map<UUID, ElfSymbolInfoTuple>>\n        elfSymbolInfo = new AuxDataSchema<>(\n            \"elfSymbolInfo\",\n            new MapCodec<>(\n                new UuidCodec(),\n                new Tuple5Codec<>(LongCodec.UINT64, new StringCodec(),\n                                  new StringCodec(), new StringCodec(),\n                                  LongCodec.UINT64, ElfSymbolInfoTuple::new),\n                HashMap::new));\n\n    /**\n     * Table of information about symbol versioning.\n     */\n    public final static AuxDataSchema<ElfSymbolVersionsTable>\n        elfSymbolVersions = new AuxDataSchema<>(\n            \"elfSymbolVersions\",\n            new Tuple3Codec<>(\n                new MapCodec<>(\n                    ShortCodec.UINT16,\n                    new Tuple2Codec<>(\n                        new ListCodec<>(new StringCodec(), ArrayList::new),\n                        ShortCodec.UINT16,\n                        ElfSymbolVersionsTable.SymVerDef::new),\n                    HashMap::new),\n                new MapCodec<>(new StringCodec(),\n                               new MapCodec<>(ShortCodec.UINT16,\n                                              new StringCodec(), HashMap::new),\n                               HashMap::new),\n                new MapCodec<>(\n                    new UuidCodec(),\n                    new Tuple2Codec<>(ShortCodec.UINT16, new BoolCodec(),\n                                      ElfSymbolVersionsTable.SymVerEntry::new),\n                    HashMap::new),\n                ElfSymbolVersionsTable::new));\n\n    /**\n     * Map from (typed) data objects to the encoding of the data, expressed as a\n     * std::string containing an assembler encoding specifier: \"string\",\n     * \"uleb128\" or \"sleb128\".\n     */\n    public final static AuxDataSchema<Map<UUID, String>> encodings =\n        new AuxDataSchema<>(\n            \"encodings\",\n            new MapCodec<>(new UuidCodec(), new StringCodec(), HashMap::new));\n\n    /**\n     * Map from function UUID to a list of weighted predictions.\n     */\n    public final static AuxDataSchema<\n        Map<String, Map<UUID, List<ProbFuncName>>>> functionNameProbabilities =\n        new AuxDataSchema<>(\n            \"functionNameProbabilities\",\n            new MapCodec<>(\n                new StringCodec(),\n                new MapCodec<>(\n                    new UuidCodec(),\n                    new ListCodec<>(\n                        new Tuple3Codec<>(new StringCodec(), new StringCodec(),\n                                          new FloatCodec(), ProbFuncName::new),\n                        ArrayList::new),\n                    HashMap::new),\n                HashMap::new));\n\n    /**\n     * Names of libraries that are included in an executable (statically linked)\n     */\n    public final static AuxDataSchema<Map<UUID, String>> includedLibraryNames =\n        new AuxDataSchema<>(\n            \"includedLibraryNames\",\n            new MapCodec<>(new UuidCodec(), new StringCodec(), HashMap::new));\n\n    /**\n     * Versions of libraries that are included in an executable (statically\n     * linked)\n     */\n    public final static AuxDataSchema<Map<UUID, String>>\n        includedLibraryVersions = new AuxDataSchema<>(\n            \"includedLibraryVersions\",\n            new MapCodec<>(new UuidCodec(), new StringCodec(), HashMap::new));\n\n    /**\n     * Names of the external libraries that are needed dynamically at run time.\n     */\n    public final static AuxDataSchema<List<String>> libraries =\n        new AuxDataSchema<>(\"libraries\",\n                            new ListCodec<>(new StringCodec(), ArrayList::new));\n\n    /**\n     * Paths contained in the rpath of the binary.\n     */\n    public final static AuxDataSchema<List<String>> libraryPaths =\n        new AuxDataSchema<>(\"libraryPaths\",\n                            new ListCodec<>(new StringCodec(), ArrayList::new));\n\n    /**\n     * List of tuples detailing an exported address, ordinal, and name for PE.\n     */\n    public final static AuxDataSchema<List<PeExportEntry>> peExportEntries =\n        new AuxDataSchema<>(\n            \"peExportEntries\",\n            new ListCodec<>(new Tuple3Codec<>(LongCodec.UINT64, LongCodec.INT64,\n                                              new StringCodec(),\n                                              PeExportEntry::new),\n                            ArrayList::new));\n\n    /**\n     * UUIDs of the exported symbols for PE.\n     */\n    public final static AuxDataSchema<List<UUID>> peExportedSymbols =\n        new AuxDataSchema<>(\"peExportedSymbols\",\n                            new ListCodec<>(new UuidCodec(), ArrayList::new));\n\n    /**\n     * List of tuples detailing an imported function address, ordinal, function\n     * name, and library names for PE.\n     */\n    public final static AuxDataSchema<List<PeImportEntry>> peImportEntries =\n        new AuxDataSchema<>(\n            \"peImportEntries\",\n            new ListCodec<>(new Tuple4Codec<>(LongCodec.UINT64, LongCodec.INT64,\n                                              new StringCodec(),\n                                              new StringCodec(),\n                                              PeImportEntry::new),\n                            ArrayList::new));\n\n    /**\n     * UUIDs of the imported symbols for PE.\n     */\n    public final static AuxDataSchema<List<UUID>> peImportedSymbols =\n        new AuxDataSchema<>(\"peImportedSymbols\",\n                            new ListCodec<>(new UuidCodec(), ArrayList::new));\n\n    /**\n     * List of PE resources.\n     */\n    public final static AuxDataSchema<List<PeResourceEntry>> peResource =\n        new AuxDataSchema<>(\n            \"peResource\",\n            new ListCodec<>(\n                new Tuple3Codec<>(\n                    new ListCodec<>(ByteCodec.UINT8, ArrayList::new),\n                    new OffsetCodec(), LongCodec.UINT64, PeResourceEntry::new),\n                ArrayList::new));\n\n    /**\n     * Profiling data. Executions by {@link CodeBlock}\n     */\n    public final static AuxDataSchema<Map<UUID, Long>> profile =\n        new AuxDataSchema<>(\n            \"profile\",\n            new MapCodec<>(new UuidCodec(), LongCodec.UINT64, HashMap::new));\n\n    /**\n     * Map of function UUIDs to their associated typeTable entries for the\n     * purpose of giving them prototypes.\n     */\n    public final static AuxDataSchema<Map<UUID, UUID>> prototypeTable =\n        new AuxDataSchema<>(\n            \"prototypeTable\",\n            new MapCodec<>(new UuidCodec(), new UuidCodec(), HashMap::new));\n\n    /**\n     * The intra-procedural SCC identifier of each {@link CodeBlock}.\n     */\n    public final static AuxDataSchema<Map<UUID, Long>> sccs =\n        new AuxDataSchema<>(\n            \"SCCs\",\n            new MapCodec<>(new UuidCodec(), LongCodec.INT64, HashMap::new));\n\n    /**\n     * Map from an Offset of a {@link SymbolicExpression} in a {@link\n     * ByteInterval} to its extent, a size in bytes.\n     */\n    public final static AuxDataSchema<Map<Offset, Long>>\n        symbolicExpressionSizes = new AuxDataSchema<>(\n            \"symbolicExpressionSizes\",\n            new MapCodec<>(new OffsetCodec(), LongCodec.UINT64, HashMap::new));\n\n    /**\n     * Structured type information about objects.\n     */\n    public final static AuxDataSchema<Map<UUID, TypeTableEntry>> typeTable =\n        new AuxDataSchema<>(\n            \"typeTable\",\n            new MapCodec<>(\n                new UuidCodec(),\n                new Variant11Codec<>(\n                    LongCodec.UINT64,\n                    new Tuple1Codec<>(ByteCodec.UINT8,\n                                      TypeTableEntry.BoolType::new),\n                    new Tuple2Codec<>(ByteCodec.INT8, LongCodec.UINT64,\n                                      TypeTableEntry.IntType::new),\n                    LongCodec.UINT64, LongCodec.UINT64,\n                    new Tuple2Codec<>(\n                        new UuidCodec(),\n                        new ListCodec<>(new UuidCodec(), ArrayList::new),\n                        TypeTableEntry.FunctionType::new),\n                    new UuidCodec(),\n                    new Tuple2Codec<>(new UuidCodec(), LongCodec.UINT64,\n                                      TypeTableEntry.ArrayType::new),\n                    new UuidCodec(),\n                    new Tuple2Codec<>(\n                        LongCodec.UINT64,\n                        new ListCodec<>(\n                            new Tuple2Codec<>(LongCodec.UINT64, new UuidCodec(),\n                                              TypeTableEntry.StructField::new),\n                            ArrayList::new),\n                        TypeTableEntry.StructType::new),\n                    new Tuple1Codec<>(ByteCodec.UINT8,\n                                      TypeTableEntry.VoidType::new),\n                    TypeTableEntry::makeUnknown, TypeTableEntry::makeBool,\n                    TypeTableEntry::makeInt, TypeTableEntry::makeChar,\n                    TypeTableEntry::makeFloat, TypeTableEntry::makeFunction,\n                    TypeTableEntry::makePointer, TypeTableEntry::makeArray,\n                    TypeTableEntry::makeAlias, TypeTableEntry::makeStruct,\n                    TypeTableEntry::makeVoid),\n                HashMap::new));\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/ByteBlock.java",
    "content": "/*\n *  Copyright (C) 2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.google.protobuf.ByteString;\nimport com.grammatech.gtirb.proto.ByteIntervalOuterClass;\nimport java.io.IOException;\nimport java.util.Optional;\nimport java.util.OptionalLong;\n\n/**\n * The ByteBlock class is a base class for code blocks and data blocks.\n */\npublic abstract class ByteBlock extends Node implements TreeListItem {\n\n    private long size;\n    private long offset;\n    private Optional<ByteInterval> byteInterval;\n\n    /**\n     * Class constructor for a ByteBlock from a protobuf byte block.\n     * @param  protoBlock     The byte block as serialized into a protocol\n     * buffer.\n     * @param  size           The size of this ByteBlock in bytes.\n     */\n    ByteBlock(ByteString protoUuid, ByteIntervalOuterClass.Block protoBlock,\n              long size) throws IOException {\n        super(Util.byteStringToUuid(protoUuid));\n        this.size = size;\n        this.offset = protoBlock.getOffset();\n        this.byteInterval = Optional.empty();\n    }\n\n    /**\n     * Class Constructor.\n     * @param  size           The number of bytes in this ByteBlock.\n     * @param  offset         The offset of this Block in the ByteInterval.\n     */\n    public ByteBlock(long size, long offset) {\n        super();\n        this.size = size;\n        this.offset = offset;\n        this.byteInterval = Optional.empty();\n    }\n\n    /**\n     * Get the size of this ByteBlock.\n     *\n     * @return  The number of bytes in this ByteBlock.\n     */\n    public long getSize() { return this.size; }\n\n    /**\n     * Set the size of this ByteBlock.\n     *\n     * @param newSize    The new size to give to this ByteBlock.\n     * @return           The new number of bytes in this ByteBlock.\n     */\n    public long setSize(long newSize) {\n        this.size = newSize;\n        return this.size;\n    }\n\n    /**\n     * Get the offset of this ByteBlock.\n     *\n     * @return  The difference in address of the beginning of this ByteBlock's\n     * ByteInterval and the beginning of this ByteBlock.\n     */\n    public long getOffset() { return this.offset; }\n\n    /**\n     * Get the index to manage this ByteBlock with.\n     *\n     * This is the index is used for storing and retrieving the ByteBlock, as\n     * required by the TreeListItem interface. ByteBlocks are ordered by\n     * offset, so this method just returns the offset.\n     * @return  The ByteBlock index, which is it's offset.\n     */\n    public long getIndex() { return this.offset; }\n\n    /**\n     * Get the address of this ByteBlock.\n     *\n     * @return  The ByteBlock address, if the ByteInterval has an address,\n     * otherwise null.\n     */\n    public OptionalLong getAddress() {\n        if (this.byteInterval.isEmpty())\n            return OptionalLong.empty();\n        OptionalLong biAddress = byteInterval.get().getAddress();\n        if (!biAddress.isPresent())\n            return OptionalLong.empty();\n        return OptionalLong.of(biAddress.getAsLong() + offset);\n    }\n\n    /**\n     * Get the ByteInterval that owns this ByteBlock.\n     *\n     * @return  The ByteInterval this ByteBlock belongs to. If it does not\n     * belong to a ByteInterval, returns null.\n     */\n    public Optional<ByteInterval> getByteInterval() {\n        return this.byteInterval;\n    }\n\n    /**\n     * Set the ByteInterval that owns this ByteBlock.\n     *\n     * @param  The ByteInterval this ByteBlock will belong to.\n     */\n    void setByteInterval(Optional<ByteInterval> byteInterval) {\n        this.byteInterval = byteInterval;\n    }\n\n    /**\n     * Serialize this ByteBlock into a protobuf.\n     *\n     * This method is intended to be overridden on the base classes.\n     *\n     * @return Block protocol buffer containing this ByteBlock.\n     */\n    ByteIntervalOuterClass.Block.Builder toProtobuf() {\n        return ByteIntervalOuterClass.Block.newBuilder();\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/ByteInterval.java",
    "content": "/*\n *  Copyright (C) 2020-2023 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.google.protobuf.ByteString;\nimport com.grammatech.gtirb.proto.ByteIntervalOuterClass;\nimport com.grammatech.gtirb.proto.SymbolicExpressionOuterClass;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.OptionalLong;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\n/**\n * A ByteInterval represents a piece of runtime memory.\n *\n * The ByteInterval class has a size and can store contents as a byte\n * array, Not having a byte array, or having one with a size smaller than\n * the ByteInterval size is allowed, generally this would represent\n * uninitialized memory.\n *\n * The byte blocks (code blocks and data blocks) and symbolic expressions\n * attached to a byte interval reference the memory range it contains,\n * and it may or may not have an assigned address at any one time.\n */\npublic final class ByteInterval extends Node implements TreeListItem {\n\n    private TreeMap<Long, List<ByteBlock>> blockTree = new TreeMap<>();\n    private TreeMap<Long, SymbolicExpression> symbolicExpressionTree =\n        new TreeMap<>();\n    private OptionalLong address;\n    private long size;\n    private byte[] bytes;\n    private Optional<Section> section;\n\n    /**\n     * Class constructor for a ByteInterval from a protobuf byte interval.\n     * @param  protoByteInterval  The byte interval as serialized into a\n     * protocol buffer.\n     */\n    private ByteInterval(ByteIntervalOuterClass.ByteInterval protoByteInterval)\n        throws IOException {\n        super(Util.byteStringToUuid(protoByteInterval.getUuid()));\n        this.section = Optional.empty();\n        if (protoByteInterval.getHasAddress()) {\n            this.address = OptionalLong.of(protoByteInterval.getAddress());\n        } else {\n            this.address = OptionalLong.empty();\n        }\n\n        this.bytes = protoByteInterval.getContents().toByteArray();\n        this.size = protoByteInterval.getSize();\n        List<ByteIntervalOuterClass.Block> protoBlockList =\n            protoByteInterval.getBlocksList();\n        for (ByteIntervalOuterClass.Block protoBlock : protoBlockList) {\n            ByteBlock newBlock = null;\n            // Avoid using protoBlock.hasData() or protoBlock.hasCode() for\n            // compatibility with older protobuf versions.\n            if (protoBlock.getValueCase() ==\n                ByteIntervalOuterClass.Block.ValueCase.DATA) {\n                newBlock = DataBlock.fromProtobuf(protoBlock);\n            } else if (protoBlock.getValueCase() ==\n                       ByteIntervalOuterClass.Block.ValueCase.CODE) {\n                newBlock = CodeBlock.fromProtobuf(protoBlock);\n            }\n            if (newBlock == null) {\n                throw new IllegalArgumentException(\n                    \"Block must be either a CodeBlock or a DataBlock.\");\n            }\n            this.insertByteBlock(newBlock);\n        }\n\n        Map<Long, SymbolicExpressionOuterClass.SymbolicExpression>\n            protoSymbolicExpressions =\n                protoByteInterval.getSymbolicExpressionsMap();\n        for (Map.Entry<Long, SymbolicExpressionOuterClass.SymbolicExpression>\n                 entry : protoSymbolicExpressions.entrySet()) {\n            SymbolicExpressionOuterClass\n                .SymbolicExpression protoSymbolicExpression = entry.getValue();\n\n            SymbolicExpression symbolicExpression;\n            if (protoSymbolicExpression.getValueCase() ==\n                SymbolicExpressionOuterClass.SymbolicExpression.ValueCase\n                    .ADDR_CONST) {\n                symbolicExpression = new SymAddrConst(protoSymbolicExpression);\n            } else if (protoSymbolicExpression.getValueCase() ==\n                       SymbolicExpressionOuterClass.SymbolicExpression.ValueCase\n                           .ADDR_ADDR) {\n                symbolicExpression = new SymAddrAddr(protoSymbolicExpression);\n            } else {\n                throw new IllegalArgumentException(\n                    \"Symbolic Expression must be either a SymAddrConst or a SymAddrAddr.\");\n            }\n            this.insertSymbolicExpression(entry.getKey(), symbolicExpression);\n        }\n    }\n\n    /**\n     * Class Constructor.\n     * @param  bytes      The array of bytes to be stored in the ByteInterval.\n     * @param  address    The address of the ByteInterval.\n     */\n    public ByteInterval(byte[] bytes, long address) {\n        super();\n        this.section = Optional.empty();\n        this.address = OptionalLong.of(address);\n        this.bytes = bytes;\n        if (bytes != null) {\n            this.size = bytes.length;\n        }\n    }\n\n    /**\n     * Class Constructor.\n     * @param  size  The size of the new ByteInterval.\n     */\n    public ByteInterval(long size) {\n        super();\n        this.setSize(size);\n        this.section = Optional.empty();\n        this.address = OptionalLong.empty();\n    }\n\n    /**\n     * Class Constructor.\n     */\n    public ByteInterval() {\n        super();\n        this.section = Optional.empty();\n        this.address = OptionalLong.empty();\n    }\n\n    /**\n     * Get the address of this ByteInterval.\n     *\n     * @return  An OptionalLong that either is empty or holds a valid address.\n     */\n    public OptionalLong getAddress() { return this.address; }\n\n    /**\n     * Set the address of this ByteInterval.\n     *\n     * @param address    The new address to give to this ByteInterval\n     */\n    public void setAddress(long address) {\n        this.address = OptionalLong.of(address);\n    }\n\n    /**\n     * Clears the address of this ByteInterval.\n     */\n    public void clearAddress() { this.address = OptionalLong.empty(); }\n\n    /**\n     * Check that this ByteInterval has an address.\n     *\n     * @return       <code>true</code> if this ByteInterval has an\n     * address; <code>false</code> otherwise.\n     */\n    public boolean hasAddress() { return address.isPresent(); }\n\n    /**\n     * Get the blocks of this ByteInterval.\n     *\n     * @return  An unmodifiable {@link ByteBlock} list of all the\n     * blocks in this {@link ByteInterval}.\n     */\n    public List<ByteBlock> getBlockList() {\n        List<ByteBlock> blockList = new ArrayList<ByteBlock>();\n        for (List<ByteBlock> entry : this.blockTree.values()) {\n            blockList.addAll(entry);\n        }\n        return Collections.unmodifiableList(blockList);\n    }\n\n    /**\n     * Get the size of this ByteBlock.\n     *\n     * @return  The number of bytes assigned to this ByteInterval.\n     */\n    public long getSize() { return this.size; }\n\n    /**\n     * Set the size of this ByteInterval.\n     *\n     * If the new size is less than the actual bytes, the byte array will be\n     * truncated to the new length.\n     *\n     * @param size  The new size to give to this ByteInterval.\n     */\n    public void setSize(long size) {\n        if (this.bytes != null && size < this.bytes.length) {\n            // Create truncated byte array of the given size\n            this.bytes = Arrays.copyOfRange(this.bytes, 0, (int)size);\n        }\n        this.size = size;\n    }\n\n    /**\n     * Get the byte array of this ByteInterval.\n     *\n     * @return  The array of bytes belonging to this ByteInterval.\n     */\n    public byte[] getBytes() { return this.bytes; }\n\n    /**\n     * Set the byte array of this ByteInterval.\n     *\n     * @param bytes    The new byte array to give to this ByteInterval.\n     */\n    public void setBytes(byte[] bytes) {\n        if (bytes != null && bytes.length > this.size) {\n            this.size = bytes.length;\n        }\n        this.bytes = bytes;\n    }\n\n    /**\n     * Get the size of this ByteBlock.\n     *\n     * @return  The number of bytes actually stored in this ByteInterval.\n     */\n    public long getInitializedSize() {\n        if (this.bytes != null)\n            return this.bytes.length;\n        return 0L;\n    }\n\n    /**\n     * Get the section this ByteInterval belongs to.\n     *\n     * @return  The Section that this ByteInterval belongs to, or null if it\n     * does not belong to any section.\n     */\n    public Optional<Section> getSection() { return this.section; }\n\n    /**\n     * Set the section this ByteInterval belongs to.\n     *\n     * @param  The Section that this ByteInterval belongs to, or null if it\n     * does not belong to any section.\n     */\n    void setSection(Optional<Section> section) { this.section = section; }\n\n    /**\n     * Get the index to manage this ByteInterval with.\n     *\n     * This is the index is used for storing and retrieving the ByteInterval, as\n     * required by the TreeListItem interface. ByteIntervals are ordered by\n     * address, so this method just returns the address.\n     * @return  The ByteInterval index, which is it's address.\n     */\n    public long getIndex() { return this.address.orElse(0); }\n\n    /////////////////////////////////////////////////////////////\n    // GENERIC METHODS\n    /////////////////////////////////////////////////////////////\n\n    //    // Generic method for retrieving items that intersect with a given\n    //    address private <T extends ByteIntervalItem> ArrayList<T>\n    //    getItemsIntersectingAddress(long address,\n    //                                TreeMap<Long, ArrayList<T>> tree) {\n    //        // Address is not valid if it is below the start if this byte\n    //        interval. if (this.address == null || address < this.address)\n    //            return null;\n    //        Long offset = address - this.address;\n    //        offset = offset < 0 ? 0L : offset;\n    //        ArrayList<T> resultList = new ArrayList<T>();\n    //\n    //        // Iterate through the blockTree, but leave out those block who\n    //        start\n    //        // after the searched-for address\n    //        SortedMap<Long, ArrayList<T>> subTree = tree.headMap(offset,\n    //        true); for (ArrayList<T> itemList : subTree.values()) {\n    //            for (T item : itemList) {\n    //                long start = item.getOffset();\n    //                long end = start + item.getSize();\n    //                // Check if this code block overlaps, including end\n    //                points:\n    //                //    block starts at or below this offset AND\n    //                //    block ends at or above this offset\n    //                // If so add it to the list.\n    //                if (start <= offset && end >= offset) {\n    //                    resultList.add(item);\n    //                }\n    //            }\n    //        }\n    //        return resultList;\n    //    }\n    // Might just as well replace all the references to this with the\n    // TreeListUtil version Generic method for retrieving items that intersect\n    // with a given address\n    private <T extends TreeListItem> List<T>\n    getItemsIntersectingAddress(long address, TreeMap<Long, List<T>> tree) {\n        if (!this.address.isPresent())\n            return null;\n        long ownAddress = this.address.getAsLong();\n\n        // Address is not valid if it is below the start if this byte interval.\n        if (Long.compareUnsigned(address, ownAddress) < 0)\n            return null;\n        long offset = address - ownAddress;\n\n        return TreeListUtils.getItemsIntersectingIndex(offset, tree);\n    }\n\n    // Generic method for retrieving items that intersect with a given address\n    // range\n    private <T extends TreeListItem> List<T>\n    getItemsIntersectingAddressRange(long startAddress, long endAddress,\n                                     TreeMap<Long, List<T>> tree) {\n        if (!this.address.isPresent())\n            return null;\n        long ownAddress = this.address.getAsLong();\n\n        // End address cannot be below the start of this ByteInterval\n        if (Long.compareUnsigned(endAddress, ownAddress) < 0)\n            return null;\n        long endOffset = endAddress - ownAddress;\n\n        // Allow ranges that start before this ByteInterval\n        long startOffset = 0;\n        if (Long.compareUnsigned(startAddress, ownAddress) >= 0) {\n            startOffset = startAddress - ownAddress;\n        }\n\n        return TreeListUtils.getItemsIntersectingIndexRange(startOffset,\n                                                            endOffset, tree);\n    }\n\n    // Generic method for retrieving items that start at a given address\n    private <T extends TreeListItem> List<T>\n    getItemsAtStartAddress(long address, TreeMap<Long, List<T>> tree) {\n        if (!this.address.isPresent())\n            return null;\n        long ownAddress = this.address.getAsLong();\n\n        // Address is not valid if it is below the start of this byte interval.\n        if (Long.compareUnsigned(address, ownAddress) < 0)\n            return null;\n        long offset = address - ownAddress;\n\n        return TreeListUtils.getItemsAtStartIndex(offset, tree);\n    }\n\n    // Generic method for retrieving items that start at a given address range\n    private <T extends TreeListItem> List<T>\n    getItemsAtStartAddressRange(long startAddress, long endAddress,\n                                TreeMap<Long, List<T>> tree) {\n        if (!this.address.isPresent())\n            return null;\n        long ownAddress = this.address.getAsLong();\n\n        // Range is not valid if either address falls outside the ByteInterval.\n        if (Long.compareUnsigned(startAddress, ownAddress + this.size) > 0 ||\n            Long.compareUnsigned(endAddress, ownAddress) < 0)\n            return null;\n\n        long startOffset = startAddress - ownAddress;\n        long endOffset = endAddress - ownAddress;\n        return TreeListUtils.getItemsAtStartIndexRange(startOffset, endOffset,\n                                                       tree);\n    }\n\n    /////////////////////////////////////////////////////////////\n    // BYTEBLOCK METHODS\n    /////////////////////////////////////////////////////////////\n\n    /**\n     * Insert a block into this ByteInterval.\n     *\n     * The Block must already have an offset. This will be used to determine\n     * where to insert it.\n     *\n     * @param block    The ByteBlock to add to this ByteInterval.\n     * @return         An updated list of blocks at this offset, or null if\n     * the insert fails.\n     */\n    public List<ByteBlock> insertByteBlock(ByteBlock block) {\n        List<ByteBlock> blockList;\n        Long offset = block.getOffset();\n        if (this.blockTree.containsKey(offset))\n            blockList = blockTree.get(offset);\n        else\n            blockList = new ArrayList<ByteBlock>();\n        blockList.add(block);\n        this.blockTree.put(offset, blockList);\n        block.setByteInterval(Optional.of(this));\n        return blockList;\n    }\n\n    /**\n     * Remove a block from this ByteInterval.\n     *\n     * @param block    The ByteBlock to add to this ByteInterval.\n     * @return boolean true if the byte interval contained the block,\n     * and it was removed.\n     */\n    public boolean removeByteBlock(ByteBlock block) {\n        if (block.getByteInterval().isEmpty() ||\n            block.getByteInterval().get() != this)\n            return false;\n        Long offset = block.getOffset();\n        List<ByteBlock> blockList = this.blockTree.get(offset);\n        if (blockList == null)\n            // no blocks at this offset\n            return false;\n        if (!blockList.remove(block))\n            // didn't remove, maybe no matching block?\n            return false;\n        // Did remove, update tree.\n        // If the block list is now empty, remove the node from the tree.\n        // Otherwise update the tree.\n        if (blockList.size() == 0)\n            this.blockTree.remove(offset);\n        else\n            this.blockTree.put(offset, blockList);\n        // List empty means did not remove\n        if (blockList != null) {\n            block.setByteInterval(Optional.empty());\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Get all ByteBlocks at an offset.\n     *\n     * @param offset      The offset of this ByteBlock from the beginning of the\n     * ByteInterval.\n     * @return            A list of blocks at this offset, or null if none.\n     */\n    public List<ByteBlock> findBlocksAtOffset(long offset) {\n        return this.blockTree.get(offset);\n    }\n\n    /**\n     * Get a ByteBlock iterator.\n     *\n     * @return  An iterator for iterating through all the blocks in this\n     * ByteInterval.\n     */\n    public Iterator<ByteBlock> byteBlockIterator() {\n        TreeListUtils<ByteBlock> blockTreeIterator =\n            new TreeListUtils<ByteBlock>(this.blockTree);\n        return blockTreeIterator.iterator();\n    }\n\n    /////////////////////////////////////////////////////////////\n    // CODEBLOCK METHODS\n    /////////////////////////////////////////////////////////////\n\n    /**\n     * Find all the blocks that have bytes that lie within the address\n     * specified.\n     *\n     * @param address      The address to look for.\n     * @return             A list of Code Blocks that intersect this address, or\n     * null if none.\n     */\n    public List<CodeBlock> findCodeBlocksOn(long address) {\n        List<ByteBlock> foundList =\n            getItemsIntersectingAddress(address, this.blockTree);\n        if (foundList == null)\n            return null;\n        List<CodeBlock> resultList = new ArrayList<CodeBlock>();\n        for (ByteBlock block : foundList) {\n            if (block instanceof CodeBlock)\n                resultList.add((CodeBlock)block);\n        }\n        if (resultList.size() > 0)\n            return resultList;\n        return null;\n    }\n\n    /**\n     * Find all the code blocks that have bytes that lie within the addresses\n     * specified.\n     *\n     * @param startAddress      The beginning of the address range to look for.\n     * (inclusive)\n     * @param endAddress        The last address of the address range to look\n     * for. (exclusive)\n     * @return                  A list of Code Blocks that intersect this\n     * address range, or null if none.\n     */\n    public List<CodeBlock> findCodeBlocksOn(long startAddress,\n                                            long endAddress) {\n        List<ByteBlock> foundList = getItemsIntersectingAddressRange(\n            startAddress, endAddress, this.blockTree);\n        if (foundList == null)\n            return null;\n        List<CodeBlock> resultList = new ArrayList<CodeBlock>();\n        for (ByteBlock block : foundList) {\n            if (block instanceof CodeBlock)\n                resultList.add((CodeBlock)block);\n        }\n        if (resultList.size() > 0)\n            return resultList;\n        return null;\n    }\n\n    /**\n     * Find all the code blocks that start at an address.\n     *\n     * @param address      The address to look for.\n     * @return             A list of Code Blocks that that start at this\n     * address, or null if none.\n     */\n    public List<CodeBlock> findCodeBlocksAt(long address) {\n        List<ByteBlock> foundList =\n            getItemsAtStartAddress(address, this.blockTree);\n        if (foundList == null)\n            return null;\n        List<CodeBlock> resultList = new ArrayList<CodeBlock>();\n        for (ByteBlock block : foundList) {\n            if (block instanceof CodeBlock)\n                resultList.add((CodeBlock)block);\n        }\n        if (resultList.size() > 0)\n            return resultList;\n        return null;\n    }\n\n    /**\n     * Find all the code blocks that start between a range of addresses.\n     *\n     * @param startAddress      The beginning of the address range to look for.\n     * (inclusive)\n     * @param endAddress        The last address in the address range to look\n     *     for.\n     * (exclusive)\n     * @return                  A list of Code Blocks that that start at this\n     * address, or null if none.\n     */\n    public List<CodeBlock> findCodeBlocksAt(long startAddress,\n                                            long endAddress) {\n        List<ByteBlock> foundList = getItemsAtStartAddressRange(\n            startAddress, endAddress, this.blockTree);\n        if (foundList == null)\n            return null;\n        List<CodeBlock> resultList = new ArrayList<CodeBlock>();\n        for (ByteBlock block : foundList) {\n            if (block instanceof CodeBlock)\n                resultList.add((CodeBlock)block);\n        }\n        if (resultList.size() > 0)\n            return resultList;\n        return null;\n    }\n\n    /////////////////////////////////////////////////////////////\n    // DATABLOCK METHODS\n    /////////////////////////////////////////////////////////////\n\n    /**\n     * Find all the data blocks that have bytes that lie within the address\n     * specified\n     *\n     * @param address      The address to look for.\n     * @return             A list of Data Blocks that intersect this address, or\n     * null if none.\n     */\n    public List<DataBlock> findDataBlocksOn(long address) {\n        List<ByteBlock> foundList =\n            getItemsIntersectingAddress(address, this.blockTree);\n        if (foundList == null)\n            return null;\n        List<DataBlock> resultList = new ArrayList<DataBlock>();\n        for (ByteBlock block : foundList) {\n            if (block instanceof DataBlock)\n                resultList.add((DataBlock)block);\n        }\n        if (resultList.size() > 0)\n            return resultList;\n        return null;\n    }\n\n    /**\n     * Find all the data blocks that have bytes that lie within the address\n     * range specified\n     *\n     * @param startAddress      The beginning of the address range to look for.\n     * (inclusive)\n     * @param endAddress        The last address of the address range to look\n     * for. (exclusive)\n     * @return                  A list of Data Blocks that intersect this\n     * address range, or null if none.\n     */\n    public List<DataBlock> findDataBlocksOn(long startAddress,\n                                            long endAddress) {\n        List<ByteBlock> foundList = getItemsIntersectingAddressRange(\n            startAddress, endAddress, this.blockTree);\n        if (foundList == null)\n            return null;\n        List<DataBlock> resultList = new ArrayList<DataBlock>();\n        for (ByteBlock block : foundList) {\n            if (block instanceof DataBlock)\n                resultList.add((DataBlock)block);\n        }\n        if (resultList.size() > 0)\n            return resultList;\n        return null;\n    }\n\n    /**\n     * Find all the data blocks that start at an address.\n     *\n     * @param address      The address to look for.\n     * @return             A list of Data Blocks that that start at this\n     * address, or null if none.\n     */\n    public List<DataBlock> findDataBlocksAt(long address) {\n        List<ByteBlock> foundList =\n            getItemsAtStartAddress(address, this.blockTree);\n        if (foundList == null)\n            return null;\n        List<DataBlock> resultList = new ArrayList<DataBlock>();\n        for (ByteBlock block : foundList) {\n            if (block instanceof DataBlock)\n                resultList.add((DataBlock)block);\n        }\n        if (resultList.size() > 0)\n            return resultList;\n        return null;\n    }\n\n    /**\n     * Find all the data blocks that start between a range of addresses.\n     *\n     * @param startAddress      The beginning of the address range to look for.\n     * (inclusive)\n     * @param endAddress        The last address in the address to look for.\n     * (exclusive)\n     * @return                  A list of Data Blocks that that start at this\n     * address, or null if none.\n     */\n    public List<DataBlock> findDataBlocksAt(long startAddress,\n                                            long endAddress) {\n        List<ByteBlock> foundList = getItemsAtStartAddressRange(\n            startAddress, endAddress, this.blockTree);\n        if (foundList == null)\n            return null;\n        List<DataBlock> resultList = new ArrayList<DataBlock>();\n        for (ByteBlock block : foundList) {\n            if (block instanceof DataBlock)\n                resultList.add((DataBlock)block);\n        }\n        if (resultList.size() > 0)\n            return resultList;\n        return null;\n    }\n\n    /////////////////////////////////////////////////////////////\n    // SYMBOLICEXPRESSION METHODS\n    /////////////////////////////////////////////////////////////\n\n    /**\n     * Insert a symbolic expression into this ByteInterval.\n     *\n     * @param offset The offset within this ByteInterval at which the address\n     * described by this Symbolic Expression belongs; not to be confused with\n     * the symbol-relative offset that may be part of a {@link SymAddrConst}.\n     * @param symbolicExpression The SymbolicExpression to add to this\n     * ByteInterval.\n     */\n    public void\n    insertSymbolicExpression(long offset,\n                             SymbolicExpression symbolicExpression) {\n        this.symbolicExpressionTree.put(offset, symbolicExpression);\n    }\n\n    /**\n     * Remove a symbolic expression from this byte interval.\n     *\n     * @param offset The offset within this {@link ByteInterval} of the\n     * {@link SymbolicExpression}.\n     * @return boolean true if the byte interval contained the symbolic\n     * expression, and it was removed.\n     */\n    public boolean removeSymbolicExpression(long offset) {\n        return (this.symbolicExpressionTree.remove(offset) != null);\n    }\n\n    /**\n     * Get a SymbolicExpression iterator.\n     *\n     * @return  An iterator for iterating through the symbolic expressions\n     * in this ByteInterval. Each value returned by the iterator is a of type\n     * Map.Entry&lt;Long, SymbolicExpression&gt;, where the key is the offset of\n     * the SymbolicExpression in the ByteInterval.\n     */\n    public Iterator<Map.Entry<Long, SymbolicExpression>>\n    symbolicExpressionIterator() {\n        return this.symbolicExpressionTree.entrySet().iterator();\n    }\n\n    /**\n     * Find all the symbolic expressions that start at an address.\n     *\n     * Note that only one symbolic expression can be at any given offset,\n     * so this will return at most one SymbolicExpression.\n     *\n     * @param address      The address to look for.\n     * @return             A Symbolic Expression at this address,\n     * or null if none.\n     */\n    public SymbolicExpression findSymbolicExpressionAt(long address) {\n        return this.symbolicExpressionTree.get(address);\n    }\n\n    /**\n     * Find all the symbolic expressions that start between a range of\n     * addresses.\n     *\n     * @param startAddress      The beginning of the address range to look for.\n     * (inclusive)\n     * @param endAddress        The last address in the address to look for.\n     * (exlusive)\n     * @return                  An iterator of the set of SymbolicExpressions\n     * found, if any, as Map entries, where the key is the offset of the\n     * SymbolicExpression in the ByteInterval.\n     */\n    public Iterator<Map.Entry<Long, SymbolicExpression>>\n    findSymbolicExpressionsAt(long startAddress, long endAddress) {\n        long start = startAddress;\n        long end = endAddress;\n\n        if (endAddress < startAddress) {\n            start = endAddress;\n            end = startAddress;\n        }\n\n        SortedMap<Long, SymbolicExpression> subTree =\n            symbolicExpressionTree.subMap(start, end);\n        return subTree.entrySet().iterator();\n    }\n\n    /**\n     * De-serialize a ByteInterval from a protobuf .\n     *\n     * @param  protoByteInterval  The byte interval as serialized into a\n     * protocol buffer.\n     * @param  section            The Section that owns this ByteInterval.\n     * @return An initialized ByteInterval.\n     */\n    static ByteInterval\n    fromProtobuf(ByteIntervalOuterClass.ByteInterval protoByteInterval)\n        throws IOException {\n        return new ByteInterval(protoByteInterval);\n    }\n\n    /**\n     * Serialize this ByteInterval into a protobuf .\n     *\n     * @return ByteInterval protocol buffer.\n     */\n    public ByteIntervalOuterClass.ByteInterval.Builder toProtobuf() {\n        ByteIntervalOuterClass.ByteInterval.Builder protoByteInterval =\n            ByteIntervalOuterClass.ByteInterval.newBuilder();\n        protoByteInterval.setUuid(Util.uuidToByteString(this.getUuid()));\n        protoByteInterval.setAddress(this.getAddress().orElse(0));\n        protoByteInterval.setSize(this.getSize());\n        protoByteInterval.setHasAddress(this.hasAddress());\n\n        // Iterate through blocks, adding them\n        Iterator<ByteBlock> blocks = this.byteBlockIterator();\n        while (blocks.hasNext()) {\n            ByteBlock block = blocks.next();\n            ByteIntervalOuterClass.Block.Builder protoBlock =\n                block.toProtobuf();\n            protoByteInterval.addBlocks(protoBlock);\n        }\n\n        // Iterate through symbolic expressions, adding them\n        for (Map.Entry<Long, SymbolicExpression> symbolicEntry :\n             symbolicExpressionTree.entrySet()) {\n            SymbolicExpression symbolicExpression = symbolicEntry.getValue();\n            SymbolicExpressionOuterClass.SymbolicExpression\n                .Builder protoSymbolicExpression =\n                symbolicExpression.toProtobuf();\n            protoByteInterval.putSymbolicExpressions(\n                symbolicEntry.getKey(), protoSymbolicExpression.build());\n        }\n        if (this.bytes == null) {\n            protoByteInterval.setContents(ByteString.EMPTY);\n        } else {\n            protoByteInterval.setContents(ByteString.copyFrom(this.bytes));\n        }\n        return protoByteInterval;\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/CFG.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.google.protobuf.ByteString;\nimport com.grammatech.gtirb.proto.CFGOuterClass;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * A CFG represents the interprocedural control flow graph.\n */\npublic class CFG {\n\n    private List<Edge> edgeList;\n    private List<byte[]> verticeList;\n\n    /**\n     * Class constructor for a {@link CFG} from a protobuf CFG.\n     * @param  protoCfg  The CFG as serialized into a protocol buffer.\n     */\n    public CFG(CFGOuterClass.CFG protoCfg) throws IOException {\n        this.edgeList = new ArrayList<Edge>();\n        this.verticeList = new ArrayList<byte[]>();\n        for (CFGOuterClass.Edge protoEdge : protoCfg.getEdgesList()) {\n            Edge edge = new Edge(protoEdge);\n            edgeList.add(edge);\n        }\n        for (com.google.protobuf.ByteString byteString :\n             protoCfg.getVerticesList()) {\n            byte[] vertice = byteString.toByteArray();\n            verticeList.add(vertice);\n        }\n    }\n\n    /**\n     * Class constructor for a {@link CFG}.\n     * @param  edgeList  The edges belonging to to this CFG.\n     * @param  verticeList  The vertices belonging to this CFG.\n     */\n    public CFG(List<Edge> edgeList, List<byte[]> verticeList) {\n        this.edgeList = edgeList;\n        this.verticeList = verticeList;\n    }\n\n    /**\n     * Get the {@link Edge} list of a {@link CFG}.\n     *\n     * @return  The edge list.\n     */\n    public List<Edge> getEdgeList() { return this.edgeList; }\n\n    /**\n     * Set the {@link Edge} list of a {@link CFG}.\n     *\n     * @param edgeList  The edge list.\n     */\n    public void setEdgeList(List<Edge> edgeList) { this.edgeList = edgeList; }\n\n    /**\n     * Get the vertice list of a {@link CFG}.\n     *\n     * @return  The vertice list.\n     */\n    public List<byte[]> getVerticeList() { return this.verticeList; }\n\n    /**\n     * Set the vertice list of a {@link CFG}.\n     *\n     * @param verticeList  The vertice list.\n     */\n    public void setVerticeList(List<byte[]> verticeList) {\n        this.verticeList = verticeList;\n    }\n\n    // DEPRECATED\n    //    public CFGOuterClass.CFG.Builder buildCFG() {\n    //        CFGOuterClass.CFG.Builder newCFG = CFGOuterClass.CFG.newBuilder();\n    //        newCFG.mergeFrom(this.protoCfg);\n    //        return newCFG;\n    //    }\n\n    /**\n     * De-serialize a {@link CFG} from a protobuf .\n     *\n     * @param  protoCFG  The CFG as serialized into a protocol buffer.\n     * @return An initialized CFG.\n     */\n    public static CFG fromProtobuf(CFGOuterClass.CFG protoCFG)\n        throws IOException {\n        return new CFG(protoCFG);\n    }\n\n    /**\n     * Serialize this {@link CFG} into a protobuf.\n     *\n     * @return edge protocol buffer.\n     */\n    public CFGOuterClass.CFG.Builder toProtobuf() {\n        CFGOuterClass.CFG.Builder protoCfg = CFGOuterClass.CFG.newBuilder();\n\n        for (byte[] vertice : this.verticeList)\n            protoCfg.addVertices(ByteString.copyFrom(vertice));\n        for (Edge edge : this.edgeList)\n            protoCfg.addEdges(edge.toProtobuf());\n        return protoCfg;\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/CfiDirective.java",
    "content": "package com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.tuple.Tuple3;\nimport java.util.List;\nimport java.util.UUID;\n\n/**\n * A tuple representing an individual CFI directive.\n */\npublic class CfiDirective extends Tuple3<String, List<Long>, UUID> {\n    /**\n     * Constructor for a CFI directive.\n     *\n     * @param name The name of the directive (mnemonic.)\n     * @param args Numeric arguments for the directive.\n     * @param symbolUuid UUID of the {@link Symbol} indicating where the\n     *     directive applies.\n     */\n    public CfiDirective(String name, List<Long> args, UUID symbolUuid) {\n        super(name, args, symbolUuid);\n    }\n\n    /**\n     * Get the name of the directive (mnemonic.)\n     */\n    public String getName() { return this.get0(); }\n\n    /**\n     * Get the numeric arguments to the directive.\n     */\n    public List<Long> getArgs() { return this.get1(); }\n\n    /**\n     * Get the UUID of the {@link Symbol} indicating where the directive\n     * applies.\n     */\n    public UUID getSymbolUuid() { return this.get2(); }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/CodeBlock.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.google.protobuf.ByteString;\nimport com.grammatech.gtirb.proto.ByteIntervalOuterClass;\nimport com.grammatech.gtirb.proto.CodeBlockOuterClass;\nimport java.io.IOException;\n\n/**\n * CodeBlock represents a basic block in the binary.\n */\npublic class CodeBlock extends ByteBlock {\n    /**\n     * Variations on decoding a particular ISA\n     */\n    public enum DecodeMode {\n        Default,\n        Thumb,\n    }\n\n    private DecodeMode decodeMode;\n\n    /**\n     * Class constructor for a {@link CodeBlock} from a protobuf CodeBlock.\n     * @param  protoBlock  The CodeBlock as serialized into a protocol buffer.\n     */\n    private CodeBlock(ByteString protoUuid,\n                      ByteIntervalOuterClass.Block protoBlock, long size)\n        throws IOException {\n        super(protoUuid, protoBlock, size);\n        assert (protoBlock.getValueCase() ==\n                ByteIntervalOuterClass.Block.ValueCase.CODE);\n        CodeBlockOuterClass.CodeBlock protoCodeBlock = protoBlock.getCode();\n        this.decodeMode =\n            DecodeMode.values()[protoCodeBlock.getDecodeModeValue()];\n    }\n\n    /**\n     * Class constructor for a {@link CodeBlock}.\n     */\n    public CodeBlock(long size, long offset, DecodeMode decodeMode) {\n        super(size, offset);\n        this.decodeMode = decodeMode;\n    }\n\n    /**\n     * Get the decode mode of this {@link ByteBlock}.\n     *\n     * @return  The decode mode.\n     */\n    public DecodeMode getDecodeMode() { return decodeMode; }\n\n    /**\n     * Set the decode mode of this {@link CodeBlock}.\n     *\n     * @param decodeMode    The decode mode.\n     */\n    public void setDecodeMode(DecodeMode decodeMode) {\n        this.decodeMode = decodeMode;\n    }\n\n    /**\n     * De-serialize a {@link CodeBlock} from a protobuf Block.\n     *\n     * @return An initialized CodeBlock.\n     */\n    static CodeBlock fromProtobuf(ByteIntervalOuterClass.Block protoBlock)\n        throws IOException {\n        // Avoid using protoBlock.hasCode() for compatibility with older\n        // protobuf\n        if (protoBlock.getValueCase() !=\n            ByteIntervalOuterClass.Block.ValueCase.CODE) {\n            return null;\n        }\n        CodeBlockOuterClass.CodeBlock protoCodeBlock = protoBlock.getCode();\n        return new CodeBlock(protoCodeBlock.getUuid(), protoBlock,\n                             protoCodeBlock.getSize());\n    }\n\n    /**\n     * Serialize this {@link CodeBlock} into a protobuf.\n     *\n     * @return Block protocol buffer containing this CodeBlock.\n     */\n    @Override\n    ByteIntervalOuterClass.Block.Builder toProtobuf() {\n        // The protoBlock is in ByteInterval outer class, and it gets a code\n        // block added to it with the setCode() method. So first create the\n        // protoBlock, then create the protoCodeBlock and add it to the\n        // protoBlock.\n        ByteIntervalOuterClass.Block.Builder protoBlock =\n            ByteIntervalOuterClass.Block.newBuilder();\n\n        CodeBlockOuterClass.CodeBlock.Builder protoCodeBlock =\n            CodeBlockOuterClass.CodeBlock.newBuilder();\n        protoCodeBlock.setDecodeModeValue(this.decodeMode.ordinal());\n        protoCodeBlock.setUuid(Util.uuidToByteString(this.getUuid()));\n        protoCodeBlock.setSize(this.getSize());\n        protoBlock.setOffset(this.getOffset());\n        protoBlock.setCode(protoCodeBlock);\n        return protoBlock;\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/DataBlock.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.google.protobuf.ByteString;\nimport com.grammatech.gtirb.proto.ByteIntervalOuterClass;\nimport com.grammatech.gtirb.proto.DataBlockOuterClass;\nimport java.io.IOException;\n\n/**\n * DataBlock represents a data object, possibly symbolic.\n */\npublic class DataBlock extends ByteBlock {\n\n    /**\n     * Class constructor for a {@link DataBlock} from a protobuf DataBlock.\n     * @param  protoBlock  The DataBlock as serialized into a protocol buffer.\n     */\n    private DataBlock(ByteString protoUuid,\n                      ByteIntervalOuterClass.Block protoBlock, long size)\n        throws IOException {\n        super(protoUuid, protoBlock, size);\n    }\n\n    /**\n     * Class constructor for a {@link DataBlock}.\n     */\n    public DataBlock(long size, long offset) { super(size, offset); }\n\n    /**\n     * De-serialize a {@link DataBlock} from a protobuf Block.\n     *\n     * @return An initialized DataBlock.\n     */\n    static DataBlock fromProtobuf(ByteIntervalOuterClass.Block protoBlock)\n        throws IOException {\n        // Avoid using protoBlock.hasData() for compatibility with older\n        // protobuf\n        if (protoBlock.getValueCase() !=\n            ByteIntervalOuterClass.Block.ValueCase.DATA) {\n            return null;\n        }\n        DataBlockOuterClass.DataBlock protoDataBlock = protoBlock.getData();\n        return new DataBlock(protoDataBlock.getUuid(), protoBlock,\n                             protoDataBlock.getSize());\n    }\n\n    /**\n     * Serialize this DataBlock into a protobuf.\n     *\n     * @return Block protocol buffer containing this DataBlock.\n     */\n    @Override\n    ByteIntervalOuterClass.Block.Builder toProtobuf() {\n        // The protoBlock is in ByteInterval outer class, and it gets a data\n        // block added to it with the setData() method. So first create the\n        // protoBlock, then create the protoDataBlock and add it to the\n        // protoBlock.\n        ByteIntervalOuterClass.Block.Builder protoBlock =\n            ByteIntervalOuterClass.Block.newBuilder();\n\n        DataBlockOuterClass.DataBlock.Builder protoDataBlock =\n            DataBlockOuterClass.DataBlock.newBuilder();\n        protoDataBlock.setUuid(Util.uuidToByteString(this.getUuid()));\n        protoDataBlock.setSize(this.getSize());\n        protoBlock.setOffset(this.getOffset());\n        protoBlock.setData(protoDataBlock);\n        return protoBlock;\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/Edge.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.proto.CFGOuterClass;\nimport java.io.IOException;\nimport java.util.UUID;\n\n/**\n * A CFG Edge represents an edge in the interprocedural control flow graph\n * (CFG).\n */\npublic class Edge {\n\n    /**\n     * Indicates the type of control flow transfer indicated by this edge.\n     */\n    public enum EdgeType {\n        Branch,\n        Call,\n        Fallthrough,\n        Return,\n        Syscall,\n        Sysret,\n        Unlabelled\n    }\n\n    private UUID sourceUuid;\n    private UUID targetUuid;\n    private EdgeType edgeType;\n    private boolean edgeLabelConditional;\n    private boolean edgeLabelDirect;\n\n    /**\n     * Class constructor for an Edge from a protobuf edge.\n     * @param  protoEdge  The edge as serialized into a protocol buffer.\n     */\n    public Edge(CFGOuterClass.Edge protoEdge) throws IOException {\n        this.setSourceUuid(Util.byteStringToUuid(protoEdge.getSourceUuid()));\n        this.setTargetUuid(Util.byteStringToUuid(protoEdge.getTargetUuid()));\n        if (protoEdge.hasLabel()) {\n            CFGOuterClass.EdgeLabel protoEdgeLabel = protoEdge.getLabel();\n            this.edgeType = EdgeType.values()[protoEdgeLabel.getTypeValue()];\n            this.setEdgeLabelConditional(protoEdgeLabel.getConditional());\n            this.setEdgeLabelDirect(protoEdgeLabel.getDirect());\n        } else {\n            this.edgeType = EdgeType.Unlabelled;\n        }\n    }\n\n    /**\n     * Class constructor for an Edge.\n     * @param  sourceUuid  UUID of the source node.\n     * @param  targetUuid  UUID of the target node.\n     * @param  edgeType  The {@link EdgeType}.\n     * @param  isConditional  True if the edge id conditional.\n     * @param  isDirect  True if the edge is direct.\n     */\n    public Edge(UUID sourceUuid, UUID targetUuid, EdgeType edgeType,\n                boolean isConditional, boolean isDirect) {\n        this.setSourceUuid(sourceUuid);\n        this.setTargetUuid(targetUuid);\n        this.edgeType = edgeType;\n        this.edgeLabelConditional = isConditional;\n        this.edgeLabelDirect = isDirect;\n    }\n\n    /**\n     * Get the source node of an {@link Edge}.\n     *\n     * @return  The edge source node (UUID).\n     */\n    public UUID getSourceUuid() { return this.sourceUuid; }\n\n    /**\n     * Set the source node of an {@link Edge}.\n     *\n     * @param sourceUuid  The edge source node (UUID).\n     */\n    public void setSourceUuid(UUID sourceUuid) { this.sourceUuid = sourceUuid; }\n\n    /**\n     * Get the target node of an {@link Edge}.\n     *\n     * @return  The edge target node (UUID).\n     */\n    public UUID getTargetUuid() { return this.targetUuid; }\n\n    /**\n     * Set the target node of an {@link Edge}.\n     *\n     * @param targetUuid  The edge target node (UUID).\n     */\n    public void setTargetUuid(UUID targetUuid) { this.targetUuid = targetUuid; }\n\n    /**\n     * Get the {@link EdgeType} of an {@link Edge}.\n     *\n     * @return  The edge type.\n     */\n    public EdgeType getEdgeType() { return this.edgeType; }\n\n    /**\n     * Set the {@link EdgeType} of an {@link Edge}.\n     *\n     * @param edgeType  The edge type.\n     */\n    public void setEdgeType(EdgeType edgeType) { this.edgeType = edgeType; }\n\n    /**\n     * Whether an {@link Edge}.\n     *\n     * @return  True if the edge is conditional.\n     */\n    public boolean isConditional() { return this.edgeLabelConditional; }\n\n    /**\n     * Set whether an {@link Edge} is conditional or not.\n     *\n     * @param conditional  True if the edge is conditional.\n     */\n    public void setEdgeLabelConditional(boolean conditional) {\n        this.edgeLabelConditional = conditional;\n    }\n\n    /**\n     * Whether an {@link Edge}.\n     *\n     * @return  True if the edge is direct.\n     */\n    public boolean isDirect() { return this.edgeLabelDirect; }\n\n    /**\n     * Set the name of a {@link Edge}.\n     *\n     * @param direct  True if the edge is direct.\n     */\n    public void setEdgeLabelDirect(boolean direct) {\n        this.edgeLabelDirect = direct;\n    }\n\n    /**\n     * De-serialize a {@link Edge} from a protobuf .\n     *\n     * @param  protoEdge  The edge as serialized into a protocol buffer.\n     * @return An initialized Edge.\n     */\n    public static Edge fromProtobuf(CFGOuterClass.Edge protoEdge)\n        throws IOException {\n        return new Edge(protoEdge);\n    }\n\n    /**\n     * Serialize this {@link Edge} into a protobuf.\n     *\n     * @return edge protocol buffer.\n     */\n    public CFGOuterClass.Edge.Builder toProtobuf() {\n        CFGOuterClass.Edge.Builder protoEdge = CFGOuterClass.Edge.newBuilder();\n        if (this.edgeType == EdgeType.Unlabelled) {\n            protoEdge.clearLabel();\n        } else {\n            CFGOuterClass.EdgeLabel.Builder protoEdgeLabel =\n                CFGOuterClass.EdgeLabel.newBuilder();\n            protoEdgeLabel.setTypeValue(this.edgeType.ordinal());\n            protoEdgeLabel.setConditional(this.edgeLabelConditional);\n            protoEdgeLabel.setDirect(this.edgeLabelDirect);\n            protoEdge.setLabel(protoEdgeLabel);\n        }\n        protoEdge.setSourceUuid(Util.uuidToByteString(this.sourceUuid));\n        protoEdge.setTargetUuid(Util.uuidToByteString(this.targetUuid));\n        return protoEdge;\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/ElfSymbolInfoTuple.java",
    "content": "package com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.tuple.Tuple5;\n\n/**\n * A tuple representing information about a {@link Symbol}.\n */\npublic class ElfSymbolInfoTuple\n    extends Tuple5<Long, String, String, String, Long> {\n    /**\n     * Constructor.\n     *\n     * @param size The size of the {@link Symbol}.\n     * @param type The type of the {@link Symbol}.\n     * @param binding The binding type of the {@link Symbol}.\n     * @param visibility What visibility level the {@link Symbol} has.\n     * @param secIndex The index of the section the {@link Symbol} resides in.\n     */\n    public ElfSymbolInfoTuple(Long size, String type, String binding,\n                              String visibility, Long secIndex) {\n        super(size, type, binding, visibility, secIndex);\n    }\n\n    /**\n     * Get the size.\n     */\n    public Long getSize() { return this.get0(); }\n\n    /**\n     * Get the type.\n     */\n    public String getType() { return this.get1(); }\n\n    /**\n     * Get the binding type.\n     */\n    public String getBinding() { return this.get2(); }\n\n    /**\n     * Get the visibility level.\n     */\n    public String getVisibility() { return this.get3(); }\n\n    /**\n     * Get the section index.\n     */\n    public Long getSecIndex() { return this.get4(); }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/ElfSymbolVersionsTable.java",
    "content": "package com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.tuple.Tuple2;\nimport com.grammatech.gtirb.tuple.Tuple3;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\n/**\n * AuxData table for storing information about symbol versions in ELF files.\n */\npublic class ElfSymbolVersionsTable\n    extends Tuple3<Map<Short, ElfSymbolVersionsTable.SymVerDef>,\n                   Map<String, Map<Short, String>>,\n                   Map<UUID, ElfSymbolVersionsTable.SymVerEntry>> {\n\n    /**\n     * A tuple for storing version strings and verdef flags.\n     */\n    public static class SymVerDef extends Tuple2<List<String>, Short> {\n        /**\n         * Constructor.\n         *\n         * @param versions The list of version strings for a version id.\n         * @param verdef Verdef flag associated with a version id.\n         */\n        public SymVerDef(List<String> versions, Short verdef) {\n            super(versions, verdef);\n        }\n\n        /**\n         * Get the list of version strings.\n         */\n        public List<String> getVersions() { return this.get0(); }\n\n        /**\n         * Get the verdef flag.\n         */\n        public Short getVerdef() { return this.get1(); }\n    }\n\n    /**\n     * A tuple for storing symbol version entries.\n     */\n    public static class SymVerEntry extends Tuple2<Short, Boolean> {\n        /**\n         * Constructor.\n         *\n         * @param verId The version id for the entry.\n         * @param hidden Flag indicating if the symbol is hidden.\n         */\n        public SymVerEntry(Short verId, Boolean hidden) {\n            super(verId, hidden);\n        }\n\n        /**\n         * Get the version id.\n         */\n        public Short getVerId() { return this.get0(); }\n\n        /**\n         * True if the symbol is hidden\n         */\n        public Boolean isHidden() { return this.get1(); }\n    }\n\n    /**\n     * Constructor.\n     *\n     * @param symVerDefMap A map of version ids to version definitions.\n     * @param symVerNeededMap A map of dynamic library names to maps of symbol\n     *     versions they need.\n     * @param symVerEntriesMap A map of {@link Symbol} UUIDs to version ids.\n     */\n    public ElfSymbolVersionsTable(\n        Map<Short, ElfSymbolVersionsTable.SymVerDef> symVerDefMap,\n        Map<String, Map<Short, String>> symVerNeededMap,\n        Map<UUID, ElfSymbolVersionsTable.SymVerEntry> symVerEntriesMap) {\n        super(symVerDefMap, symVerNeededMap, symVerEntriesMap);\n    }\n\n    /**\n     * Get the symbol version definition map.\n     */\n    public Map<Short, ElfSymbolVersionsTable.SymVerDef> getSymVerDefMap() {\n        return this.get0();\n    }\n\n    /**\n     * Get the map of versions needed by dynamic libraries.\n     */\n    public Map<String, Map<Short, String>> getVerNeededMap() {\n        return this.get1();\n    }\n\n    /**\n     * Get the symbol version entries map.\n     */\n    public Map<UUID, ElfSymbolVersionsTable.SymVerEntry> getSymVerEntriesMap() {\n        return this.get2();\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/IR.java",
    "content": "/*\n *  Copyright (C) 2020-2023 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.Module;\nimport com.grammatech.gtirb.proto.IROuterClass;\nimport com.grammatech.gtirb.proto.ModuleOuterClass;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Optional;\n\n/**\n * A complete internal representation. IR describes the internal representation\n * of a software artifact.\n */\npublic class IR extends AuxDataContainer {\n\n    private List<Module> modules;\n    private CFG cfg;\n    private int version; // This is the protobuf version from the protoIr\n\n    static final private byte[] GTIRB_MAGIC_CHARS =\n        \"GTIRB\".getBytes(Charset.forName(\"ASCII\"));\n    static final private int GTIRB_MAGIC_LENGTH = 5;\n\n    /**\n     * Default class constructor for IR.\n     */\n    public IR() {\n        super();\n        this.modules = new ArrayList<Module>();\n    }\n\n    /**\n     * Class constructor for IR from an IR protobuf.\n     * @param  protoIr  The {@link IR} as serialized into a protocol buffer.\n     */\n    private IR(IROuterClass.IR protoIr) throws IOException {\n        super(protoIr.getUuid(), protoIr.getAuxDataMap());\n    }\n\n    /**\n     * Load IR from protobuf.\n     *\n     * @return  The {@link IR} loaded from the protobuf.\n     */\n    private static IR loadProtobuf(IROuterClass.IR protoIr) throws IOException {\n        // If no protobuf, can't load it.\n        if (protoIr == null)\n            return null;\n        IR ir = new IR(protoIr);\n        ir.version = protoIr.getVersion();\n        // Import the modules\n        ir.modules = new ArrayList<Module>();\n        for (ModuleOuterClass.Module protoModule : protoIr.getModulesList()) {\n            Module module = Module.fromProtobuf(protoModule);\n            ir.modules.add(module);\n        }\n        // Import the CFG\n        ir.cfg = new CFG(protoIr.getCfg());\n        return ir;\n    }\n\n    /**\n     * Load IR from a protobuf file stream.\n     *\n     * @return  IR if load is successful, null otherwise.\n     */\n    public static IR loadFile(InputStream fileIn) {\n        byte[] magic = new byte[GTIRB_MAGIC_LENGTH];\n        try {\n            // Magic signature\n            // Bytes 0-4 contain the ASCII characters: GTIRB.\n            // Bytes 5-6 are considered reserved for future use and should be 0.\n            // Byte 7 contains the GTIRB protobuf spec version in use.\n            int bytes_read = fileIn.read(magic);\n            if (bytes_read != GTIRB_MAGIC_LENGTH ||\n                !Arrays.equals(magic, GTIRB_MAGIC_CHARS)) {\n                return null;\n            }\n            fileIn.skip(2);\n            int ver = fileIn.read();\n            if (ver != Version.gtirbProtobufVersion) {\n                return null;\n            }\n        } catch (IOException ie) {\n            return null;\n        }\n\n        IROuterClass.IR protoIr;\n        try {\n            protoIr = IROuterClass.IR.parseFrom(fileIn);\n        } catch (FileNotFoundException fe) {\n            return null;\n        } catch (IOException ie) {\n            return null;\n        }\n        try {\n            IR ir = IR.loadProtobuf(protoIr);\n            return ir;\n        } catch (IOException ie) {\n            return null;\n        }\n    }\n\n    /**\n     * Load IR from a protobuf file.\n     *\n     * @return  IR if load is successful, null otherwise.\n     */\n    public static IR loadFile(String fileInName) {\n        try {\n            File fileIn = new File(fileInName);\n            FileInputStream fileInputStream = new FileInputStream(fileIn);\n            return loadFile(fileInputStream);\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    /**\n     * Get the list of modules belonging to this {@link IR}.\n     *\n     * @return  An unmodifiable {@link Module} list of all the\n     * modules in this {@link IR}. Any attempt to remove an element of\n     * this list will throw an UnsupportedOperationException.\n     */\n    public List<Module> getModules() {\n        return Collections.unmodifiableList(this.modules);\n    }\n\n    /**\n     * Find modules by name.\n     *\n     * @return A list of all {@link Module} in this {@link IR} that have a\n     * matching name.\n     */\n    public List<Module> findModules(String name) {\n        List<Module> modulesNamed = new ArrayList<Module>();\n        for (Module module : this.modules) {\n            if (name.equals(module.getName())) {\n                modulesNamed.add(module);\n            }\n        }\n        return modulesNamed;\n    }\n\n    /**\n     * Add a module to this {@link IR}.\n     *\n     * @param module  {@link Module} to add.\n     */\n    public void addModule(Module module) {\n        this.modules.add(module);\n        module.setIr(Optional.of(this));\n    }\n\n    /**\n     * Add a list of modules to this {@link IR}.\n     *\n     * @param modules  Modules to add.\n     */\n    public void addModules(List<Module> modules) {\n        for (Module module : modules) {\n            this.addModule(module);\n        }\n    }\n\n    /**\n     * Remove a module from this {@link IR}.\n     *\n     * @param module  {@link Module} to remove.\n     * @return boolean true if the IR contained the module and it was removed.\n     */\n    public boolean removeModule(Module module) {\n        if (module.getIr().isPresent() && module.getIr().get() == this &&\n            this.modules.remove(module)) {\n            module.setIr(Optional.empty());\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Get the CFG belonging to this {@link IR}.\n     *\n     * @return  A {@link CFG}.\n     */\n    public CFG getCfg() { return this.cfg; }\n\n    /**\n     * Set the CFG belonging to this {@link IR}.\n     *\n     * @param cfg  A {@link CFG}.\n     */\n    public void setCfg(CFG cfg) { this.cfg = cfg; }\n\n    /**\n     * Get the protobuf version of this {@link IR}.\n     *\n     * @return Protobuf version.\n     */\n    public int getVersion() { return this.version; }\n\n    /**\n     * Set the protobuf version of this {@link IR}.\n     *\n     * @param version Protobuf version.\n     */\n    public void setVersion(int version) { this.version = version; }\n\n    /**\n     * Serialize this IR into a protobuf.\n     *\n     * @return IR protocol buffer.\n     */\n    public IROuterClass.IR.Builder toProtobuf() {\n        IROuterClass.IR.Builder protoIr = IROuterClass.IR.newBuilder();\n        protoIr.setUuid(Util.uuidToByteString(this.getUuid()));\n        protoIr.setVersion(Version.gtirbProtobufVersion);\n        // Add modules\n        for (Module module : this.modules) {\n            ModuleOuterClass.Module.Builder protoModule = module.toProtobuf();\n            protoIr.addModules(protoModule);\n        }\n        // Add CFG\n        if (this.cfg != null) {\n            protoIr.setCfg(this.cfg.toProtobuf());\n        }\n        return protoIr;\n    }\n\n    /**\n     * Save IR to a protobuf file stream.\n     */\n    public void saveFile(OutputStream fileOut) throws IOException {\n        fileOut.write(GTIRB_MAGIC_CHARS);\n        fileOut.write(0);\n        fileOut.write(0);\n        fileOut.write(Version.gtirbProtobufVersion);\n\n        IROuterClass.IR protoIr = this.toProtobuf().build();\n        protoIr.writeTo(fileOut);\n    }\n\n    /**\n     * Save IR to a protobuf file.\n     */\n    public void saveFile(String fileOutName) throws IOException {\n        File fileOut = new File(fileOutName);\n        FileOutputStream fileOutputStream = new FileOutputStream(fileOut);\n        this.saveFile(fileOutputStream);\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/Module.java",
    "content": "/*\n *  Copyright (C) 2020-2023 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.proto.ModuleOuterClass;\nimport com.grammatech.gtirb.proto.ProxyBlockOuterClass;\nimport com.grammatech.gtirb.proto.SectionOuterClass;\nimport com.grammatech.gtirb.proto.SymbolOuterClass;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.UUID;\n\n/**\n * Represents a single binary (library or executable),\n */\npublic class Module extends AuxDataContainer {\n\n    /**\n     * \tIdentifies an executable file format.\n     */\n    public enum FileFormat {\n        Format_Undefined,\n        COFF,\n        ELF,\n        PE,\n        IdaProDb32,\n        IdaProDb64,\n        XCOFF,\n        MACHO,\n        RAW\n    }\n\n    /**\n     * \tIdentifies an instruction set architecture.\n     */\n    public enum ISA {\n        ISA_Undefined,\n        IA32,\n        PPC32,\n        X64,\n        ARM,\n        ValidButUnsupported,\n        PPC64,\n        ARM64,\n        MIPS32,\n        MIPS64\n    }\n\n    /**\n     * \tIdentifies a byte ordering (endianness).\n     */\n    public enum ByteOrder { ByteOrder_Undefined, BigEndian, LittleEndian }\n\n    private Optional<IR> ir;\n    private String binaryPath;\n    private long preferredAddr;\n    private long rebaseDelta;\n    private FileFormat fileFormat;\n    private ISA isa;\n    private String name;\n    private TreeMap<Long, List<Section>> sectionTree;\n    private List<Symbol> symbolList;\n    private List<ProxyBlock> proxyBlockList;\n    private CodeBlock entryPoint;\n    private ByteOrder byteOrder;\n\n    /**\n     * Class constructor for a Module from a protobuf module.\n     * @param  protoModule   The module as serialized into a protocol buffer.\n     */\n    Module(ModuleOuterClass.Module protoModule) throws IOException {\n        super(protoModule.getUuid(), protoModule.getAuxDataMap());\n        this.ir = Optional.empty();\n        this.binaryPath = protoModule.getBinaryPath();\n        this.preferredAddr = protoModule.getPreferredAddr();\n        this.rebaseDelta = protoModule.getRebaseDelta();\n        this.fileFormat = FileFormat.values()[protoModule.getFileFormatValue()];\n        this.isa = ISA.values()[protoModule.getIsaValue()];\n        this.name = protoModule.getName();\n        this.byteOrder = ByteOrder.values()[protoModule.getByteOrderValue()];\n\n        initializeSectionList(protoModule.getSectionsList());\n        initializeSymbolList(protoModule.getSymbolsList());\n        initializeProxyBlockList(protoModule.getProxiesList());\n\n        // Sections must be initialized before looking up the entry point\n        UUID entryUUID = Util.byteStringToUuid(protoModule.getEntryPoint());\n        Node entryNode = Node.getByUuid(entryUUID);\n        if (entryNode instanceof CodeBlock)\n            this.entryPoint = (CodeBlock)entryNode;\n    }\n\n    /**\n     * Class Constructor.\n     * @param  binaryPath       The binary path of this Module.\n     * @param  preferredAddr    The preferred address of this Module.\n     * @param  rebaseDelta      The rebase delta of this Module.\n     * @param  fileFormat       The file format of this Module.\n     * @param  isa              The ISA of this Module.\n     * @param  name             The name of this Module.\n     * @param  sections         A list of Sections belonging to this Module.\n     * @param  symbols          A list of Symbols belonging to this Module.\n     * @param  proxyBlocks      A list of ProxyBlocks belonging to this Module.\n     * @param  entryPoint       The entry point of this module or null.\n     */\n    public Module(String binaryPath, long preferredAddr, long rebaseDelta,\n                  FileFormat fileFormat, ISA isa, String name,\n                  List<Section> sections, List<Symbol> symbols,\n                  List<ProxyBlock> proxyBlocks, CodeBlock entryPoint) {\n        super();\n        this.ir = Optional.empty();\n        this.binaryPath = binaryPath;\n        this.preferredAddr = preferredAddr;\n        this.rebaseDelta = rebaseDelta;\n        this.fileFormat = fileFormat;\n        this.isa = isa;\n        this.name = name;\n        this.entryPoint = entryPoint;\n        this.setSymbols(symbols);\n        this.setProxyBlocks(proxyBlocks);\n        this.setSections(sections);\n    }\n\n    /**\n     * Class Constructor for a minimal module with no sections, symbols, or\n     * proxyBlocks.\n     * @param  binaryPath       The binary path of this Module.\n     * @param  preferredAddr    The preferred address of this Module.\n     * @param  rebaseDelta      The rebase delta of this Module.\n     * @param  fileFormat       The file format of this Module.\n     * @param  isa              The ISA of this Module.\n     * @param  name             The name of this Module.\n     */\n    public Module(String binaryPath, long preferredAddr, long rebaseDelta,\n                  FileFormat fileFormat, ISA isa, String name) {\n        super();\n        this.ir = Optional.empty();\n        this.binaryPath = binaryPath;\n        this.preferredAddr = preferredAddr;\n        this.rebaseDelta = rebaseDelta;\n        this.fileFormat = fileFormat;\n        this.isa = isa;\n        this.name = name;\n        this.symbolList = new ArrayList<Symbol>();\n        this.sectionTree = new TreeMap<Long, List<Section>>();\n        this.proxyBlockList = new ArrayList<ProxyBlock>();\n        this.entryPoint = null;\n    }\n\n    /**\n     * Get the {@link IR} this Module belongs to.\n     *\n     * @return  An Optional that contains the IR this module belongs to,\n     * or empty if it does not belong to an IR.\n     */\n    public Optional<IR> getIr() { return this.ir; }\n\n    /**\n     * Set the {@link IR} this Module belongs to.\n     *\n     * @param  An Optional that contains the IR this module will belongs\n     * to, or empty if it should not belong to an IR.\n     */\n    void setIr(Optional<IR> ir) { this.ir = ir; }\n\n    /**\n     * Get the location of the corresponding binary on disk.\n     *\n     * @return  The path to the corresponding binary on disk.\n     */\n    public String getBinaryPath() { return this.binaryPath; }\n\n    /**\n     * Set the location of the corresponding binary on disk.\n     *\n     * This is for informational purposes only and will not be\n     * used to open the image, so it does not need to be the path\n     * of an existing file.\n     *\n     * @param binaryPath    The path name to use.\n     */\n    public void setBinaryPath(String binaryPath) {\n        this.binaryPath = binaryPath;\n    }\n\n    /**\n     * Get the preferred address for loading this module.\n     *\n     * @return  The preferred address.\n     */\n    public long getPreferredAddr() { return this.preferredAddr; }\n\n    /**\n     * Set the preferred address for loading this module.\n     *\n     * @param preferredAddr  The module preferred address.\n     */\n    public void setPreferredAddr(long preferredAddr) {\n        this.preferredAddr = preferredAddr;\n    }\n\n    /**\n     * Get the difference between this module's preferred address and the\n     * address where it was actually loaded.\n     *\n     * @return  The rebase delta.\n     */\n    public long getRebaseDelta() { return this.rebaseDelta; }\n\n    /**\n     * Set the difference between this module's preferred address and the\n     * address where it was actually loaded.\n     *\n     * @param rebaseDelta    The module rebase delta.\n     */\n    public void setRebaseDelta(long rebaseDelta) {\n        this.rebaseDelta = rebaseDelta;\n    }\n\n    /**\n     * Get the format of the binary pointed to by getBinaryPath().\n     *\n     * @return  The format of the binary associated with this module, as a\n     * {@link FileFormat} enumerator.\n     */\n    public FileFormat getFileFormat() { return this.fileFormat; }\n\n    /**\n     * Set the file format of this Module.\n     *\n     * @param fileFormat    The module file format.\n     */\n    public void setFileFormat(FileFormat fileFormat) {\n        this.fileFormat = fileFormat;\n    }\n\n    /**\n     * Get the ISA of the instructions in this Module.\n     *\n     * @return  The module {@link ISA}.\n     */\n    public ISA getIsa() { return this.isa; }\n\n    /**\n     * Set the ISA of the instructions in this Module.\n     *\n     * @param isa    The module {@link ISA}.\n     */\n    public void setIsa(ISA isa) { this.isa = isa; }\n\n    /**\n     * Get the name of this Module.\n     *\n     * @return  The module name.\n     */\n    public String getName() { return this.name; }\n\n    /**\n     * Set the name of this Module.\n     *\n     * @param name    The module name.\n     */\n    public void setName(String name) { this.name = name; }\n\n    /**\n     * Get the sections of this Module.\n     *\n     * @return  An unmodifiable {@link Section} list of all the\n     * sections in this {@link Module}.\n     */\n    public List<Section> getSections() {\n        List<Section> sectionList = new ArrayList<Section>();\n        for (List<Section> entry : this.sectionTree.values()) {\n            sectionList.addAll(entry);\n        }\n        return Collections.unmodifiableList(sectionList);\n    }\n\n    /**\n     * Set the section list of this Module.\n     *\n     * @param sectionList    The module section list.\n     */\n    private void setSections(List<Section> sectionList) {\n        if (sectionTree == null) {\n            sectionTree = new TreeMap<Long, List<Section>>();\n        } else {\n            sectionTree.clear();\n        }\n        for (Section section : sectionList) {\n            TreeListUtils.insertItem(section, sectionTree);\n            section.setModule(Optional.of(this));\n        }\n    }\n\n    /**\n     * Add a section to this Module.\n     *\n     * @param section  The {@link Section} to add.\n     */\n    public void addSection(Section section) {\n        TreeListUtils.insertItem(section, this.sectionTree);\n        section.setModule(Optional.of(this));\n    }\n\n    /**\n     * Remove a section from this Module.\n     *\n     * @param section  The {@link Section} to remove.\n     * @return boolean true if the Module contained the section, and it was\n     * removed.\n     */\n    public boolean removeSection(Section section) {\n        if (section.getModule().isPresent() &&\n            section.getModule().get() == this) {\n            TreeListUtils.removeItem(section, this.sectionTree);\n            section.setModule(Optional.empty());\n            return true;\n        } else\n            return false;\n    }\n\n    /**\n     * Get the symbols of this Module.\n     *\n     * @return  An unmodifiable {@link Symbol} list of all the\n     * symbols in this {@link Module}.\n     */\n    public List<Symbol> getSymbols() {\n        return Collections.unmodifiableList(this.symbolList);\n    }\n\n    /**\n     * Add a symbol to this Module.\n     *\n     * @param symbol  The {@link Symbol} to add to this {@link Module}.\n     */\n    public void addSymbol(Symbol symbol) {\n        this.symbolList.add(symbol);\n        symbol.setModule(Optional.of(this));\n    }\n\n    /**\n     * Remove a symbol from this Module.\n     *\n     * @param symbol  The {@link Symbol} to remove from this {@link Module}.\n     * @return boolean true if the Module contained the symbol, and it was\n     * removed.\n     */\n    public boolean removeSymbol(Symbol symbol) {\n        if (symbol.getModule().isPresent() &&\n            symbol.getModule().get() == this &&\n            this.symbolList.remove(symbol)) {\n            symbol.setModule(Optional.empty());\n            return true;\n        } else\n            return false;\n    }\n\n    /**\n     * Set the symbol list of this Module.\n     *\n     * @param symbolList    The module symbol list.\n     */\n    private void setSymbols(List<Symbol> symbolList) {\n        if (this.symbolList == null) {\n            this.symbolList = new ArrayList<Symbol>();\n        }\n        for (Symbol symbol : symbolList)\n            this.addSymbol(symbol);\n    }\n\n    /**\n     * Get a list of proxy blocks in this Module.\n     *\n     * @return  An unmodifiable {@link ProxyBlock} list of all the\n     * proxy blocks in this {@link Module}.\n     */\n    public List<ProxyBlock> getProxyBlocks() {\n        return Collections.unmodifiableList(this.proxyBlockList);\n    }\n\n    /**\n     * Add a proxy block to this Module.\n     *\n     * @param proxyBlock    The {@link ProxyBlock} to add to this {@link\n     * Module}.\n     */\n    public void addProxyBlock(ProxyBlock proxyBlock) {\n        this.proxyBlockList.add(proxyBlock);\n        proxyBlock.setModule(Optional.of(this));\n    }\n\n    /**\n     * Remove a proxy block from this Module.\n     *\n     * @param proxyBlock    The {@link ProxyBlock} to remove from this {@link\n     * Module}.\n     * @return boolean true if the Module contained the proxy block, and it was\n     * removed.\n     */\n    public boolean removeProxyBlock(ProxyBlock proxyBlock) {\n        if (proxyBlock.getModule().isPresent() &&\n            proxyBlock.getModule().get() == this &&\n            this.proxyBlockList.remove(proxyBlock)) {\n            proxyBlock.setModule(Optional.empty());\n            return true;\n        } else\n            return false;\n    }\n\n    /**\n     * Set the proxy block list of this Module.\n     *\n     * @param proxyBlockList    The module proxyBlock list.\n     */\n    private void setProxyBlocks(List<ProxyBlock> proxyBlockList) {\n        if (this.proxyBlockList == null) {\n            this.proxyBlockList = new ArrayList<ProxyBlock>();\n        }\n        for (ProxyBlock proxyBlock : proxyBlockList)\n            this.addProxyBlock(proxyBlock);\n    }\n\n    /**\n     * Get the entry point of this module, or null if not present.\n     *\n     * @return  The module entry point (a code block) or null if no entry is\n     * point has been designated.\n     */\n    public CodeBlock getEntryPoint() { return entryPoint; }\n\n    /**\n     * Set the entry point of this Module.\n     *\n     * @param entryCodeBlock    The module entry point (a {@link CodeBlock}).\n     */\n    public void setEntryPoint(CodeBlock entryCodeBlock) {\n        this.entryPoint = entryCodeBlock;\n    }\n\n    /**\n     * Get the ByteOrder of this Module.\n     *\n     * @return  The module byte order (endianness).\n     */\n    public ByteOrder getByteOrder() { return this.byteOrder; }\n\n    /**\n     * Set the byte order of this Module.\n     *\n     * @param  byteOrder    The module byte order (endianness).\n     */\n    public void setByteOrder(ByteOrder byteOrder) {\n        this.byteOrder = byteOrder;\n    }\n\n    /**\n     * Initialize this module's sections from section protocol buffers\n     *\n     * When creating a Module from a protocol buffer module, use this method to\n     * initialize the sections belonging to this module from the protocol\n     * buffers of those sections.\n     *\n     */\n    private void\n    initializeSectionList(List<SectionOuterClass.Section> protoSectionList)\n        throws IOException {\n        this.sectionTree = new TreeMap<>();\n        // For each section, add to sectionList in this class\n        for (SectionOuterClass.Section protoSection : protoSectionList) {\n            Section newSection = Section.fromProtobuf(protoSection);\n            this.addSection(newSection);\n        }\n    }\n\n    /**\n     * Initialize this module's symbols from symbol protocol buffers\n     *\n     * When creating a Module from a protocol buffer module, use this method to\n     * initialize the symbols belonging to this module from the protocol\n     * buffers of those symbols.\n     *\n     */\n    private void\n    initializeSymbolList(List<SymbolOuterClass.Symbol> protoSymbolList)\n        throws IOException {\n        this.symbolList = new ArrayList<Symbol>();\n        // For each symbol, add to symbolList in this class\n        for (SymbolOuterClass.Symbol protoSymbol : protoSymbolList) {\n            Symbol newSymbol = Symbol.fromProtobuf(protoSymbol);\n            this.addSymbol(newSymbol);\n        }\n    }\n\n    /**\n     * Initialize this module's proxy blocks from proxy block protocol buffers\n     *\n     * When creating a Module from a protocol buffer module, use this method to\n     * initialize the proxy blocks belonging to this module from the protocol\n     * buffers of those proxy blocks.\n     *\n     */\n    private void initializeProxyBlockList(\n        List<ProxyBlockOuterClass.ProxyBlock> protoProxyBlockList)\n        throws IOException {\n        this.proxyBlockList = new ArrayList<ProxyBlock>();\n        // For each proxy block, add to proxyBlockList in this class\n        for (ProxyBlockOuterClass.ProxyBlock protoProxyBlock :\n             protoProxyBlockList) {\n            ProxyBlock newProxyBlock =\n                ProxyBlock.fromProtobuf(protoProxyBlock, this);\n            this.addProxyBlock(newProxyBlock);\n        }\n    }\n\n    /**\n     * Find all the sections that have bytes that intersect with the address\n     * specified.\n     *\n     * @param address      The address to look for.\n     * @return             A list of {@link Section} objects that intersect this\n     * address, or empty list if none.\n     */\n    public List<Section> findSectionsOn(long address) {\n        return TreeListUtils.getItemsIntersectingIndex(address,\n                                                       this.sectionTree);\n    }\n\n    /**\n     * Find all the sections that have bytes that intersect with the address\n     * range specified.\n     *\n     * @param startAddress      The beginning of the address range to look for.\n     * (inclusive)\n     * @param endAddress        The last address of the address range to look\n     * for. (exclusive)\n     * @return                  A list of {@link Section} objects that intersect\n     * this address range, or empty list if none.\n     */\n    public List<Section> findSectionsOn(long startAddress, long endAddress) {\n        return TreeListUtils.getItemsIntersectingIndexRange(\n            startAddress, endAddress, this.sectionTree);\n    }\n\n    /**\n     * Find all the sections that start at an address.\n     *\n     * @param address      The address to look for.\n     * @return             A list of {@link Section} objects that start at the\n     * address.\n     */\n    public List<Section> findSectionsAt(long address) {\n        return TreeListUtils.getItemsAtStartIndex(address, this.sectionTree);\n    }\n\n    /**\n     * Find all the sections that start between a range of addresses.\n     *\n     * @param startAddress      The beginning of the address range to look for.\n     * (inclusive)\n     * @param endAddress        The last address in the address to look for.\n     * (exclusive)\n     * @return                  A list of {@link Section} objects that that\n     * start at this address, or null if none.\n     */\n    public List<Section> findSectionsAt(long startAddress, long endAddress) {\n        return TreeListUtils.getItemsAtStartIndexRange(startAddress, endAddress,\n                                                       this.sectionTree);\n    }\n\n    /**\n     * De-serialize this Module from a protobuf .\n     *\n     * @param  protoModule   The module as serialized into a protocol buffer.\n     * @return An initialized Module.\n     */\n    static Module fromProtobuf(ModuleOuterClass.Module protoModule)\n        throws IOException {\n        return new Module(protoModule);\n    }\n\n    /**\n     * Serialize this Module into a protobuf .\n     *\n     * @return Module protocol buffer.\n     */\n    ModuleOuterClass.Module.Builder toProtobuf() {\n        ModuleOuterClass.Module.Builder protoModule =\n            ModuleOuterClass.Module.newBuilder();\n        protoModule.setUuid(Util.uuidToByteString(this.getUuid()));\n        protoModule.setBinaryPath(this.getBinaryPath());\n        protoModule.setPreferredAddr(this.getPreferredAddr());\n        protoModule.setRebaseDelta(this.getRebaseDelta());\n        // The enums values are mapped one-to-one\n        protoModule.setFileFormatValue(this.fileFormat.ordinal());\n        protoModule.setIsaValue(this.isa.ordinal());\n        protoModule.setName(this.getName());\n        if (this.byteOrder != null) {\n            protoModule.setByteOrderValue(this.byteOrder.ordinal());\n        }\n        CodeBlock entryPoint = this.getEntryPoint();\n        if (entryPoint != null) {\n            protoModule.setEntryPoint(\n                Util.uuidToByteString(this.getEntryPoint().getUuid()));\n        }\n        // Add collections by calling toProtobuf on each item\n        for (Symbol symbol : this.symbolList)\n            protoModule.addSymbols(symbol.toProtobuf());\n        for (ProxyBlock proxyBlock : this.proxyBlockList)\n            protoModule.addProxies(proxyBlock.toProtobuf());\n        Iterator<Section> sectionIterator =\n            new TreeListUtils<Section>(this.sectionTree).iterator();\n        while (sectionIterator.hasNext()) {\n            Section section = sectionIterator.next();\n            protoModule.addSections(section.toProtobuf());\n        }\n        // Add auxData by calling toProtobuf on each type\n        // TODO: Can this be done by AuxDataContainer, itself?\n        // Doing it here, we have to access the protected member AuxDataMap\n        // from the container.\n        for (Map.Entry<String, AuxData> entry : this.auxDataMap.entrySet()) {\n            protoModule.putAuxData(entry.getKey(),\n                                   entry.getValue().toProtobuf().build());\n        }\n        return protoModule;\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/Node.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport java.lang.ref.WeakReference;\nimport java.util.HashMap;\nimport java.util.UUID;\n\n/**\n * Node is the root class for many GTIRB components.\n */\npublic class Node {\n    private final UUID uuid;\n    private static HashMap<UUID, WeakReference<Node>> uuid_cache =\n        new HashMap<UUID, WeakReference<Node>>();\n\n    /**\n     * Create a Node with a randomly generated UUID.\n     */\n    public Node() { this(UUID.randomUUID()); }\n\n    /**\n     * Create a Node with a specified UUID.\n     */\n    public Node(UUID uuid) {\n        this.uuid = uuid;\n        uuid_cache.put(uuid, new WeakReference<>(this));\n    }\n\n    /**\n     * Find a node using its UUID.\n     *\n     * @return  The node with the given UUID.\n     */\n    public static Node getByUuid(UUID uuid) {\n        WeakReference<Node> noderef = uuid_cache.get(uuid);\n        if (noderef != null)\n            return noderef.get();\n        return null;\n    }\n\n    /**\n     * Find a node of the given type by UUID.\n     *\n     * @return  The node with the given UUID.\n     */\n    public static <T extends Node> T getByUuid(UUID uuid, Class<T> type) {\n        WeakReference<Node> noderef = uuid_cache.get(uuid);\n        if (noderef != null) {\n            Node node = noderef.get();\n            if (type.isInstance(node)) {\n                return type.cast(node);\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Get the UUID of this node.\n     *\n     * @return  The UUID.\n     */\n    public UUID getUuid() { return uuid; }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/Offset.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport java.util.UUID;\n\n/**\n * An Offset describes a location inside a {@link CodeBlock} or {@link\n * DataBlock}.\n */\npublic class Offset {\n\n    private UUID elementId;\n    private long displacement;\n\n    /**\n     * Constructor\n     *\n     * @param elementId  The UUID of a {@link ByteBlock} containing the location\n     * of interest.\n     * @param displacement  The offset inside the Node to point to.\n     */\n    public Offset(UUID elementId, long displacement) {\n        this.elementId = elementId;\n        this.displacement = displacement;\n    }\n\n    /**\n     * Get the UUID of the block this {@link Offset} points to.\n     *\n     * @return  The element UUID.\n     */\n    public UUID getElementId() { return this.elementId; }\n\n    /**\n     * Get the displacement into the block this {@link Offset} points to.\n     *\n     * @return  The displacement.\n     */\n    public long getDisplacement() { return this.displacement; }\n\n    @Override\n    public boolean equals(Object o) {\n        if (o == this) {\n            return true;\n        }\n\n        if (!(o instanceof Offset)) {\n            return false;\n        }\n\n        Offset off = (Offset)o;\n        return this.elementId.equals(off.elementId) &&\n            this.displacement == off.displacement;\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/PeExportEntry.java",
    "content": "package com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.tuple.Tuple3;\n\n/**\n * A tuple storing information about a PE file export entry.\n */\npublic class PeExportEntry extends Tuple3<Long, Long, String> {\n    /**\n     * Constructor.\n     *\n     * @param address The address of the export.\n     * @param ordinal The ordinal of the export.\n     * @param name The name of the export.\n     */\n    public PeExportEntry(Long address, Long ordinal, String name) {\n        super(address, ordinal, name);\n    }\n\n    /**\n     * Get the address.\n     */\n    public Long getAddress() { return this.get0(); }\n\n    /**\n     * Get the ordinal.\n     */\n    public Long getOrdinal() { return this.get1(); }\n\n    /**\n     * Get the name.\n     */\n    public String getName() { return this.get2(); }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/PeImportEntry.java",
    "content": "package com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.tuple.Tuple4;\n\n/**\n * A tuple representing an import entry for a PE file.\n */\npublic class PeImportEntry extends Tuple4<Long, Long, String, String> {\n    /**\n     * Constructor.\n     *\n     * @param address The address of the imported symbol.\n     * @param ordinal The ordinal of the imported symbol.\n     * @param funcName The name of the imported symbol.\n     * @param libName The name of the library the symbol is imported from.\n     */\n    public PeImportEntry(Long address, Long ordinal, String funcName,\n                         String libName) {\n        super(address, ordinal, funcName, libName);\n    }\n\n    /**\n     * Get the address.\n     */\n    public Long getAddress() { return this.get0(); }\n\n    /**\n     * Get the ordinal.\n     */\n    public Long getOrdinal() { return this.get1(); }\n\n    /**\n     * Get the function name.\n     */\n    public String getFuncName() { return this.get2(); }\n\n    /**\n     * Get the library name.\n     */\n    public String getLibName() { return this.get3(); }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/PeResourceEntry.java",
    "content": "package com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.Offset;\nimport com.grammatech.gtirb.tuple.Tuple3;\nimport java.util.List;\n\n/**\n * A tuple representing a resource attached to a PE file.\n */\npublic class PeResourceEntry extends Tuple3<List<Byte>, Offset, Long> {\n    /**\n     * Constructor.\n     *\n     * @param header The resource header.\n     * @param offset Where the resource is located.\n     * @param size The size of the resource data.\n     */\n    public PeResourceEntry(List<Byte> header, Offset offset, Long size) {\n        super(header, offset, size);\n    }\n\n    /**\n     * Get the header.\n     */\n    public List<Byte> getHeader() { return this.get0(); }\n\n    /**\n     * Get the offset.\n     */\n    public Offset getOffset() { return this.get1(); }\n\n    /**\n     * Get the size.\n     */\n    public Long getSize() { return this.get2(); }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/ProbFuncName.java",
    "content": "package com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.tuple.Tuple3;\n\n/**\n * A tuple representing a probability fact associated with a function's name.\n */\npublic class ProbFuncName extends Tuple3<String, String, Float> {\n\n    /**\n     * Constructor.\n     *\n     * @param name Source-level function name.\n     * @param binaryName Binary-level function name.\n     * @param prob The probability associated with the names.\n     */\n    public ProbFuncName(String name, String binaryName, Float prob) {\n        super(name, binaryName, prob);\n    }\n\n    /**\n     * Get the source-level name.\n     */\n    public String getName() { return this.get0(); }\n\n    /**\n     * Get the binary-level name.\n     */\n    public String getBinaryName() { return this.get1(); }\n\n    /**\n     * Get the probability.\n     */\n    public Float getProbability() { return this.get2(); }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/ProxyBlock.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.proto.ProxyBlockOuterClass;\nimport java.io.IOException;\nimport java.util.Optional;\nimport java.util.UUID;\n\n/**\n * ProxyBlock is a placeholder that serves as the end point (source or target)\n * of a CfgEdge.\n */\npublic class ProxyBlock extends Node {\n\n    private Optional<Module> module;\n\n    /**\n     * Class constructor for a ProxyBlock from a protobuf section.\n     * @param  protoProxyBlock  The ProxyBlock as serialized into a protocol\n     * buffer.\n     */\n    private ProxyBlock(ProxyBlockOuterClass.ProxyBlock protoProxyBlock)\n        throws IOException {\n        super(Util.byteStringToUuid(protoProxyBlock.getUuid()));\n        this.module = Optional.empty();\n    }\n\n    /**\n     * Class Constructor.\n     */\n    public ProxyBlock() {\n        super();\n        this.module = Optional.empty();\n    }\n\n    public ProxyBlock(UUID uuid) {\n        super(uuid);\n        this.module = Optional.empty();\n    }\n\n    /**\n     * Get the {@link Module} this ProxyBlock belongs to.\n     *\n     * @return  An Optional that contains the Module this\n     * proxy block belongs to, or empty if it does not belong to a Module.\n     */\n    public Optional<Module> getModule() { return this.module; }\n\n    /**\n     * Set the Module this ProxyBlock belongs to.\n     *\n     * @param  An Optional that contains the Module this\n     * proxy block belongs to, or empty if it does not belong to a Module.\n     */\n    void setModule(Optional<Module> module) { this.module = module; }\n\n    /**\n     * De-serialize a {@link ProxyBlock} from a protobuf .\n     *\n     * @param  protoProxyBlock  The ProxyBlock as serialized into a protocol\n     * buffer.\n     * @param  module        The Module that owns this Section.\n     * @return An initialized proxy block.\n     */\n    static ProxyBlock\n    fromProtobuf(ProxyBlockOuterClass.ProxyBlock protoProxyBlock, Module module)\n        throws IOException {\n        return new ProxyBlock(protoProxyBlock);\n    }\n\n    /**\n     * Serialize this ProxyBlock into a protobuf .\n     *\n     * @return A protocol buffer containing this ProxyBlock.\n     */\n    ProxyBlockOuterClass.ProxyBlock.Builder toProtobuf() {\n        ProxyBlockOuterClass.ProxyBlock.Builder protoProxyBlock =\n            ProxyBlockOuterClass.ProxyBlock.newBuilder();\n        protoProxyBlock.setUuid(Util.uuidToByteString(this.getUuid()));\n        return protoProxyBlock;\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/Section.java",
    "content": "/*\n *  Copyright (C) 2020-2023 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.proto.ByteIntervalOuterClass;\nimport com.grammatech.gtirb.proto.SectionOuterClass;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.NoSuchElementException;\nimport java.util.Optional;\nimport java.util.OptionalLong;\nimport java.util.Set;\nimport java.util.TreeMap;\n\n/**\n * The Section class represents a named section or segment of a program file,\n * with flags that define its settings and ByteIntervals to store binary\n * information.\n */\npublic class Section extends Node implements TreeListItem {\n\n    /**\n     * Identities the flags used for a section.\n     */\n    public enum SectionFlag {\n        Undefined,\n        Readable,\n        Writable,\n        Executable,\n        Loaded,\n        Initialized,\n        ThreadLocal\n    }\n\n    private Optional<Module> module;\n    private String name;\n    private final TreeMap<Long, List<ByteInterval>> byteIntervalTree;\n    private Set<SectionFlag> sectionFlags;\n\n    /**\n     * Class constructor for a Section from a protobuf section.\n     * @param  protoSection  The section as serialized into a protocol buffer.\n     */\n    private Section(SectionOuterClass.Section protoSection) throws IOException {\n        super(Util.byteStringToUuid(protoSection.getUuid()));\n\n        this.name = protoSection.getName();\n        this.module = Optional.empty();\n\n        byteIntervalTree = new TreeMap<Long, List<ByteInterval>>();\n        List<ByteIntervalOuterClass.ByteInterval> protoByteIntervalList =\n            protoSection.getByteIntervalsList();\n        for (ByteIntervalOuterClass.ByteInterval protoByteInterval :\n             protoByteIntervalList) {\n            ByteInterval byteInterval =\n                ByteInterval.fromProtobuf(protoByteInterval);\n            this.addByteInterval(byteInterval);\n        }\n\n        this.sectionFlags = new HashSet<SectionFlag>();\n        for (Integer value : protoSection.getSectionFlagsValueList()) {\n            SectionFlag newSectionFlag = SectionFlag.values()[value];\n            this.addSectionFlag(newSectionFlag);\n        }\n    }\n\n    /**\n     * Class Constructor.\n     * @param  name            The name of this Section.\n     * @param  flags           A set of flags to apply to this Section.\n     * @param  byteIntervals   A list of ByteIntervals belonging to this\n     * Section.\n     */\n    public Section(String name, Set<SectionFlag> flags,\n                   List<ByteInterval> byteIntervals) {\n        super();\n        this.module = Optional.empty();\n        this.setName(name);\n\n        this.sectionFlags = new HashSet<SectionFlag>();\n        for (SectionFlag flag : flags)\n            this.addSectionFlag(flag);\n\n        this.byteIntervalTree = new TreeMap<Long, List<ByteInterval>>();\n        for (ByteInterval byteInterval : byteIntervals)\n            this.addByteInterval(byteInterval);\n    }\n\n    /**\n     * Get the {@link Module} this Section belongs to.\n     *\n     * @return  An Optional that contains the Module this\n     * section belongs to, or empty if it does not belong to a Module.\n     */\n    public Optional<Module> getModule() { return this.module; }\n\n    /**\n     * Set the Module this Section belongs to.\n     *\n     * @param  module An Optional that contains the Module this\n     * section belongs to, or empty if it does not belong to a Module.\n     */\n    public void setModule(Optional<Module> module) { this.module = module; }\n\n    /**\n     * Get the name of a {@link Section Section}.\n     *\n     * @return  The section name.\n     */\n    public String getName() { return this.name; }\n\n    /**\n     * Set the name of this Section.\n     *\n     * @param name    The section name.\n     */\n    public void setName(String name) { this.name = name; }\n\n    /**\n     * Get a ByteInterval iterator.\n     *\n     * @return  An iterator for iterating through all the ByteIntervals in this\n     * Section.\n     */\n    private Iterator<ByteInterval> getByteIntervalIterator() {\n        TreeListUtils<ByteInterval> byteIntervalTreeIterator =\n            new TreeListUtils<ByteInterval>(this.byteIntervalTree);\n        return byteIntervalTreeIterator.iterator();\n    }\n\n    /**\n     * Get the ByteIntervals belonging to this Section.\n     *\n     * @return  An unmodifiable {@link ByteInterval} list of all the\n     * byte intervals in this {@link Section}.\n     */\n    public List<ByteInterval> getByteIntervals() {\n        List<ByteInterval> resultList = new ArrayList<ByteInterval>();\n        Iterator<ByteInterval> byteIntervals = this.getByteIntervalIterator();\n        while (byteIntervals.hasNext())\n            resultList.add(byteIntervals.next());\n        return Collections.unmodifiableList(resultList);\n    }\n\n    /**\n     * Add a ByteInterval.\n     *\n     * @param byteInterval A {@link ByteInterval} to add to this Section.\n     */\n    public void addByteInterval(ByteInterval byteInterval) {\n        TreeListUtils.insertItem(byteInterval, byteIntervalTree);\n        byteInterval.setSection(Optional.of(this));\n    }\n\n    /**\n     * Remove a ByteInterval.\n     *\n     * @param byteInterval A {@link ByteInterval} to remove from this Section.\n     * @return boolean true if this section contained the byte interval, and it\n     * was removed.\n     */\n    public boolean removeByteInterval(ByteInterval byteInterval) {\n        if (byteInterval.getSection().isPresent() &&\n            byteInterval.getSection().get() == this) {\n            TreeListUtils.removeItem(byteInterval, byteIntervalTree);\n            byteInterval.setSection(Optional.empty());\n            return true;\n        } else\n            return false;\n    }\n\n    /**\n     * Get the flags applying to this Section.\n     *\n     * @return  An unmodifiable {@link SectionFlag} set of all the\n     * section flags of this {@link Section}.\n     */\n    public Set<SectionFlag> getSectionFlags() {\n        return Collections.unmodifiableSet(this.sectionFlags);\n    }\n\n    /**\n     * Add a Section flag.\n     *\n     * @param sectionFlag A {@link SectionFlag} that will be applied to this\n     * Section.\n     */\n    public void addSectionFlag(SectionFlag sectionFlag) {\n        this.sectionFlags.add(sectionFlag);\n    }\n\n    /**\n     * Remove a Section flag.\n     *\n     * @param sectionFlag A {@link SectionFlag} to be removed from this\n     * Section.\n     * @return boolean true if this section contained the section flag, and it\n     * was removed.\n     */\n    public boolean removeSectionFlag(SectionFlag sectionFlag) {\n        return (this.sectionFlags.remove(sectionFlag));\n    }\n\n    /**\n     * Return the size of this section, if known.\n     *\n     * The size is calculated from the {@link ByteInterval} objects in this\n     * section. More specifically, if the address of all byte intervals in this\n     * section are fixed, then it will return the difference between the lowest\n     * and highest address among the intervals. If any one interval does not\n     * have an address, then this function will return null, as the size is not\n     * calculable in that case. Note that a section with no intervals in it has\n     * no address or size, so it will return null in that case.\n     *\n     * @return The size of this section if known, otherwise 0.\n     */\n    public long getSize() {\n        if (byteIntervalTree.size() == 0)\n            return 0;\n\n        // Check whether any ByteIntervals lack an address.\n        // A BI inserted without an address would use 0 for a key.\n        if (this.byteIntervalTree.containsKey(0L)) {\n            for (ByteInterval byteInterval : byteIntervalTree.get(0L)) {\n                if (!byteInterval.hasAddress())\n                    return 0;\n            }\n        }\n\n        // If we get here, there is at least one ByteInterval, and every one has\n        // an address.\n        Iterator<ByteInterval> byteIntervalTreeIterator =\n            this.getByteIntervalIterator();\n        ByteInterval byteInterval = byteIntervalTreeIterator.next();\n        long sectionStart =\n            byteInterval.getAddress().orElseThrow(NoSuchElementException::new);\n        long sectionEnd = sectionStart + byteInterval.getSize();\n        while (byteIntervalTreeIterator.hasNext()) {\n            byteInterval = byteIntervalTreeIterator.next();\n            long biStart = byteInterval.getAddress().orElseThrow(\n                NoSuchElementException::new);\n            long biEnd = biStart + byteInterval.getSize();\n            if (Long.compareUnsigned(biStart, sectionStart) < 0L)\n                sectionStart = biStart;\n            if (Long.compareUnsigned(biEnd, sectionEnd) > 0L)\n                sectionEnd = biEnd;\n        }\n        return sectionEnd - sectionStart;\n    }\n\n    /**\n     * Return the address of this section, if known.\n     *\n     * The address is calculated from the {@link ByteInterval} objects in this\n     * section. More specifically, if the address of all byte intervals in this\n     * section are fixed, then it will return the address of the interval lowest\n     * in memory. If any one interval does not have an address, then this\n     * function will return null, as the address is not calculable in that case.\n     * Note that a section with no intervals in it has no address or size, so it\n     * will return null in that case.\n     *\n     * @return The address of this section if known, otherwise null.\n     */\n    public OptionalLong getAddress() {\n        if (byteIntervalTree.size() == 0)\n            return OptionalLong.empty();\n        Iterator<ByteInterval> byteIntervalTreeIterator =\n            this.getByteIntervalIterator();\n        OptionalLong minAddress = OptionalLong.empty();\n        while (byteIntervalTreeIterator.hasNext()) {\n            ByteInterval byteInterval = byteIntervalTreeIterator.next();\n            OptionalLong biAddress = byteInterval.getAddress();\n            if (!biAddress.isPresent())\n                return OptionalLong.empty();\n            // This iterator is sorted, but with signed comparison.\n            // Checking every ByteInterval here instead of just using the first\n            // iteration helps avoid any (unlikely) signedness issues.\n            if (!minAddress.isPresent() ||\n                Long.compareUnsigned(minAddress.getAsLong(),\n                                     biAddress.getAsLong()) > 0)\n                minAddress = biAddress;\n        }\n        // Return the start of the first byte interval\n        return minAddress;\n    }\n\n    /**\n     * Get the index to manage this Section with.\n     *\n     * This index is used for storing and retrieving the Section, as\n     * required by the TreeListItem interface. Sections are ordered by\n     * address, so this method just returns the address.\n     * @return  The ByteInterval index, which is it's address.\n     */\n    public long getIndex() { return this.getAddress().orElse(0); }\n\n    /**\n     * Get all ByteIntervals containing an address.\n     *\n     * @param address      The address to look for.\n     * @return             A list of ByteIntervals that intersect this address,\n     * or empty list if none.\n     */\n    public List<ByteInterval> findByteIntervalsOn(long address) {\n        return TreeListUtils.getItemsIntersectingIndex(address,\n                                                       this.byteIntervalTree);\n    }\n\n    /**\n     * Get all ByteIntervals containing any address in a range.\n     *\n     * @param startAddress      The beginning of the address range to look for.\n     * (inclusive)\n     * @param endAddress        The last address of the address range to look\n     * for. (exclusive)\n     * @return                  A list of ByteIntervals that intersect this\n     * address range, or empty list if none.\n     */\n    public List<ByteInterval> findByteIntervalsOn(long startAddress,\n                                                  long endAddress) {\n        return TreeListUtils.getItemsIntersectingIndexRange(\n            startAddress, endAddress, this.byteIntervalTree);\n    }\n\n    /**\n     * Get all ByteIntervals that begin at an address.\n     *\n     * @param address      The address to look for.\n     * @return             A list of ByteIntervals that that start at this\n     * address, or null if none.\n     */\n    public List<ByteInterval> findByteIntervalsAt(long address) {\n        return TreeListUtils.getItemsAtStartIndex(address,\n                                                  this.byteIntervalTree);\n    }\n\n    /**\n     * Get all ByteIntervals that begin at a range of addressees.\n     *\n     * @param startAddress      The beginning of the address range to look for.\n     * (inclusive)\n     * @param endAddress        The last address in the address to look for.\n     * (exlusive)\n     * @return                  A list of ByteIntervals that that start at this\n     * address, or null if none.\n     */\n    public List<ByteInterval> findByteIntervalsAt(long startAddress,\n                                                  long endAddress) {\n        return TreeListUtils.getItemsAtStartIndexRange(startAddress, endAddress,\n                                                       this.byteIntervalTree);\n    }\n\n    /**\n     * De-serialize a {@link Section} from a protobuf .\n     *\n     * @return An initialized section.\n     */\n    static Section fromProtobuf(SectionOuterClass.Section protoSection)\n        throws IOException {\n        return new Section(protoSection);\n    }\n\n    /**\n     * Serialize this Section into a protobuf .\n     *\n     * @return Section protocol buffer.\n     */\n    SectionOuterClass.Section.Builder toProtobuf() {\n        SectionOuterClass.Section.Builder protoSection =\n            SectionOuterClass.Section.newBuilder();\n        protoSection.setUuid(Util.uuidToByteString(this.getUuid()));\n        protoSection.setName(this.getName());\n\n        // Add byte intervals\n        Iterator<ByteInterval> byteIntervals = this.getByteIntervalIterator();\n        while (byteIntervals.hasNext()) {\n            ByteInterval byteInterval = byteIntervals.next();\n            ByteIntervalOuterClass.ByteInterval.Builder protoByteInterval =\n                byteInterval.toProtobuf();\n            protoSection.addByteIntervals(protoByteInterval);\n        }\n\n        for (SectionFlag sectionFlag : this.sectionFlags)\n            protoSection.addSectionFlagsValue(sectionFlag.ordinal());\n        return protoSection;\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/SectionPropertyTuple.java",
    "content": "package com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.tuple.Tuple2;\n\n/**\n * A tuple for representing information about section properties in ELF files.\n */\npublic class SectionPropertyTuple extends Tuple2<Long, Long> {\n    /**\n     * Constructor for building a tuple for a section.\n     *\n     * @param type The type of the section.\n     * @param flags The flags for the section.\n     */\n    public SectionPropertyTuple(Long type, Long flags) { super(type, flags); }\n\n    /**\n     * Get the type of the section.\n     *\n     * @return The type of the section.\n     */\n    public Long getType() { return this.get0(); }\n\n    /**\n     * Get the flags attached to the section.\n     *\n     * @return The flags for the section.\n     */\n    public Long getFlags() { return this.get1(); }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/SymAddrAddr.java",
    "content": "/*\n *  Copyright (C) 2020-2023 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.proto.SymbolicExpressionOuterClass;\nimport java.io.IOException;\nimport java.util.Set;\nimport java.util.UUID;\n\n/**\n *\n * The SymAddrAddr class represents a symbolic operand of the form \"(Sym1 -\n Sym2) / Scale + Offset\".\n\n */\npublic class SymAddrAddr extends SymbolicExpression {\n\n    private long scale;\n    private long offset;\n    private UUID symbol1_uuid;\n    private UUID symbol2_uuid;\n\n    /**\n     * Class constructor for a SymAddrAddr from a protobuf symbolic\n     * expression.\n     * @param  protoSymbolicExpression  The SymAddrAddr symbolic expression, as\n     * serialized into a protocol buffer.\n     */\n    public SymAddrAddr(\n        SymbolicExpressionOuterClass.SymbolicExpression protoSymbolicExpression)\n        throws IOException {\n        super(protoSymbolicExpression);\n        SymbolicExpressionOuterClass.SymAddrAddr protoSymAddrAddr =\n            protoSymbolicExpression.getAddrAddr();\n        this.setSymbol1Uuid(\n            Util.byteStringToUuid(protoSymAddrAddr.getSymbol1Uuid()));\n        this.setSymbol2Uuid(\n            Util.byteStringToUuid(protoSymAddrAddr.getSymbol2Uuid()));\n        this.setScale(protoSymAddrAddr.getScale());\n        this.setOffset(protoSymAddrAddr.getOffset());\n    }\n\n    /**\n     * Class constructor for a SymbolicExpression.\n     * @param  offset           The constant offset operand.\n     * @param  scale            The scale applied to the symbol difference.\n     * @param  symbol1_uuid     The UUID of the first symbolic operand.\n     * @param  symbol2_uuid     The UUID of the second symbolic operand.\n     * @param  attributeFlags   A list of applicable attributes. May be empty.\n     */\n    public SymAddrAddr(long offset, long scale, UUID symbol1_uuid,\n                       UUID symbol2_uuid, Set<AttributeFlag> attributeFlags) {\n        super(attributeFlags);\n        this.setScale(scale);\n        this.setOffset(offset);\n        this.setSymbol1Uuid(symbol1_uuid);\n        this.setSymbol2Uuid(symbol2_uuid);\n    }\n\n    /**\n     * Get the symbol UUID of the first operand in this SymAddrAddr.\n     *\n     * @return  The UUID of the first symbolic operand of this expression.\n     */\n    public UUID getSymbol1Uuid() { return symbol1_uuid; }\n\n    /**\n     * Set the symbol UUID of the first operand in this SymAddrAddr.\n     *\n     * @param symbol_uuid    New value for the UUID of the first symbolic\n     * operand of the expression.\n     */\n    public void setSymbol1Uuid(UUID symbol_uuid) {\n        this.symbol1_uuid = symbol_uuid;\n    }\n\n    /**\n     * Get the symbol UUID of the second operand in this SymAddrAddr.\n     *\n     * @return  The UUID of the second symbolic operand of this expression.\n     */\n    public UUID getSymbol2Uuid() { return symbol2_uuid; }\n\n    /**\n     * Set the symbol UUID of the second operand in this SymAddrAddr.\n     *\n     * @param symbol_uuid    New value for the UUID of the second symbolic\n     * operand of the expression.\n     */\n    public void setSymbol2Uuid(UUID symbol_uuid) {\n        this.symbol2_uuid = symbol_uuid;\n    }\n\n    /**\n     * Get the scale this SymAddrAddr.\n     *\n     * @return        The SymAddrAddr scale\n     */\n    public long getScale() { return scale; }\n\n    /**\n     * Set the scale this SymAddrAddr.\n     *\n     * @param scale    The new scale to set the SymAddrAddr scale to\n     */\n    public void setScale(long scale) { this.scale = scale; }\n\n    /**\n     * Gets the constant offset of this SymAddrAddr\n     * @return The current offset value\n     */\n    public long getOffset() { return this.offset; }\n\n    /**\n     * Sets the constant offset of this SymAddrAddr.\n     * @param offset New value for the constant offset.\n     */\n    public void setOffset(long offset) { this.offset = offset; }\n\n    /**\n     * De-serialize a {@link SymAddrAddr} from a protobuf .\n     *\n     * @param  protoSymbolicExpression     The symbolic expression as serialized\n     * into a protocol buffer.\n     * @return An initialized SymAddrAddr.\n     */\n    public static SymAddrAddr fromProtobuf(\n        SymbolicExpressionOuterClass.SymbolicExpression protoSymbolicExpression)\n        throws IOException {\n        return new SymAddrAddr(protoSymbolicExpression);\n    }\n\n    /**\n     * Serialize this SymAddrConst into a protobuf.\n     *\n     * @return Block protocol buffer containing this SymAddrConst.\n     */\n    @Override\n    public SymbolicExpressionOuterClass.SymbolicExpression.Builder\n    toProtobuf() {\n        SymbolicExpressionOuterClass.SymbolicExpression\n            .Builder protoSymbolicExpression =\n            SymbolicExpressionOuterClass.SymbolicExpression.newBuilder();\n        SymbolicExpressionOuterClass.SymAddrAddr.Builder protoSymAddrAddr =\n            SymbolicExpressionOuterClass.SymAddrAddr.newBuilder();\n        protoSymAddrAddr.setSymbol1Uuid(\n            Util.uuidToByteString(this.getSymbol1Uuid()));\n        protoSymAddrAddr.setSymbol2Uuid(\n            Util.uuidToByteString(this.getSymbol2Uuid()));\n        protoSymAddrAddr.setOffset(this.getOffset());\n        protoSymbolicExpression.setAddrAddr(protoSymAddrAddr);\n\n        // NOTE for this to be valid, a one-to-one mapping of enums must be\n        // maintained\n        for (AttributeFlag attributeFlag : this.getAttributeFlags())\n            protoSymbolicExpression.addAttributeFlagsValue(\n                attributeFlag.ordinal());\n        for (Integer value : this.getUnknownAttributeFlags()) {\n            protoSymbolicExpression.addAttributeFlagsValue(value);\n        }\n        return protoSymbolicExpression;\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/SymAddrConst.java",
    "content": "/*\n *  Copyright (C) 2020-2023 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.proto.SymbolicExpressionOuterClass;\nimport java.io.IOException;\nimport java.util.Set;\nimport java.util.UUID;\n\n/**\n * The SymAddConst class represents a symbolic operand of the form \"Sym +\n * Offset\".\n */\npublic class SymAddrConst extends SymbolicExpression {\n\n    private UUID symbol_uuid;\n    private long offset;\n\n    /**\n     * Class constructor for a SymAddrConst from a protobuf symbolic expression.\n     * @param  protoSymbolicExpression  The symbolic expression as serialized\n     * into a protocol buffer.\n     */\n    public SymAddrConst(\n        SymbolicExpressionOuterClass.SymbolicExpression protoSymbolicExpression)\n        throws IOException {\n        super(protoSymbolicExpression);\n        SymbolicExpressionOuterClass.SymAddrConst protoSymAddrConst =\n            protoSymbolicExpression.getAddrConst();\n        this.setSymbolUuid(\n            Util.byteStringToUuid(protoSymAddrConst.getSymbolUuid()));\n        this.offset = protoSymAddrConst.getOffset();\n    }\n\n    /**\n     * Class constructor for a SymAddrConst.\n     * @param  offset          The offset of this symbolic expression in the\n     * ByteInterval.\n     * @param  symbol_uuid     The UUID of the symbolic operand.\n     */\n    public SymAddrConst(long offset, UUID symbol_uuid,\n                        Set<AttributeFlag> attributeFlags) {\n        super(attributeFlags);\n        this.setSymbolUuid(symbol_uuid);\n        this.offset = offset;\n    }\n\n    /**\n     * Get the symbol UUID of this SymAddrConst.\n     *\n     * @return  The UUID of the symbolic operand of this expression.\n     */\n    public UUID getSymbolUuid() { return symbol_uuid; }\n\n    /**\n     * Set the symbol UUID of this SymAddrConst.\n     *\n     * @param  symbol_uuid    New value for the UUID of the symbolic operand of\n     * the expression.\n     */\n    public void setSymbolUuid(UUID symbol_uuid) {\n        this.symbol_uuid = symbol_uuid;\n    }\n\n    /**\n     * Gets the symbol-relative constant offset of this SymAddrConst.\n     * @return The current offset value\n     */\n    public long getOffset() { return this.offset; }\n\n    /**\n     * Sets the symbol-relative constant offset of this SymAddrConst.\n     * @param offset New value for the constant offset.\n     */\n    public void setOffset(long offset) { this.offset = offset; }\n\n    /**\n     * De-serialize a {@link SymAddrConst} from a protobuf.\n     *\n     * @param  protoSymbolicExpression  The symbolic expression as serialized\n     * into a protocol buffer.\n     * @return An initialized SymAddrConst\n     */\n    public static SymAddrConst fromProtobuf(\n        SymbolicExpressionOuterClass.SymbolicExpression protoSymbolicExpression)\n        throws IOException {\n        return new SymAddrConst(protoSymbolicExpression);\n    }\n\n    /**\n     * Serialize this SymAddrConst into a protobuf.\n     *\n     * @return Block protocol buffer containing this SymAddrConst.\n     */\n    @Override\n    public SymbolicExpressionOuterClass.SymbolicExpression.Builder\n    toProtobuf() {\n        SymbolicExpressionOuterClass.SymbolicExpression\n            .Builder protoSymbolicExpression =\n            SymbolicExpressionOuterClass.SymbolicExpression.newBuilder();\n        SymbolicExpressionOuterClass.SymAddrConst.Builder protoSymAddrConst =\n            SymbolicExpressionOuterClass.SymAddrConst.newBuilder();\n        protoSymAddrConst.setSymbolUuid(\n            Util.uuidToByteString(this.getSymbolUuid()));\n        protoSymAddrConst.setOffset(this.getOffset());\n        protoSymbolicExpression.setAddrConst(protoSymAddrConst);\n        // NOTE for this to be valid, a one-to-one mapping of enums must be\n        // maintained\n        for (AttributeFlag attributeFlag : this.getAttributeFlags())\n            protoSymbolicExpression.addAttributeFlagsValue(\n                attributeFlag.ordinal());\n        for (Integer value : this.getUnknownAttributeFlags()) {\n            protoSymbolicExpression.addAttributeFlagsValue(value);\n        }\n        return protoSymbolicExpression;\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/Symbol.java",
    "content": "/*\n *  Copyright (C) 2020-2023 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.proto.SymbolOuterClass;\nimport java.io.IOException;\nimport java.util.Optional;\nimport java.util.OptionalLong;\nimport java.util.UUID;\n\n/**\n * Maps a name to an object in the IR.\n * A Symbol may have a referent or a value, or neither. A referent is\n * a ByteBlock, somewhere in the IR. A value is an integer.\n * Use the hasValue() method to determine if the payload is a value,\n * hasReferent to determine if it has a referent.\n */\npublic class Symbol extends Node {\n\n    /**\n     * \tSymbol payload options.\n     */\n    public enum PayloadType { REFERENT, VALUE, NONE }\n\n    private Optional<Module> module;\n    private String name;\n    private long value;\n    private UUID referentUuid;\n    private PayloadType payloadType;\n    private boolean atEnd;\n\n    /**\n     * Class constructor for a Symbol from a protobuf symbol.\n     * @param  protoSymbol   The Symbol as serialized into a protocol buffer.\n     */\n    private Symbol(SymbolOuterClass.Symbol protoSymbol) throws IOException {\n        super(Util.byteStringToUuid(protoSymbol.getUuid()));\n        this.module = Optional.empty();\n        this.name = protoSymbol.getName();\n        this.atEnd = protoSymbol.getAtEnd();\n        // Set default values:\n        this.value = 0;\n        this.referentUuid = Util.NIL_UUID; // init to null as fallback\n        // Determine payload for this symbol, if there is one:\n        if (protoSymbol.getOptionalPayloadCase() ==\n            SymbolOuterClass.Symbol.OptionalPayloadCase.VALUE) {\n            this.value = protoSymbol.getValue();\n            this.payloadType = PayloadType.VALUE;\n        } else if (protoSymbol.getOptionalPayloadCase() ==\n                   SymbolOuterClass.Symbol.OptionalPayloadCase.REFERENT_UUID) {\n            this.referentUuid =\n                Util.byteStringToUuid(protoSymbol.getReferentUuid());\n            this.payloadType = PayloadType.REFERENT;\n        } else {\n            this.payloadType = PayloadType.NONE;\n        }\n    }\n\n    /**\n     * Class constructor for a Symbol with a referent payload.\n     * @param  name          The section as serialized into a protocol buffer.\n     * @param  referentUuid  The symbol referent as a UUID.\n     */\n    public Symbol(String name, UUID referentUuid) {\n        super();\n        this.module = Optional.empty();\n        this.name = name;\n        this.referentUuid = referentUuid;\n        this.payloadType = PayloadType.REFERENT;\n        this.value = 0;\n        this.atEnd = false; // default to not being at end\n    }\n\n    /**\n     * Class constructor for a Symbol with a value payload.\n     * @param  name          The section as serialized into a protocol buffer.\n     * @param  value         The symbol value.\n     */\n    public Symbol(String name, long value) {\n        super();\n        this.module = Optional.empty();\n        this.name = name;\n        this.value = value;\n        this.payloadType = PayloadType.VALUE;\n        this.referentUuid = Util.NIL_UUID;\n        this.atEnd = false; // default to not being at end\n    }\n\n    /**\n     * Class constructor for a minimal Symbol with no payload.\n     * @param  name          The section as serialized into a protocol buffer.\n     */\n    public Symbol(String name) {\n        super();\n        this.module = Optional.empty();\n        this.name = name;\n        this.payloadType = PayloadType.NONE;\n        this.value = 0;\n        this.referentUuid = Util.NIL_UUID;\n        this.atEnd = false; // default to not being at end\n    }\n\n    /**\n     * Get the {@link Module} this Symbol belongs to.\n     *\n     * @return  An Optional that contains the Module this\n     * symbol belongs to, or empty if it does not belong to a Module.\n     */\n    public Optional<Module> getModule() { return this.module; }\n\n    /**\n     * Set the Module this Symbol belongs to.\n     *\n     * @param  module An Optional that contains the Module this\n     * symbol belongs to, or empty if it does not belong to a Module.\n     */\n    public void setModule(Optional<Module> module) { this.module = module; }\n\n    /**\n     * Get the name of this Symbol.\n     *\n     * @return  The symbol name.\n     */\n    public String getName() { return name; }\n\n    /**\n     * Set the name of this Symbol.\n     *\n     * @param name    The symbol name.\n     */\n    public void setName(String name) { this.name = name; }\n\n    /**\n     * Get the referent of this Symbol.\n     *\n     * @return  The symbol's referent, or null if there is no referent.\n     */\n    public Node getReferent() {\n        if (this.payloadType == PayloadType.REFERENT)\n            return Node.getByUuid(this.referentUuid);\n        return null;\n    }\n\n    /**\n     * Get the UUID of this Symbol's referent.\n     *\n     * @return  An Optional that has the UUID of this symbol's referent, if it\n     * has one.\n     */\n    public Optional<UUID> getReferentUuid() {\n        if (this.payloadType == PayloadType.REFERENT)\n            return Optional.of(this.referentUuid);\n        return Optional.empty();\n    }\n\n    /**\n     * Set the UUID of this Symbol's referent.\n     *\n     * Calling this method will set the payload type to REFERENT.\n     *\n     * @param uuid  The UUID of this symbol's referent..\n     */\n    public void setReferentUuid(UUID uuid) {\n        this.referentUuid = uuid;\n        this.payloadType = PayloadType.REFERENT;\n    }\n\n    /**\n     * Get the value of this Symbol.\n     *\n     * @return  An OptionalLong that has the symbol value, if it has one.\n     */\n    public OptionalLong getValue() {\n        if (this.payloadType == PayloadType.VALUE)\n            return OptionalLong.of(this.value);\n        return OptionalLong.empty();\n    }\n\n    /**\n     * Set the value of this Symbol.\n     *\n     * @param value   The symbol value.\n     */\n    public void setValue(long value) {\n        this.value = value;\n        this.payloadType = PayloadType.VALUE;\n    }\n\n    /**\n     * Get the payload type of this Symbol.\n     *\n     * @return  The symbol name.\n     */\n    public PayloadType getPayloadType() { return this.payloadType; }\n\n    /**\n     * Get whether symbol is at end.\n     *\n     * @return true if symbol is at end, false otherwise.\n     */\n    public boolean isAtEnd() { return this.atEnd; }\n\n    /**\n     * Set whether symbol is at end.\n\n     * @param atEnd The at end value to set\n     */\n    public void setAtEnd(boolean atEnd) { this.atEnd = atEnd; }\n\n    /**\n     * De-serialize a {@link Symbol} from a protobuf .\n     *\n     * @param protoSymbol The protobuf version of this symbol\n     * @return An initialized symbol.\n     */\n    static Symbol fromProtobuf(SymbolOuterClass.Symbol protoSymbol)\n        throws IOException {\n        return new Symbol(protoSymbol);\n    }\n\n    /**\n     * Serialize this Symbol into a protobuf.\n     *\n     * @return Symbol protocol buffer.\n     */\n    SymbolOuterClass.Symbol.Builder toProtobuf() {\n        SymbolOuterClass.Symbol.Builder protoSymbol =\n            SymbolOuterClass.Symbol.newBuilder();\n        protoSymbol.setUuid(Util.uuidToByteString(this.getUuid()));\n        protoSymbol.setName(this.getName());\n        protoSymbol.clearOptionalPayload();\n        if (this.payloadType == PayloadType.VALUE)\n            protoSymbol.setValue(this.value);\n        else if (this.payloadType == PayloadType.REFERENT)\n            protoSymbol.setReferentUuid(\n                Util.uuidToByteString(this.referentUuid));\n        return protoSymbol;\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/SymbolicExpression.java",
    "content": "/*\n *  Copyright (C) 2020-2023 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.proto.SymbolicExpressionOuterClass;\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * The Symbolic Expression class is a base class for expressions such as\n * SymAddrConst, SymAddrAddr, and SymStackConst.\n */\npublic class SymbolicExpression {\n\n    /**\n     * Attributes for Symbolic Expressions.\n     *\n     * @see <a\n     *     href=\"https://grammatech.github.io/gtirb/md__symbolic_expression.html\">SymbolicExpression</a>\n     */\n    public enum AttributeFlag {\n        GOT(SymbolicExpressionOuterClass.SymAttribute.GOT_VALUE),\n        GOTPC(SymbolicExpressionOuterClass.SymAttribute.GOTPC_VALUE),\n        GOTOFF(SymbolicExpressionOuterClass.SymAttribute.GOTOFF_VALUE),\n        GOTREL(SymbolicExpressionOuterClass.SymAttribute.GOTREL_VALUE),\n        PLT(SymbolicExpressionOuterClass.SymAttribute.PLT_VALUE),\n        PLTOFF(SymbolicExpressionOuterClass.SymAttribute.PLTOFF_VALUE),\n        PCREL(SymbolicExpressionOuterClass.SymAttribute.PCREL_VALUE),\n        SECREL(SymbolicExpressionOuterClass.SymAttribute.SECREL_VALUE),\n        TLS(SymbolicExpressionOuterClass.SymAttribute.TLS_VALUE),\n        TLSGD(SymbolicExpressionOuterClass.SymAttribute.TLSGD_VALUE),\n        TLSLD(SymbolicExpressionOuterClass.SymAttribute.TLSLD_VALUE),\n        TLSLDM(SymbolicExpressionOuterClass.SymAttribute.TLSLDM_VALUE),\n        TLSCALL(SymbolicExpressionOuterClass.SymAttribute.TLSCALL_VALUE),\n        TLSDESC(SymbolicExpressionOuterClass.SymAttribute.TLSDESC_VALUE),\n        TPREL(SymbolicExpressionOuterClass.SymAttribute.TPREL_VALUE),\n        TPOFF(SymbolicExpressionOuterClass.SymAttribute.TPOFF_VALUE),\n        DTPREL(SymbolicExpressionOuterClass.SymAttribute.DTPREL_VALUE),\n        DTPOFF(SymbolicExpressionOuterClass.SymAttribute.DTPOFF_VALUE),\n        DTPMOD(SymbolicExpressionOuterClass.SymAttribute.DTPMOD_VALUE),\n        NTPOFF(SymbolicExpressionOuterClass.SymAttribute.NTPOFF_VALUE),\n        PAGE(SymbolicExpressionOuterClass.SymAttribute.PAGE_VALUE),\n        PAGEOFF(SymbolicExpressionOuterClass.SymAttribute.PAGEOFF_VALUE),\n        CALL(SymbolicExpressionOuterClass.SymAttribute.CALL_VALUE),\n        LO(SymbolicExpressionOuterClass.SymAttribute.LO_VALUE),\n        HI(SymbolicExpressionOuterClass.SymAttribute.HI_VALUE),\n        HIGHER(SymbolicExpressionOuterClass.SymAttribute.HIGHER_VALUE),\n        HIGHEST(SymbolicExpressionOuterClass.SymAttribute.HIGHEST_VALUE),\n        GOTNTPOFF(SymbolicExpressionOuterClass.SymAttribute.GOTNTPOFF_VALUE),\n        INDNTPOFF(SymbolicExpressionOuterClass.SymAttribute.INDNTPOFF_VALUE),\n        G0(SymbolicExpressionOuterClass.SymAttribute.G0_VALUE),\n        G1(SymbolicExpressionOuterClass.SymAttribute.G1_VALUE),\n        G2(SymbolicExpressionOuterClass.SymAttribute.G2_VALUE),\n        G3(SymbolicExpressionOuterClass.SymAttribute.G3_VALUE),\n        UPPER16(SymbolicExpressionOuterClass.SymAttribute.UPPER16_VALUE),\n        LOWER16(SymbolicExpressionOuterClass.SymAttribute.LOWER16_VALUE),\n        LO12(SymbolicExpressionOuterClass.SymAttribute.LO12_VALUE),\n        LO15(SymbolicExpressionOuterClass.SymAttribute.LO15_VALUE),\n        LO14(SymbolicExpressionOuterClass.SymAttribute.LO14_VALUE),\n        HI12(SymbolicExpressionOuterClass.SymAttribute.HI12_VALUE),\n        HI21(SymbolicExpressionOuterClass.SymAttribute.HI21_VALUE),\n        S(SymbolicExpressionOuterClass.SymAttribute.S_VALUE),\n        PG(SymbolicExpressionOuterClass.SymAttribute.PG_VALUE),\n        NC(SymbolicExpressionOuterClass.SymAttribute.NC_VALUE),\n        ABS(SymbolicExpressionOuterClass.SymAttribute.ABS_VALUE),\n        PREL(SymbolicExpressionOuterClass.SymAttribute.PREL_VALUE),\n        PREL31(SymbolicExpressionOuterClass.SymAttribute.PREL31_VALUE),\n        TARGET1(SymbolicExpressionOuterClass.SymAttribute.TARGET1_VALUE),\n        TARGET2(SymbolicExpressionOuterClass.SymAttribute.TARGET2_VALUE),\n        SBREL(SymbolicExpressionOuterClass.SymAttribute.SBREL_VALUE),\n        TLSLDO(SymbolicExpressionOuterClass.SymAttribute.TLSLDO_VALUE),\n        HI16(SymbolicExpressionOuterClass.SymAttribute.HI16_VALUE),\n        LO16(SymbolicExpressionOuterClass.SymAttribute.LO16_VALUE),\n        GPREL(SymbolicExpressionOuterClass.SymAttribute.GPREL_VALUE),\n        DISP(SymbolicExpressionOuterClass.SymAttribute.DISP_VALUE),\n        OFST(SymbolicExpressionOuterClass.SymAttribute.OFST_VALUE),\n        H(SymbolicExpressionOuterClass.SymAttribute.H_VALUE),\n        L(SymbolicExpressionOuterClass.SymAttribute.L_VALUE),\n        HA(SymbolicExpressionOuterClass.SymAttribute.HA_VALUE),\n        HIGH(SymbolicExpressionOuterClass.SymAttribute.HIGH_VALUE),\n        HIGHA(SymbolicExpressionOuterClass.SymAttribute.HIGHA_VALUE),\n        HIGHERA(SymbolicExpressionOuterClass.SymAttribute.HIGHERA_VALUE),\n        HIGHESTA(SymbolicExpressionOuterClass.SymAttribute.HIGHESTA_VALUE),\n        TOCBASE(SymbolicExpressionOuterClass.SymAttribute.TOCBASE_VALUE),\n        TOC(SymbolicExpressionOuterClass.SymAttribute.TOC_VALUE),\n        NOTOC(SymbolicExpressionOuterClass.SymAttribute.NOTOC_VALUE),\n        ;\n\n        private final int value;\n        private static final Map<Integer, AttributeFlag> mapping = initMap();\n\n        AttributeFlag(int value) { this.value = value; }\n\n        public int value() { return this.value; }\n\n        public static AttributeFlag fromInteger(int value) {\n            return mapping.get(value);\n        }\n\n        private static Map<Integer, AttributeFlag> initMap() {\n            Map<Integer, AttributeFlag> mapping = new HashMap<>();\n            for (AttributeFlag flag : AttributeFlag.values()) {\n                mapping.put(flag.value(), flag);\n            }\n            return Collections.unmodifiableMap(mapping);\n        }\n    }\n\n    private Set<AttributeFlag> attributeFlags;\n    private Set<Integer> unknownAttributeFlags;\n\n    /**\n     * Class constructor for a SymbolicExpression from a protobuf symbolic\n     * expression.\n     * @param  protoSymbolicExpression     The symbolic expression as serialized\n     * into a protocol buffer.\n     */\n    protected SymbolicExpression(\n        SymbolicExpressionOuterClass.SymbolicExpression protoSymbolicExpression)\n        throws IOException {\n        this.attributeFlags = new HashSet<AttributeFlag>();\n        this.unknownAttributeFlags = new HashSet<Integer>();\n\n        for (Integer value :\n             protoSymbolicExpression.getAttributeFlagsValueList()) {\n            AttributeFlag attributeFlag = AttributeFlag.fromInteger(value);\n            if (attributeFlag == null) {\n                this.unknownAttributeFlags.add(value);\n            } else {\n                this.attributeFlags.add(attributeFlag);\n            }\n        }\n    }\n\n    /**\n     * Class constructor for a SymbolicExpression.\n     * @param  attributeFlags A set of flags that are applicable to this\n     *                        symbolic expression.\n     */\n    protected SymbolicExpression(Set<AttributeFlag> attributeFlags) {\n        this.attributeFlags = new HashSet<AttributeFlag>();\n        for (AttributeFlag attributeFlag : attributeFlags)\n            this.addAttributeFlag(attributeFlag);\n        this.unknownAttributeFlags = new HashSet<Integer>();\n    }\n\n    /**\n     * Get the flags applying to this SymbolicExpression.\n     *\n     * @return  An unmodifiable {@link AttributeFlag} set of all the\n     * attribute flags in this {@link SymbolicExpression}.\n     */\n    public Set<AttributeFlag> getAttributeFlags() {\n        return Collections.unmodifiableSet(this.attributeFlags);\n    }\n\n    /**\n     * Add an attribute flags to this SymbolicExpression.\n     *\n     * @param attributeFlag An {@link AttributeFlag} that will be applied\n     * to this symbolic expression.\n     */\n    public void addAttributeFlag(AttributeFlag attributeFlag) {\n        this.attributeFlags.add(attributeFlag);\n    }\n\n    /**\n     * Remove an attribute flags from this SymbolicExpression.\n     *\n     * @param attributeFlag An {@link AttributeFlag} that will be removed\n     * from this symbolic expression.\n     * @return boolean true if this symbolic expression contained the attribute\n     * flag, and it was removed.\n     */\n    public boolean removeAttributeFlag(AttributeFlag attributeFlag) {\n        return (this.attributeFlags.remove(attributeFlag));\n    }\n\n    /**\n     * Get unknown attribute flags applying to this SymbolicExpression.\n     *\n     * @return  An unmodifiable list of all the unknown attribute\n     * flags in this {@link SymbolicExpression}, as integers.\n     */\n    public Set<Integer> getUnknownAttributeFlags() {\n        return Collections.unmodifiableSet(this.unknownAttributeFlags);\n    }\n\n    /**\n     * Add an unknown attribute flag to this SymbolicExpression.\n     *\n     * @param unknownFlag An unknown attribute flag that will be applied\n     * to this symbolic expression and stored as an integer.\n     */\n    public void addUnknownFlag(Integer unknownFlag) {\n        this.unknownAttributeFlags.add(unknownFlag);\n    }\n\n    /**\n     * Remove an unknown attribute flag from this SymbolicExpression.\n     *\n     * @param unknownFlag An unknown attribute flag that will be removed\n     * to this symbolic expression.\n     * @return boolean true if this symbolic expression contained the attribute\n     * flag, and it was removed.\n     */\n    public boolean removeUnknownFlag(Integer unknownFlag) {\n        return (this.unknownAttributeFlags.remove(unknownFlag));\n    }\n\n    /**\n     * De-serialize a {@link SymbolicExpression} from a protobuf .\n     *\n     * @param protoSymbolicExpression The protobuf version of this\n     * symbolicExpression\n     * @return An initialized SymbolicExpression.\n     */\n    public static SymbolicExpression fromProtobuf(\n        SymbolicExpressionOuterClass.SymbolicExpression protoSymbolicExpression)\n        throws IOException {\n        return new SymbolicExpression(protoSymbolicExpression);\n    }\n\n    /**\n     * Serialize this SymbolicExpression into a protobuf.\n     *\n     * This method is intended to be overwritten in the subclasses.\n     *\n     * @return Protocol buffer containing this Symbolic Expression.\n     */\n    public SymbolicExpressionOuterClass.SymbolicExpression.Builder\n    toProtobuf() {\n        return SymbolicExpressionOuterClass.SymbolicExpression.newBuilder();\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/TreeListItem.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\n/**\n * Interface for generic items to be stored in sorted order.\n */\npublic interface TreeListItem {\n\n    /**\n     * Get the item index.\n     *\n     * Item index is used to store the items in sorted order.\n     *\n     * @return The item index..\n     */\n    long getIndex();\n\n    /**\n     * Get the item size.\n     *\n     * Item size is used to determine overlapping addresses.\n     *\n     * @return The item size.\n     */\n    long getSize();\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/TreeListUtils.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\n/**\n * Utilities for storing and retrieving generic items in sorted order.\n * Implementation is a TreeMap with nodes indexed by address\n * (or in some cases offset) where an address/offset is allowed to\n * have multiple items at the same index, and when multiple items have the\n * same index they are stored as an ArrayList.\n */\npublic class TreeListUtils<Type> implements Iterable<Type> {\n\n    private TreeMap<Long, List<Type>> treeMap;\n\n    public TreeListUtils(TreeMap<Long, List<Type>> treeMap) {\n        this.treeMap = treeMap;\n    }\n\n    /**\n     * Generic method for inserting items into a TreeList.\n     *\n     * @param item    The item to be added.\n     * @param tree    The tree to be inserted into.\n     * @return The updated tree node.\n     */\n    public static <T extends TreeListItem> List<T>\n    insertItem(T item, TreeMap<Long, List<T>> tree) {\n        Long index = item.getIndex();\n        List<T> itemList;\n        if (tree.containsKey(index))\n            itemList = tree.get(index);\n        else\n            itemList = new ArrayList<T>();\n        itemList.add(item);\n        tree.put(index, itemList);\n        return itemList;\n    }\n\n    /**\n     * Generic method for removing items from a TreeList.\n     *\n     * @param item    The item to be removed.\n     * @param tree    The tree to be removed from.\n     * @return The updated tree node.\n     */\n    public static <T extends TreeListItem> List<T>\n    removeItem(T item, TreeMap<Long, List<T>> tree) {\n        Long index = item.getIndex();\n        List<T> itemList = tree.get(index);\n        if (itemList == null)\n            // no blocks at this offset\n            return null;\n        if (!itemList.remove(item))\n            // didn't remove, maybe no matching item?\n            return null;\n        // Did remove, update tree.\n        // If the block list is now empty, remove the node from the tree.\n        // Otherwise update the tree.\n        if (itemList.size() == 0)\n            tree.remove(index);\n        else\n            tree.put(index, itemList);\n        // Return list, even if empty, because null means did not remove.\n        return itemList;\n    }\n\n    /**\n     * Generic method for retrieving items that intersect with a given address\n     *\n     * @param index    The address/offset to be matched.\n     * @param tree     The tree to be matched in.\n     * @return         A list of matching items.\n     */\n    public static <T extends TreeListItem> List<T>\n    getItemsIntersectingIndex(long index, TreeMap<Long, List<T>> tree) {\n        // Iterate through the tree nodes, but leave out those nodes who start\n        // after the searched-for index.\n        List<T> resultList = new ArrayList<T>();\n        SortedMap<Long, List<T>> subTree = tree.headMap(index, true);\n        for (List<T> itemList : subTree.values()) {\n            for (T item : itemList) {\n                long start = item.getIndex();\n                long end = start + item.getSize();\n                // Check if this item overlaps, including end points:\n                //    item starts at or below this offset AND\n                //    item ends at or above this offset\n                // If so add it to the list.\n                if (start <= index && end >= index) {\n                    resultList.add(item);\n                }\n            }\n        }\n        return resultList;\n    }\n\n    /**\n     * Generic method for retrieving items that intersect with a given address\n     * range\n     *\n     * @param startIndex  The start of the address range to be matched.\n     * @param endIndex    The end of the address range.\n     * @param tree        The tree to be matched in.\n     * @return            A list of matching items.\n     */\n    public static <T extends TreeListItem> List<T>\n    getItemsIntersectingIndexRange(long startIndex, long endIndex,\n                                   TreeMap<Long, List<T>> tree) {\n        // Iterate through the tree nodes, but leave out those nodes who start\n        // after the searched-for index.\n        List<T> resultList = new ArrayList<T>();\n        SortedMap<Long, List<T>> subTree = tree.headMap(endIndex, true);\n        for (List<T> itemList : subTree.values()) {\n            for (T item : itemList) {\n                long start = item.getIndex();\n                long end = start + item.getSize();\n                // Check for overlap, including end points:\n                //    (1) The range starts within the range of this interval:\n                //        Item start is at or above the range start AND\n                //        item start is at or below the range end\n                // OR (2) The range ends within the range of this interval:\n                //        Item end is at or above the range start AND\n                //        item end is at or below the range end\n                // OR (3) The range includes the range of this interval\n                //        Item start is below range start AND\n                //        item end is above range end\n                // If so add it to the list to return.\n                if (startIndex >= start && startIndex <= end)\n                    resultList.add(item);\n                else if (endIndex >= start && endIndex <= end)\n                    resultList.add(item);\n                else if (startIndex < start && endIndex > end)\n                    resultList.add(item);\n            }\n        }\n        return resultList;\n    }\n\n    /**\n     * Generic method for retrieving items that start at a given address.\n     *\n     * @param index       The address to be matched.\n     * @param tree        The tree to be matched in.\n     * @return            A list of matching items.\n     */\n    public static <T extends TreeListItem> List<T>\n    getItemsAtStartIndex(long index, TreeMap<Long, List<T>> tree) {\n        List<T> resultList = new ArrayList<T>();\n        if (tree.containsKey(index))\n            resultList.addAll(tree.get(index));\n        return (resultList);\n    }\n\n    /**\n     * Generic method for retrieving items that start at a given address range.\n     *\n     * @param startIndex  The start of the address range to be matched.\n     *     (inclusive)\n     * @param endIndex    The end of the address range. (exclusive)\n     * @param tree        The tree to be matched in.\n     * @return            A list of matching items.\n     */\n    public static <T extends TreeListItem> List<T>\n    getItemsAtStartIndexRange(long startIndex, long endIndex,\n                              TreeMap<Long, List<T>> tree) {\n        ArrayList<T> resultList = new ArrayList<T>();\n\n        // First key in range can be found with ceilingKey()\n        // Successive keys, if there are any, can be found with higherKey()\n        Long key = tree.ceilingKey(startIndex);\n        if (key != null && key < endIndex) {\n            resultList.addAll(tree.get(key));\n            key = tree.higherKey(key);\n        }\n\n        // Keep adding as long as you find items in range\n        while (key != null && key < endIndex) {\n            resultList.addAll(tree.get(key));\n            key = tree.higherKey(key);\n        }\n        return resultList;\n    }\n\n    /**\n     * Generic method for iterating through all items.\n     *\n     * @return An iterator for the tree.\n     */\n    @Override\n    public Iterator<Type> iterator() {\n        Iterator<Type> it = new Iterator<Type>() {\n            private int treeSize = treeMap.size();\n            private int currentTreeIndex = 0;\n            private int currentListIndex = 0;\n            // Get the (current set of keys for the whole tree, as an array of\n            // Longs, so that it can be incremented through\n            private Set<Long> keySet = treeMap.keySet();\n            private Long keyArray[] = keySet.toArray(new Long[0]);\n\n            // We need a currentList variable in this scope, but it the tree may\n            // be empty, so we can't initialize it here. So set it to emptyList,\n            // which will report a size of 0.\n            private List<Type> currentList = Collections.emptyList();\n\n            private boolean listHasNext() {\n                if (currentList.size() > 0 &&\n                    currentListIndex < currentList.size())\n                    return true;\n                return false;\n            }\n\n            private boolean treeHasNext() {\n                if (keySet.size() > 0 && currentTreeIndex < keySet.size())\n                    return true;\n                return false;\n            }\n\n            @Override\n            public boolean hasNext() {\n                if (treeSize == 0)\n                    return false;\n                if (listHasNext() || treeHasNext())\n                    return true;\n                return false;\n            }\n\n            @Override\n            public Type next() {\n                if (treeSize == 0)\n                    return null;\n                if (listHasNext())\n                    return currentList.get(currentListIndex++);\n                else if (treeHasNext()) {\n                    currentList = treeMap.get(keyArray[currentTreeIndex++]);\n                    currentListIndex = 0;\n                    return currentList.get(currentListIndex++);\n                }\n                return null;\n            }\n\n            @Override\n            public void remove() {\n                throw new UnsupportedOperationException();\n            }\n        };\n        return it;\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/TypeTableEntry.java",
    "content": "package com.grammatech.gtirb;\n\nimport com.grammatech.gtirb.tuple.Tuple1;\nimport com.grammatech.gtirb.tuple.Tuple2;\nimport com.grammatech.gtirb.variant.Token;\nimport com.grammatech.gtirb.variant.Variant11;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.UUID;\n\n/**\n * A variant representing type information for an object.\n */\npublic class TypeTableEntry\n    extends Variant11<Long, TypeTableEntry.BoolType, TypeTableEntry.IntType,\n                      Long, Long, TypeTableEntry.FunctionType, UUID,\n                      TypeTableEntry.ArrayType, UUID, TypeTableEntry.StructType,\n                      TypeTableEntry.VoidType> {\n\n    /**\n     * A marker type representing the type bool.\n     */\n    public static class BoolType extends Tuple1<Byte> {\n        /**\n         * Constructor.\n         *\n         * Note that this tuple's byte is defined to always be 0.\n         */\n        public BoolType(Byte b) { super((byte)0); }\n    }\n\n    /**\n     * A marker type representing the type int.\n     */\n    public static class IntType extends Tuple2<Byte, Long> {\n        /**\n         * Constructor.\n         *\n         * @param signedness Whether or not the type is signed (1 - signed, 0 -\n         *     unsigned).\n         * @param width Number of bytes the type is implemented with.\n         */\n        public IntType(Byte signedness, Long width) {\n            super(signedness, width);\n        }\n\n        /**\n         * True if the type is signed.\n         */\n        public boolean isSigned() { return this.get0() == 1; }\n\n        /**\n         * Get the width.\n         */\n        public Long getWidth() { return this.get1(); }\n    }\n\n    /**\n     * A marker type for representing function types.\n     */\n    public static class FunctionType extends Tuple2<UUID, List<UUID>> {\n        /**\n         * Constructor.\n         *\n         * @param returnType The UUID of the return type.\n         * @param paramTypes The types of the parameters.\n         */\n        public FunctionType(UUID returnType, List<UUID> paramTypes) {\n            super(returnType, paramTypes);\n        }\n\n        /**\n         * Get the return type UUID.\n         */\n        public UUID getReturnType() { return this.get0(); }\n\n        /**\n         * Get the types of the parameters.\n         */\n        public List<UUID> getParamTypes() { return this.get1(); }\n    }\n\n    /**\n     * A marker type for representing array types.\n     */\n    public static class ArrayType extends Tuple2<UUID, Long> {\n        /**\n         * Constructor.\n         *\n         * @param elemType The type of the elements of the array.\n         * @param size The size of the array.\n         */\n        public ArrayType(UUID elemType, Long size) { super(elemType, size); }\n\n        /**\n         * Get the element type UUID.\n         */\n        public UUID getElemType() { return this.get0(); }\n\n        /**\n         * Get the size of the array type.\n         */\n        public Long getSize() { return this.get1(); }\n    }\n\n    /**\n     * A tuple representing a structure field.\n     */\n    public static class StructField extends Tuple2<Long, UUID> {\n        /**\n         * Constructor.\n         *\n         * @param offset The offset within the struct this field is at.\n         * @param type The UUID of the type stored in this field.\n         */\n        public StructField(Long offset, UUID type) { super(offset, type); }\n\n        /**\n         * Get the offset of the field.\n         */\n        public Long getOffset() { return this.get0(); }\n\n        /**\n         * Get the type of the field.\n         */\n        public UUID getType() { return this.get1(); }\n    }\n\n    /**\n     * A marker type for representing structure types.\n     */\n    public static class StructType extends Tuple2<Long, List<StructField>> {\n        /**\n         * Constructor.\n         *\n         * @param size The total size of the struct.\n         * @param fields The list of fields in the struct.\n         */\n        public StructType(Long size, List<StructField> fields) {\n            super(size, fields);\n        }\n\n        /**\n         * Get the total size of the struct.\n         */\n        public Long getSize() { return this.get0(); }\n\n        /**\n         * Get the fields of the struct.\n         */\n        public List<StructField> getFields() { return this.get1(); }\n    }\n\n    /**\n     * A marker type representing the type void.\n     */\n    public static class VoidType extends Tuple1<Byte> {\n        /**\n         * Constructor.\n         *\n         * Note that this tuple's byte is defined to always be 0.\n         */\n        public VoidType(Byte b) { super((byte)0); }\n    }\n\n    /* Hidden constructors */\n    private TypeTableEntry(Token.T0 tok, Long v) { super(tok, v); }\n    private TypeTableEntry(Token.T1 tok, BoolType v) { super(tok, v); }\n    private TypeTableEntry(Token.T2 tok, IntType v) { super(tok, v); }\n    private TypeTableEntry(Token.T3 tok, Long v) { super(tok, v); }\n    private TypeTableEntry(Token.T4 tok, Long v) { super(tok, v); }\n    private TypeTableEntry(Token.T5 tok, FunctionType v) { super(tok, v); }\n    private TypeTableEntry(Token.T6 tok, UUID v) { super(tok, v); }\n    private TypeTableEntry(Token.T7 tok, ArrayType v) { super(tok, v); }\n    private TypeTableEntry(Token.T8 tok, UUID v) { super(tok, v); }\n    private TypeTableEntry(Token.T9 tok, StructType v) { super(tok, v); }\n    private TypeTableEntry(Token.T10 tok, VoidType v) { super(tok, v); }\n\n    /**\n     * Get the size of an unknown type.\n     */\n    public Optional<Long> getSizeIfUnknown() { return this.get0(); }\n\n    /**\n     * Returns whether or not the type is a bool type.\n     */\n    public boolean isBool() { return this.get1().isPresent(); }\n\n    /**\n     * Get the IntType tuple if this is an int type.\n     */\n    public Optional<IntType> getAsInt() { return this.get2(); }\n\n    /**\n     * Get the size of a char type.\n     */\n    public Optional<Long> getSizeIfChar() { return this.get3(); }\n\n    /**\n     * Get the size of a float type.\n     */\n    public Optional<Long> getSizeIfFloat() { return this.get4(); }\n\n    /**\n     * Get the FunctionType tuple if this is a function type.\n     */\n    public Optional<FunctionType> getAsFunction() { return this.get5(); }\n\n    /**\n     * Get the UUID of the pointed-to type if this is a pointer type.\n     */\n    public Optional<UUID> getUuidIfPointer() { return this.get6(); }\n\n    /**\n     * Get the ArrayType tuple if this is an array type.\n     */\n    public Optional<ArrayType> getAsArray() { return this.get7(); }\n\n    /**\n     * Get the UUID of the aliased type if this is an alias type.\n     */\n    public Optional<UUID> getUuidIfAlias() { return this.get8(); }\n\n    /**\n     * Get the StructType tuple if this is a struct type.\n     */\n    public Optional<StructType> getAsStruct() { return this.get9(); }\n\n    /**\n     * Returns true if this is a void type.\n     */\n    public boolean isVoid() { return this.get10().isPresent(); }\n\n    /**\n     * Factory for unknown type.\n     */\n    public static TypeTableEntry makeUnknown(Long size) {\n        return new TypeTableEntry(new Token.T0(), size);\n    }\n\n    /**\n     * Factory for bool type.\n     */\n    public static TypeTableEntry makeBool(BoolType boolType) {\n        return new TypeTableEntry(new Token.T1(), boolType);\n    }\n\n    /**\n     * Factory for int type.\n     */\n    public static TypeTableEntry makeInt(IntType intType) {\n        return new TypeTableEntry(new Token.T2(), intType);\n    }\n\n    /**\n     * Factory for char type.\n     */\n    public static TypeTableEntry makeChar(Long size) {\n        return new TypeTableEntry(new Token.T3(), size);\n    }\n\n    /**\n     * Factory for float type.\n     */\n    public static TypeTableEntry makeFloat(Long size) {\n        return new TypeTableEntry(new Token.T4(), size);\n    }\n\n    /**\n     * Factory for function type.\n     */\n    public static TypeTableEntry makeFunction(FunctionType funcType) {\n        return new TypeTableEntry(new Token.T5(), funcType);\n    }\n\n    /**\n     * Factory for pointer type.\n     */\n    public static TypeTableEntry makePointer(UUID pointedToType) {\n        return new TypeTableEntry(new Token.T6(), pointedToType);\n    }\n\n    /**\n     * Factory for array type.\n     */\n    public static TypeTableEntry makeArray(ArrayType arrType) {\n        return new TypeTableEntry(new Token.T7(), arrType);\n    }\n\n    /**\n     * Factory for alias type.\n     */\n    public static TypeTableEntry makeAlias(UUID aliasedType) {\n        return new TypeTableEntry(new Token.T8(), aliasedType);\n    }\n\n    /**\n     * Factory for struct type.\n     */\n    public static TypeTableEntry makeStruct(StructType structType) {\n        return new TypeTableEntry(new Token.T9(), structType);\n    }\n\n    /**\n     * Factory for void type.\n     */\n    public static TypeTableEntry makeVoid(VoidType voidType) {\n        return new TypeTableEntry(new Token.T10(), voidType);\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/Util.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb;\n\nimport com.google.protobuf.ByteString;\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.lang.IllegalArgumentException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.UUID;\n\n/**\n * General purpose methods.\n */\npublic class Util {\n\n    public static final UUID NIL_UUID = new UUID(0, 0);\n    public static final long NIL_ADDR = 0;\n\n    /**\n     * Converts a 16-byte array into a UUID.\n     *\n     * @param b The byte array.\n     * @return The resulting UUID.\n     */\n    public static UUID byteArrayToUUID(byte[] b)\n        throws IllegalArgumentException {\n        if (b.length != 16) {\n            throw new IllegalArgumentException(\"b.length() != 16\");\n        }\n        ByteBuffer bb = ByteBuffer.wrap(b);\n        bb.order(ByteOrder.LITTLE_ENDIAN);\n        return new UUID(bb.getLong(), bb.getLong());\n    }\n\n    /**\n     * Reads a UUID from an InputStream.\n     *\n     * @param in The stream to read from.\n     * @return The UUID read.\n     */\n    public static UUID readUUID(InputStream in) throws IOException {\n        byte[] b = new byte[16];\n        if (in.read(b, 0, 16) != 16) {\n            throw new EOFException(\"Insufficient bytes to read a UUID from.\");\n        }\n        try {\n            return byteArrayToUUID(b);\n        } catch (IllegalArgumentException e) {\n            // Should never happen.\n            throw new RuntimeException(\n                \"byteArrayToUUID() and readUUID using inconsistent buffer sizes!\");\n        }\n    }\n\n    /**\n     * Convert a ByteString to a UUID.\n     *\n     * @param byteString  The byte string.\n     * @return            A UUID having the value retrieved from the byte\n     * string.\n     */\n    public static UUID\n    byteStringToUuid(com.google.protobuf.ByteString byteString)\n        throws IOException {\n        if (byteString == com.google.protobuf.ByteString.EMPTY) {\n            return new UUID(0, 0);\n        }\n        byte[] uuidByteArray = byteString.toByteArray();\n        try {\n            return byteArrayToUUID(uuidByteArray);\n        } catch (IllegalArgumentException e) {\n            throw new IOException(\n                \"Protobuf ByteString has insufficient length for a UUID!\");\n        }\n    }\n\n    /**\n     * Converts a UUID to a 16-byte array\n     *\n     * @param uuid The uuid to convert.\n     * @return The resulting 16-byte array.\n     */\n    public static byte[] uuidToByteArray(UUID uuid) {\n        byte[] ba = new byte[16];\n        ByteBuffer bb = ByteBuffer.wrap(ba);\n        bb.order(ByteOrder.LITTLE_ENDIAN);\n        bb.putLong(uuid.getMostSignificantBits());\n        bb.putLong(uuid.getLeastSignificantBits());\n        return ba;\n    }\n\n    /**\n     * Writes a UUID to an OutputStream\n     *\n     * @param out The stream to write to.\n     */\n    public static void writeUUID(OutputStream out, UUID uuid)\n        throws IOException {\n        byte[] b = uuidToByteArray(uuid);\n        out.write(b, 0, 16);\n    }\n\n    /**\n     * Convert a UUID to a ByteString.\n     *\n     * @param uuid  The UUID.\n     * @return      A ByteString storing the value of the UUID.\n     */\n    public static com.google.protobuf.ByteString uuidToByteString(UUID uuid) {\n        return ByteString.copyFrom(uuidToByteArray(uuid));\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/BoolCodec.java",
    "content": "/*\n *  Copyright (C) 2022 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.auxdatacodec;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * A Codec for bool.\n */\npublic class BoolCodec implements Codec<Boolean> {\n\n    public String getTypeName() { return \"bool\"; }\n\n    public Boolean decode(InputStream in) throws IOException {\n        byte[] b = new byte[1];\n        if (in.read(b, 0, 1) != 1) {\n            throw new EOFException(\n                \"Insufficient bytes to read a Boolean from.\");\n        }\n        return Boolean.valueOf(b[0] != 0);\n    }\n\n    public void encode(OutputStream out, Boolean val) throws IOException {\n        out.write((byte)(val ? 1 : 0));\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/ByteCodec.java",
    "content": "package com.grammatech.gtirb.auxdatacodec;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\npublic class ByteCodec implements Codec<Byte> {\n\n    private String typeName;\n\n    private ByteCodec(String tn) { this.typeName = tn; }\n\n    public String getTypeName() { return this.typeName; }\n\n    public Byte decode(InputStream in) throws IOException {\n        byte[] b = new byte[1];\n        if (in.read(b, 0, 1) != 1) {\n            throw new EOFException(\"Insufficient bytes to read a Byte from.\");\n        }\n        return b[0];\n    }\n\n    public void encode(OutputStream out, Byte val) throws IOException {\n        byte[] b = new byte[1];\n        b[0] = val;\n        out.write(b, 0, 1);\n    }\n\n    public final static ByteCodec INT8 = new ByteCodec(\"int8_t\");\n    public final static ByteCodec UINT8 = new ByteCodec(\"uint8_t\");\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/Codec.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.auxdatacodec;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * A codec is an object that knows how to encode and decode AuxData objects.\n */\npublic interface Codec<T> {\n\n    /**\n     * Gets the portable name for the type used in protobuf.\n     *\n     * @return The name of the type.\n     */\n    public String getTypeName();\n\n    /**\n     * Decode a serialized instance into an in-memory object of type T.\n     *\n     * @param in The input stream the object is to be decoded from.\n     * @return The decoded object.\n     */\n    public T decode(InputStream in) throws IOException;\n\n    /**\n     * Encode an in-memory object into serialized form.\n     *\n     * @param out The output stream to send the serialized object to.\n     * @param val The in-memory object to be serialized.\n     */\n    public void encode(OutputStream out, T val) throws IOException;\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/FloatCodec.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.auxdatacodec;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\n\npublic class FloatCodec implements Codec<Float> {\n\n    public String getTypeName() { return \"float\"; }\n\n    public Float decode(InputStream in) throws IOException {\n        byte[] b = new byte[4];\n        if (in.read(b, 0, 4) != 4) {\n            throw new EOFException(\"Insufficient bytes to read a Float from.\");\n        }\n        ByteBuffer bb = ByteBuffer.wrap(b);\n        bb.order(ByteOrder.LITTLE_ENDIAN);\n        return bb.getFloat();\n    }\n\n    public void encode(OutputStream out, Float val) throws IOException {\n        byte[] b = new byte[4];\n        ByteBuffer bb = ByteBuffer.wrap(b);\n        bb.order(ByteOrder.LITTLE_ENDIAN);\n        bb.putFloat(val);\n        out.write(b, 0, 4);\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/IntegerCodec.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.auxdatacodec;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\n\npublic class IntegerCodec implements Codec<Integer> {\n\n    private String typeName;\n\n    private IntegerCodec(String tn) { this.typeName = tn; }\n\n    public String getTypeName() { return this.typeName; }\n\n    public Integer decode(InputStream in) throws IOException {\n        byte[] b = new byte[4];\n        if (in.read(b, 0, 4) != 4) {\n            throw new EOFException(\n                \"Insufficient bytes to read an Integer from.\");\n        }\n        ByteBuffer bb = ByteBuffer.wrap(b);\n        bb.order(ByteOrder.LITTLE_ENDIAN);\n        return bb.getInt();\n    }\n\n    public void encode(OutputStream out, Integer val) throws IOException {\n        byte[] b = new byte[4];\n        ByteBuffer bb = ByteBuffer.wrap(b);\n        bb.order(ByteOrder.LITTLE_ENDIAN);\n        bb.putInt(val);\n        out.write(b, 0, 4);\n    }\n\n    public final static IntegerCodec INT32 = new IntegerCodec(\"int32_t\");\n    public final static IntegerCodec UINT32 = new IntegerCodec(\"uint32_t\");\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/ListCodec.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.auxdatacodec;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.List;\nimport java.util.function.Supplier;\n\npublic class ListCodec<T> implements Codec<List<T>> {\n    private Codec<T> tCodec;\n    private Supplier<List<T>> sup;\n\n    public ListCodec(Codec<T> tc, Supplier<List<T>> s) {\n        this.tCodec = tc;\n        this.sup = s;\n    }\n\n    public String getTypeName() {\n        return \"sequence<\" + this.tCodec.getTypeName() + \">\";\n    }\n\n    public List<T> decode(InputStream in) throws IOException {\n        List<T> al = this.sup.get();\n        long len = LongCodec.decodeStatic(in);\n\n        for (int i = 0; i < len; i++)\n            al.add(this.tCodec.decode(in));\n        return al;\n    }\n\n    public void encode(OutputStream out, List<T> al) throws IOException {\n        LongCodec.encodeStatic(out, (long)al.size());\n        for (T item : al) {\n            this.tCodec.encode(out, item);\n        }\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/LongCodec.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.auxdatacodec;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\n\npublic class LongCodec implements Codec<Long> {\n\n    private String typeName;\n\n    private LongCodec(String tn) { this.typeName = tn; }\n\n    public String getTypeName() { return this.typeName; }\n\n    public static long decodeStatic(InputStream in) throws IOException {\n        byte[] b = new byte[8];\n        if (in.read(b, 0, 8) != 8) {\n            throw new EOFException(\"Insufficient bytes to read a Long from.\");\n        }\n        ByteBuffer bb = ByteBuffer.wrap(b);\n        bb.order(ByteOrder.LITTLE_ENDIAN);\n        return bb.getLong();\n    }\n\n    public Long decode(InputStream in) throws IOException {\n        return new Long(decodeStatic(in));\n    }\n\n    public static void encodeStatic(OutputStream out, long val)\n        throws IOException {\n        byte[] b = new byte[8];\n        ByteBuffer bb = ByteBuffer.wrap(b);\n        bb.order(ByteOrder.LITTLE_ENDIAN);\n        bb.putLong(val);\n        out.write(b, 0, 8);\n    }\n\n    public void encode(OutputStream out, Long val) throws IOException {\n        encodeStatic(out, val);\n    }\n\n    public final static LongCodec INT64 = new LongCodec(\"int64_t\");\n    public final static LongCodec UINT64 = new LongCodec(\"uint64_t\");\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/MapCodec.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.auxdatacodec;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\npublic class MapCodec<K, V> implements Codec<Map<K, V>> {\n    private Codec<K> kCodec;\n    private Codec<V> vCodec;\n    private Supplier<Map<K, V>> sup;\n\n    public MapCodec(Codec<K> kc, Codec<V> vc, Supplier<Map<K, V>> s) {\n        this.kCodec = kc;\n        this.vCodec = vc;\n        this.sup = s;\n    }\n\n    public String getTypeName() {\n        return \"mapping<\" + kCodec.getTypeName() + \",\" + vCodec.getTypeName() +\n            \">\";\n    }\n\n    public Map<K, V> decode(InputStream in) throws IOException {\n        Map<K, V> map = this.sup.get();\n\n        // Size of the map.\n        long len = LongCodec.decodeStatic(in);\n\n        // All the entries.\n        for (int i = 0; i < len; i++) {\n            K key = this.kCodec.decode(in);\n            V val = this.vCodec.decode(in);\n            map.put(key, val);\n        }\n        return map;\n    }\n\n    public void encode(OutputStream out, Map<K, V> map) throws IOException {\n        // Size of the map.\n        LongCodec.encodeStatic(out, (long)map.size());\n\n        // All the entries.\n        for (Map.Entry<K, V> entry : map.entrySet()) {\n            this.kCodec.encode(out, entry.getKey());\n            this.vCodec.encode(out, entry.getValue());\n        }\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/OffsetCodec.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.auxdatacodec;\n\nimport com.grammatech.gtirb.Offset;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.UUID;\n\npublic class OffsetCodec implements Codec<Offset> {\n\n    public String getTypeName() { return \"Offset\"; }\n\n    public Offset decode(InputStream in) throws IOException {\n        UUID uuid = UuidCodec.decodeStatic(in);\n        long disp = LongCodec.decodeStatic(in);\n        return new Offset(uuid, disp);\n    }\n\n    public void encode(OutputStream out, Offset val) throws IOException {\n        UuidCodec.encodeStatic(out, val.getElementId());\n        LongCodec.encodeStatic(out, val.getDisplacement());\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/SetCodec.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.auxdatacodec;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\npublic class SetCodec<T> implements Codec<Set<T>> {\n    private Codec<T> tCodec;\n    private Supplier<Set<T>> sup;\n\n    public SetCodec(Codec<T> tc, Supplier<Set<T>> s) {\n        this.tCodec = tc;\n        this.sup = s;\n    }\n\n    public String getTypeName() {\n        return \"set<\" + this.tCodec.getTypeName() + \">\";\n    }\n\n    public Set<T> decode(InputStream in) throws IOException {\n        Set<T> set = this.sup.get();\n\n        // Size of the set.\n        long len = LongCodec.decodeStatic(in);\n\n        // All the entries.\n        for (int i = 0; i < len; i++) {\n            T item = this.tCodec.decode(in);\n            set.add(item);\n        }\n        return set;\n    }\n\n    public void encode(OutputStream out, Set<T> set) throws IOException {\n        // Size of the set.\n        LongCodec.encodeStatic(out, (long)set.size());\n\n        for (T item : set) {\n            this.tCodec.encode(out, item);\n        }\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/ShortCodec.java",
    "content": "package com.grammatech.gtirb.auxdatacodec;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\n\npublic class ShortCodec implements Codec<Short> {\n\n    private String typeName;\n\n    private ShortCodec(String tn) { this.typeName = tn; }\n\n    public String getTypeName() { return this.typeName; }\n\n    public Short decode(InputStream in) throws IOException {\n        byte[] b = new byte[2];\n        if (in.read(b, 0, 2) != 2) {\n            throw new EOFException(\"Insufficient bytes to read a Short from.\");\n        }\n        ByteBuffer bb = ByteBuffer.wrap(b);\n        bb.order(ByteOrder.LITTLE_ENDIAN);\n        return bb.getShort();\n    }\n\n    public void encode(OutputStream out, Short val) throws IOException {\n        byte[] b = new byte[2];\n        ByteBuffer bb = ByteBuffer.wrap(b);\n        bb.order(ByteOrder.LITTLE_ENDIAN);\n        bb.putShort(val);\n        out.write(b, 0, 2);\n    }\n\n    public final static ShortCodec INT16 = new ShortCodec(\"int16_t\");\n    public final static ShortCodec UINT16 = new ShortCodec(\"uint16_t\");\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/StringCodec.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.auxdatacodec;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\n\n/**\n * A Codec for strings.\n */\npublic class StringCodec implements Codec<String> {\n\n    public String getTypeName() { return \"string\"; }\n\n    public String decode(InputStream in) throws IOException {\n        int length = (int)LongCodec.decodeStatic(in);\n        if (length == 0) {\n            return \"\";\n        }\n        byte[] strBytes = new byte[length];\n        if (in.read(strBytes, 0, length) != length) {\n            throw new EOFException(\n                \"Insufficient bytes to read expected String length.\");\n        }\n\n        return new String(strBytes, StandardCharsets.UTF_8);\n    }\n\n    public void encode(OutputStream out, String val) throws IOException {\n        byte[] strBytes = val.getBytes(StandardCharsets.UTF_8);\n        LongCodec.encodeStatic(out, (long)strBytes.length);\n        out.write(strBytes, 0, strBytes.length);\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/Tuple1Codec.java",
    "content": "package com.grammatech.gtirb.auxdatacodec;\n\nimport com.grammatech.gtirb.tuple.Tuple1;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\npublic class Tuple1Codec<T extends Tuple1<A>, A> implements Codec<T> {\n    private Codec<A> aCodec;\n\n    private Tuple1Maker<T, A> maker;\n\n    public interface Tuple1Maker<T, A> { public T make(A a); }\n\n    public Tuple1Codec(Codec<A> ac, Tuple1Maker<T, A> maker) {\n        this.aCodec = ac;\n        this.maker = maker;\n    }\n\n    public String getTypeName() {\n        return \"tuple<\" + aCodec.getTypeName() + \">\";\n    }\n\n    public T decode(InputStream in) throws IOException {\n        A a = this.aCodec.decode(in);\n        return this.maker.make(a);\n    }\n\n    public void encode(OutputStream out, T val) throws IOException {\n        this.aCodec.encode(out, val.get0());\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/Tuple2Codec.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.auxdatacodec;\n\nimport com.grammatech.gtirb.tuple.Tuple2;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\npublic class Tuple2Codec<T extends Tuple2<A, B>, A, B> implements Codec<T> {\n    private Codec<A> aCodec;\n    private Codec<B> bCodec;\n\n    private Tuple2Maker<T, A, B> maker;\n\n    public interface Tuple2Maker<T, A, B> { public T make(A a, B b); }\n\n    public Tuple2Codec(Codec<A> ac, Codec<B> bc, Tuple2Maker<T, A, B> maker) {\n        this.aCodec = ac;\n        this.bCodec = bc;\n        this.maker = maker;\n    }\n\n    public String getTypeName() {\n        return \"tuple<\" + aCodec.getTypeName() + \",\" + bCodec.getTypeName() +\n            \">\";\n    }\n\n    public T decode(InputStream in) throws IOException {\n        A a = this.aCodec.decode(in);\n        B b = this.bCodec.decode(in);\n        return this.maker.make(a, b);\n    }\n\n    public void encode(OutputStream out, T val) throws IOException {\n        this.aCodec.encode(out, val.get0());\n        this.bCodec.encode(out, val.get1());\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/Tuple3Codec.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.auxdatacodec;\n\nimport com.grammatech.gtirb.tuple.Tuple3;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\npublic class Tuple3Codec<T extends Tuple3<A, B, C>, A, B, C>\n    implements Codec<T> {\n    private Codec<A> aCodec;\n    private Codec<B> bCodec;\n    private Codec<C> cCodec;\n\n    private Tuple3Maker<T, A, B, C> maker;\n\n    public interface Tuple3Maker<T, A, B, C> { public T make(A a, B b, C c); }\n\n    public Tuple3Codec(Codec<A> ac, Codec<B> bc, Codec<C> cc,\n                       Tuple3Maker<T, A, B, C> maker) {\n        this.aCodec = ac;\n        this.bCodec = bc;\n        this.cCodec = cc;\n        this.maker = maker;\n    }\n\n    public String getTypeName() {\n        return \"tuple<\" + aCodec.getTypeName() + \",\" + bCodec.getTypeName() +\n            \",\" + cCodec.getTypeName() + \">\";\n    }\n\n    public T decode(InputStream in) throws IOException {\n        A a = this.aCodec.decode(in);\n        B b = this.bCodec.decode(in);\n        C c = this.cCodec.decode(in);\n        return this.maker.make(a, b, c);\n    }\n\n    public void encode(OutputStream out, T val) throws IOException {\n        this.aCodec.encode(out, val.get0());\n        this.bCodec.encode(out, val.get1());\n        this.cCodec.encode(out, val.get2());\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/Tuple4Codec.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.auxdatacodec;\n\nimport com.grammatech.gtirb.tuple.Tuple4;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\npublic class Tuple4Codec<T extends Tuple4<A, B, C, D>, A, B, C, D>\n    implements Codec<T> {\n    private Codec<A> aCodec;\n    private Codec<B> bCodec;\n    private Codec<C> cCodec;\n    private Codec<D> dCodec;\n\n    private Tuple4Maker<T, A, B, C, D> maker;\n\n    public interface Tuple4Maker<T, A, B, C, D> {\n        public T make(A a, B b, C c, D d);\n    }\n\n    public Tuple4Codec(Codec<A> ac, Codec<B> bc, Codec<C> cc, Codec<D> dc,\n                       Tuple4Maker<T, A, B, C, D> maker) {\n        this.aCodec = ac;\n        this.bCodec = bc;\n        this.cCodec = cc;\n        this.dCodec = dc;\n        this.maker = maker;\n    }\n\n    public String getTypeName() {\n        return \"tuple<\" + aCodec.getTypeName() + \",\" + bCodec.getTypeName() +\n            \",\" + cCodec.getTypeName() + \",\" + dCodec.getTypeName() + \">\";\n    }\n\n    public T decode(InputStream in) throws IOException {\n        A a = this.aCodec.decode(in);\n        B b = this.bCodec.decode(in);\n        C c = this.cCodec.decode(in);\n        D d = this.dCodec.decode(in);\n        return this.maker.make(a, b, c, d);\n    }\n\n    public void encode(OutputStream out, T val) throws IOException {\n        this.aCodec.encode(out, val.get0());\n        this.bCodec.encode(out, val.get1());\n        this.cCodec.encode(out, val.get2());\n        this.dCodec.encode(out, val.get3());\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/Tuple5Codec.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.auxdatacodec;\n\nimport com.grammatech.gtirb.tuple.Tuple5;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\npublic class Tuple5Codec<T extends Tuple5<A, B, C, D, E>, A, B, C, D, E>\n    implements Codec<T> {\n    private Codec<A> aCodec;\n    private Codec<B> bCodec;\n    private Codec<C> cCodec;\n    private Codec<D> dCodec;\n    private Codec<E> eCodec;\n\n    private Tuple5Maker<T, A, B, C, D, E> maker;\n\n    public interface Tuple5Maker<T, A, B, C, D, E> {\n        public T make(A a, B b, C c, D d, E e);\n    }\n\n    public Tuple5Codec(Codec<A> ac, Codec<B> bc, Codec<C> cc, Codec<D> dc,\n                       Codec<E> ec, Tuple5Maker<T, A, B, C, D, E> maker) {\n        this.aCodec = ac;\n        this.bCodec = bc;\n        this.cCodec = cc;\n        this.dCodec = dc;\n        this.eCodec = ec;\n        this.maker = maker;\n    }\n\n    public String getTypeName() {\n        return \"tuple<\" + aCodec.getTypeName() + \",\" + bCodec.getTypeName() +\n            \",\" + cCodec.getTypeName() + \",\" + dCodec.getTypeName() + \",\" +\n            eCodec.getTypeName() + \">\";\n    }\n\n    public T decode(InputStream in) throws IOException {\n        A a = this.aCodec.decode(in);\n        B b = this.bCodec.decode(in);\n        C c = this.cCodec.decode(in);\n        D d = this.dCodec.decode(in);\n        E e = this.eCodec.decode(in);\n        return this.maker.make(a, b, c, d, e);\n    }\n\n    public void encode(OutputStream out, T val) throws IOException {\n        this.aCodec.encode(out, val.get0());\n        this.bCodec.encode(out, val.get1());\n        this.cCodec.encode(out, val.get2());\n        this.dCodec.encode(out, val.get3());\n        this.eCodec.encode(out, val.get4());\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/UuidCodec.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.auxdatacodec;\n\nimport com.grammatech.gtirb.Util;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.UUID;\n\npublic class UuidCodec implements Codec<UUID> {\n\n    public String getTypeName() { return \"UUID\"; }\n\n    public static UUID decodeStatic(InputStream in) throws IOException {\n        return Util.readUUID(in);\n    }\n\n    public UUID decode(InputStream in) throws IOException {\n        return Util.readUUID(in);\n    }\n\n    public static void encodeStatic(OutputStream out, UUID val)\n        throws IOException {\n        Util.writeUUID(out, val);\n    }\n\n    public void encode(OutputStream out, UUID val) throws IOException {\n        Util.writeUUID(out, val);\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/Variant11Codec.java",
    "content": "package com.grammatech.gtirb.auxdatacodec;\n\nimport com.grammatech.gtirb.variant.Variant11;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * A codec for serializing 3-element variants.\n */\npublic class Variant11Codec<\n    T extends Variant11<A, B, C, D, E, F, G, H, I, J, K>, A, B, C, D, E, F, G,\n              H, I, J, K> implements Codec<T> {\n    private Codec<A> aCodec;\n    private Codec<B> bCodec;\n    private Codec<C> cCodec;\n    private Codec<D> dCodec;\n    private Codec<E> eCodec;\n    private Codec<F> fCodec;\n    private Codec<G> gCodec;\n    private Codec<H> hCodec;\n    private Codec<I> iCodec;\n    private Codec<J> jCodec;\n    private Codec<K> kCodec;\n\n    private Variant11Maker<T, A> aMaker;\n    private Variant11Maker<T, B> bMaker;\n    private Variant11Maker<T, C> cMaker;\n    private Variant11Maker<T, D> dMaker;\n    private Variant11Maker<T, E> eMaker;\n    private Variant11Maker<T, F> fMaker;\n    private Variant11Maker<T, G> gMaker;\n    private Variant11Maker<T, H> hMaker;\n    private Variant11Maker<T, I> iMaker;\n    private Variant11Maker<T, J> jMaker;\n    private Variant11Maker<T, K> kMaker;\n\n    public interface Variant11Maker<T, X> { public T make(X x); }\n\n    /**\n     * Construct a codec for 3-element variants.\n     *\n     * @param ac Codec for the first field of the variant.\n     * @param bc Codec for the second field of the variant.\n     * @param cc Codec for the third field of the variant.\n     * @param dc Codec for the fourth field of the variant.\n     * @param ec Codec for the fifth field of the variant.\n     * @param fc Codec for the sixth field of the variant.\n     * @param gc Codec for the seventh field of the variant.\n     * @param hc Codec for the eighth field of the variant.\n     * @param ic Codec for the ninth field of the variant.\n     * @param jc Codec for the tenth field of the variant.\n     * @param kc Codec for the eleventh field of the variant.\n     * @param aMaker Constructor/factory for constructing a variant\n     * with the first field populated.\n     * @param bMaker Constructor/factory for constructing a variant\n     * with the second field populated.\n     * @param cMaker Constructor/factory for constructing a variant\n     * with the third field populated.\n     * @param dMaker Constructor/factory for constructing a variant\n     * with the fourth field populated.\n     * @param eMaker Constructor/factory for constructing a variant\n     * with the fifth field populated.\n     * @param fMaker Constructor/factory for constructing a variant\n     * with the sixth field populated.\n     * @param gMaker Constructor/factory for constructing a variant\n     * with the seventh field populated.\n     * @param hMaker Constructor/factory for constructing a variant\n     * with the eighth field populated.\n     * @param iMaker Constructor/factory for constructing a variant\n     * with the ninth field populated.\n     * @param jMaker Constructor/factory for constructing a variant\n     * with the tenth field populated.\n     * @param kMaker Constructor/factory for constructing a variant\n     * with the eleventh field populated.\n     */\n    public Variant11Codec(\n        Codec<A> ac, Codec<B> bc, Codec<C> cc, Codec<D> dc, Codec<E> ec,\n        Codec<F> fc, Codec<G> gc, Codec<H> hc, Codec<I> ic, Codec<J> jc,\n        Codec<K> kc, Variant11Maker<T, A> aMaker, Variant11Maker<T, B> bMaker,\n        Variant11Maker<T, C> cMaker, Variant11Maker<T, D> dMaker,\n        Variant11Maker<T, E> eMaker, Variant11Maker<T, F> fMaker,\n        Variant11Maker<T, G> gMaker, Variant11Maker<T, H> hMaker,\n        Variant11Maker<T, I> iMaker, Variant11Maker<T, J> jMaker,\n        Variant11Maker<T, K> kMaker) {\n        this.aCodec = ac;\n        this.bCodec = bc;\n        this.cCodec = cc;\n        this.dCodec = dc;\n        this.eCodec = ec;\n        this.fCodec = fc;\n        this.gCodec = gc;\n        this.hCodec = hc;\n        this.iCodec = ic;\n        this.jCodec = jc;\n        this.kCodec = kc;\n        this.aMaker = aMaker;\n        this.bMaker = bMaker;\n        this.cMaker = cMaker;\n        this.dMaker = dMaker;\n        this.eMaker = eMaker;\n        this.fMaker = fMaker;\n        this.gMaker = gMaker;\n        this.hMaker = hMaker;\n        this.iMaker = iMaker;\n        this.jMaker = jMaker;\n        this.kMaker = kMaker;\n    }\n\n    public String getTypeName() {\n        return \"variant<\" + aCodec.getTypeName() + \",\" + bCodec.getTypeName() +\n            \",\" + cCodec.getTypeName() + \",\" + dCodec.getTypeName() + \",\" +\n            eCodec.getTypeName() + \",\" + fCodec.getTypeName() + \",\" +\n            gCodec.getTypeName() + \",\" + hCodec.getTypeName() + \",\" +\n            iCodec.getTypeName() + \",\" + jCodec.getTypeName() + \",\" +\n            kCodec.getTypeName() + \">\";\n    }\n\n    public T decode(InputStream in) throws IOException {\n        int idx = (int)LongCodec.decodeStatic(in);\n        switch (idx) {\n        case 0: {\n            A a = this.aCodec.decode(in);\n            return this.aMaker.make(a);\n        }\n        case 1: {\n            B b = this.bCodec.decode(in);\n            return this.bMaker.make(b);\n        }\n        case 2: {\n            C c = this.cCodec.decode(in);\n            return this.cMaker.make(c);\n        }\n        case 3: {\n            D d = this.dCodec.decode(in);\n            return this.dMaker.make(d);\n        }\n        case 4: {\n            E e = this.eCodec.decode(in);\n            return this.eMaker.make(e);\n        }\n        case 5: {\n            F f = this.fCodec.decode(in);\n            return this.fMaker.make(f);\n        }\n        case 6: {\n            G g = this.gCodec.decode(in);\n            return this.gMaker.make(g);\n        }\n        case 7: {\n            H h = this.hCodec.decode(in);\n            return this.hMaker.make(h);\n        }\n        case 8: {\n            I i = this.iCodec.decode(in);\n            return this.iMaker.make(i);\n        }\n        case 9: {\n            J j = this.jCodec.decode(in);\n            return this.jMaker.make(j);\n        }\n        case 10: {\n            K k = this.kCodec.decode(in);\n            return this.kMaker.make(k);\n        }\n        }\n        throw new IOException(\"Unexpected variant index: \" + idx);\n    }\n\n    public void encode(OutputStream out, T val) throws IOException {\n        int idx = val.getIndex();\n        LongCodec.encodeStatic(out, (long)idx);\n        switch (idx) {\n        case 0: {\n            this.aCodec.encode(out, val.get0().get());\n            break;\n        }\n        case 1: {\n            this.bCodec.encode(out, val.get1().get());\n            break;\n        }\n        case 2: {\n            this.cCodec.encode(out, val.get2().get());\n            break;\n        }\n        case 3: {\n            this.dCodec.encode(out, val.get3().get());\n            break;\n        }\n        case 4: {\n            this.eCodec.encode(out, val.get4().get());\n            break;\n        }\n        case 5: {\n            this.fCodec.encode(out, val.get5().get());\n            break;\n        }\n        case 6: {\n            this.gCodec.encode(out, val.get6().get());\n            break;\n        }\n        case 7: {\n            this.hCodec.encode(out, val.get7().get());\n            break;\n        }\n        case 8: {\n            this.iCodec.encode(out, val.get8().get());\n            break;\n        }\n        case 9: {\n            this.jCodec.encode(out, val.get9().get());\n            break;\n        }\n        case 10: {\n            this.kCodec.encode(out, val.get10().get());\n            break;\n        }\n        default: {\n            assert false;\n        }\n        }\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/Variant2Codec.java",
    "content": "package com.grammatech.gtirb.auxdatacodec;\n\nimport com.grammatech.gtirb.variant.Variant2;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * A codec for serializing 2-element variants.\n */\npublic class Variant2Codec<T extends Variant2<A, B>, A, B> implements Codec<T> {\n    private Codec<A> aCodec;\n    private Codec<B> bCodec;\n\n    private Variant2Maker<T, A> aMaker;\n    private Variant2Maker<T, B> bMaker;\n\n    public interface Variant2Maker<T, X> { public T make(X x); }\n\n    /**\n     * Construct a codec for 2-element variants.\n     *\n     * @param ac Codec for the first field of the variant.\n     * @param bc Codec for the second field of the variant.\n     * @param aMaker Constructor/factory for constructing a variant\n     * with the first field populated.\n     * @param bMaker Constructor/factory for constructing a variant\n     * with the second field populated.\n     */\n    public Variant2Codec(Codec<A> ac, Codec<B> bc, Variant2Maker<T, A> aMaker,\n                         Variant2Maker<T, B> bMaker) {\n        this.aCodec = ac;\n        this.bCodec = bc;\n        this.aMaker = aMaker;\n        this.bMaker = bMaker;\n    }\n\n    public String getTypeName() {\n        return \"variant<\" + aCodec.getTypeName() + \",\" + bCodec.getTypeName() +\n            \">\";\n    }\n\n    public T decode(InputStream in) throws IOException {\n        int idx = (int)LongCodec.decodeStatic(in);\n        switch (idx) {\n        case 0: {\n            A a = this.aCodec.decode(in);\n            return this.aMaker.make(a);\n        }\n        case 1: {\n            B b = this.bCodec.decode(in);\n            return this.bMaker.make(b);\n        }\n        }\n        throw new IOException(\"Unexpected variant index: \" + idx);\n    }\n\n    public void encode(OutputStream out, T val) throws IOException {\n        int idx = val.getIndex();\n        LongCodec.encodeStatic(out, (long)idx);\n        switch (idx) {\n        case 0: {\n            this.aCodec.encode(out, val.get0().get());\n            break;\n        }\n        case 1: {\n            this.bCodec.encode(out, val.get1().get());\n            break;\n        }\n        default: {\n            assert false;\n        }\n        }\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/auxdatacodec/Variant3Codec.java",
    "content": "package com.grammatech.gtirb.auxdatacodec;\n\nimport com.grammatech.gtirb.variant.Variant3;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * A codec for serializing 3-element variants.\n */\npublic class Variant3Codec<T extends Variant3<A, B, C>, A, B, C>\n    implements Codec<T> {\n    private Codec<A> aCodec;\n    private Codec<B> bCodec;\n    private Codec<C> cCodec;\n\n    private Variant3Maker<T, A> aMaker;\n    private Variant3Maker<T, B> bMaker;\n    private Variant3Maker<T, C> cMaker;\n\n    public interface Variant3Maker<T, X> { public T make(X a); }\n\n    /**\n     * Construct a codec for 3-element variants.\n     *\n     * @param ac Codec for the first field of the variant.\n     * @param bc Codec for the second field of the variant.\n     * @param cc Codec for the third field of the variant.\n     * @param aMaker Constructor/factory for constructing a variant\n     * with the first field populated.\n     * @param bMaker Constructor/factory for constructing a variant\n     * with the second field populated.\n     * @param cMaker Constructor/factory for constructing a variant\n     * with the third field populated.\n     */\n    public Variant3Codec(Codec<A> ac, Codec<B> bc, Codec<C> cc,\n                         Variant3Maker<T, A> aMaker, Variant3Maker<T, B> bMaker,\n                         Variant3Maker<T, C> cMaker) {\n        this.aCodec = ac;\n        this.bCodec = bc;\n        this.cCodec = cc;\n        this.aMaker = aMaker;\n        this.bMaker = bMaker;\n        this.cMaker = cMaker;\n    }\n\n    public String getTypeName() {\n        return \"variant<\" + aCodec.getTypeName() + \",\" + bCodec.getTypeName() +\n            \",\" + cCodec.getTypeName() + \">\";\n    }\n\n    public T decode(InputStream in) throws IOException {\n        int idx = (int)LongCodec.decodeStatic(in);\n        switch (idx) {\n        case 0: {\n            A a = this.aCodec.decode(in);\n            return this.aMaker.make(a);\n        }\n        case 1: {\n            B b = this.bCodec.decode(in);\n            return this.bMaker.make(b);\n        }\n        case 2: {\n            C c = this.cCodec.decode(in);\n            return this.cMaker.make(c);\n        }\n        }\n        throw new IOException(\"Unexpected variant index: \" + idx);\n    }\n\n    public void encode(OutputStream out, T val) throws IOException {\n        int idx = val.getIndex();\n        LongCodec.encodeStatic(out, (long)idx);\n        switch (idx) {\n        case 0: {\n            this.aCodec.encode(out, val.get0().get());\n            break;\n        }\n        case 1: {\n            this.bCodec.encode(out, val.get1().get());\n            break;\n        }\n        case 2: {\n            this.cCodec.encode(out, val.get2().get());\n            break;\n        }\n        default: {\n            assert false;\n        }\n        }\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/tuple/Tuple1.java",
    "content": "package com.grammatech.gtirb.tuple;\n\n/**\n * Immutable collection of one element of any type.\n *\n * Note that this class is abstract. Intended use is to extend this\n * class with a simple wrapper that uses named getters/setters.\n */\npublic abstract class Tuple1<A> {\n\n    private final A first;\n\n    /**\n     * Class constructor for a Tuple1. Once created, a tuple cannot be\n     * modified.\n     * @param  first  The first element of the tuple.\n     */\n    protected Tuple1(A first) { this.first = first; }\n\n    /**\n     * Get the first element of the {@link Tuple1}.\n     *\n     * @return  The first element.\n     */\n    public A get0() { return this.first; }\n\n    /**\n     * Implementation of deep equality.\n     * @param other The other object to compare equality against\n     * @return True of other is equal to this object.\n     */\n    @Override\n    public boolean equals(Object other) {\n        if (other == this) {\n            return true;\n        }\n\n        if (!(other instanceof Tuple1<?>)) {\n            return false;\n        }\n\n        Tuple1<?> asTuple1 = (Tuple1<?>)other;\n        return this.first.equals(asTuple1.first);\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/tuple/Tuple2.java",
    "content": "/*\n *  Copyright (C) 2020-2023 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.tuple;\n\n/**\n * Immutable collection of two elements of any type.\n *\n * Note that this class is abstract. Intended use is to extend this\n * class with a simple wrapper that uses named getters/setters.\n */\npublic abstract class Tuple2<A, B> {\n\n    private final A first;\n    private final B second;\n\n    /**\n     * Class constructor for a Tuple2. Once created, a tuple cannot be\n     * modified.\n     * @param  first  The first element of the tuple.\n     * @param  second  The second element of the tuple.\n     */\n    protected Tuple2(A first, B second) {\n        this.first = first;\n        this.second = second;\n    }\n\n    /**\n     * Get the first element of the {@link Tuple2}.\n     *\n     * @return  The first element.\n     */\n    public A get0() { return this.first; }\n\n    /**\n     * Get the second element of the {@link Tuple2}.\n     *\n     * @return  The second element.\n     */\n    public B get1() { return this.second; }\n\n    /**\n     * Implementation of deep equality.\n     * @param other The other object to compare equality against\n     * @return True of other is equal to this object.\n     */\n    @Override\n    public boolean equals(Object other) {\n        if (other == this) {\n            return true;\n        }\n\n        if (!(other instanceof Tuple2<?, ?>)) {\n            return false;\n        }\n\n        Tuple2<?, ?> asTuple2 = (Tuple2<?, ?>)other;\n        return this.first.equals(asTuple2.first) &&\n            this.second.equals(asTuple2.second);\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/tuple/Tuple3.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.tuple;\n\n/**\n * Immutable collection of three elements of any type.\n *\n * Note that this class is abstract. Intended use is to extend this\n * class with a simple wrapper that uses named getters/setters.\n */\npublic abstract class Tuple3<A, B, C> {\n\n    private final A first;\n    private final B second;\n    private final C third;\n\n    /**\n     * Class constructor for a Tuple3. Once created, a tuple cannot be\n     * modified.\n     * @param  first  The first element of the tuple.\n     * @param  second  The second element of the tuple.\n     * @param  third  The third element of the tuple.\n     */\n    protected Tuple3(A first, B second, C third) {\n        this.first = first;\n        this.second = second;\n        this.third = third;\n    }\n\n    /**\n     * Get the first element of the {@link Tuple3}.\n     *\n     * @return  The first element.\n     */\n    public A get0() { return this.first; }\n\n    /**\n     * Get the second element of the {@link Tuple3}.\n     *\n     * @return  The second element.\n     */\n    public B get1() { return this.second; }\n\n    /**\n     * Get the third element of the {@link Tuple3}.\n     *\n     * @return  The third element.\n     */\n    public C get2() { return this.third; }\n\n    /**\n     * Implementation of deep equality.\n     * @param other The other object to compare equality against\n     * @return True of other is equal to this object.\n     */\n    @Override\n    public boolean equals(Object other) {\n        if (other == this) {\n            return true;\n        }\n\n        if (!(other instanceof Tuple3<?, ?, ?>)) {\n            return false;\n        }\n\n        Tuple3<?, ?, ?> asTuple3 = (Tuple3<?, ?, ?>)other;\n        return this.first.equals(asTuple3.first) &&\n            this.second.equals(asTuple3.second) &&\n            this.third.equals(asTuple3.third);\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/tuple/Tuple4.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.tuple;\n\n/**\n * Immutable collection of four elements of any type.\n *\n * Note that this class is abstract. Intended use is to extend this\n * class with a simple wrapper that uses named getters/setters.\n */\npublic abstract class Tuple4<A, B, C, D> {\n\n    private final A first;\n    private final B second;\n    private final C third;\n    private final D fourth;\n\n    /**\n     * Class constructor for a Tuple4. Once created, a tuple cannot be\n     * modified.\n     * @param  first  The first element of the tuple.\n     * @param  second  The second element of the tuple.\n     * @param  third  The third element of the tuple.\n     * @param  fourth  The fourth element of the tuple.\n     */\n    protected Tuple4(A first, B second, C third, D fourth) {\n        this.first = first;\n        this.second = second;\n        this.third = third;\n        this.fourth = fourth;\n    }\n\n    /**\n     * Get the first element of the {@link Tuple4}.\n     *\n     * @return  The first element.\n     */\n    public A get0() { return this.first; }\n\n    /**\n     * Get the second element of the {@link Tuple4}.\n     *\n     * @return  The second element.\n     */\n    public B get1() { return this.second; }\n\n    /**\n     * Get the third element of the {@link Tuple4}.\n     *\n     * @return  The third element.\n     */\n    public C get2() { return this.third; }\n\n    /**\n     * Get the fourth element of the {@link Tuple4}.\n     *\n     * @return  The fourth element.\n     */\n    public D get3() { return this.fourth; }\n\n    /**\n     * Implementation of deep equality.\n     * @param other The other object to compare equality against\n     * @return True of other is equal to this object.\n     */\n    @Override\n    public boolean equals(Object other) {\n        if (other == this) {\n            return true;\n        }\n\n        if (!(other instanceof Tuple4<?, ?, ?, ?>)) {\n            return false;\n        }\n\n        Tuple4<?, ?, ?, ?> asTuple4 = (Tuple4<?, ?, ?, ?>)other;\n        return this.first.equals(asTuple4.first) &&\n            this.second.equals(asTuple4.second) &&\n            this.third.equals(asTuple4.third) &&\n            this.fourth.equals(asTuple4.fourth);\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/tuple/Tuple5.java",
    "content": "/*\n *  Copyright (C) 2020-2021 GrammaTech, Inc.\n *\n *  This code is licensed under the MIT license. See the LICENSE file in the\n *  project root for license terms.\n *\n *  This project is sponsored by the Office of Naval Research, One Liberty\n *  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n *  N68335-17-C-0700.  The content of the information does not necessarily\n *  reflect the position or policy of the Government and no official\n *  endorsement should be inferred.\n *\n */\n\npackage com.grammatech.gtirb.tuple;\n\n/**\n * Immutable collection of five elements of any type.\n *\n * Note that this class is abstract. Intended use is to extend this\n * class with a simple wrapper that uses named getters/setters.\n */\npublic abstract class Tuple5<A, B, C, D, E> {\n\n    private final A first;\n    private final B second;\n    private final C third;\n    private final D fourth;\n    private final E fifth;\n\n    /**\n     * Class constructor for a Tuple5. Once created, a tuple cannot be\n     * modified.\n     * @param  first  The first element of the tuple.\n     * @param  second  The second element of the tuple.\n     * @param  third  The third element of the tuple.\n     * @param  fourth  The fourth element of the tuple.\n     * @param  fifth  The fifth element of the tuple.\n     */\n    protected Tuple5(A first, B second, C third, D fourth, E fifth) {\n        this.first = first;\n        this.second = second;\n        this.third = third;\n        this.fourth = fourth;\n        this.fifth = fifth;\n    }\n\n    /**\n     * Get the first element of the {@link Tuple5}.\n     *\n     * @return  The first element.\n     */\n    public A get0() { return this.first; }\n\n    /**\n     * Get the second element of the {@link Tuple5}.\n     *\n     * @return  The second element.\n     */\n    public B get1() { return this.second; }\n\n    /**\n     * Get the third element of the {@link Tuple5}.\n     *\n     * @return  The third element.\n     */\n    public C get2() { return this.third; }\n\n    /**\n     * Get the fourth element of the {@link Tuple5}.\n     *\n     * @return  The fourth element.\n     */\n    public D get3() { return this.fourth; }\n\n    /**\n     * Get the fifth element of the {@link Tuple5}.\n     *\n     * @return  The fifth element.\n     */\n    public E get4() { return this.fifth; }\n\n    /**\n     * Implementation of deep equality.\n     * @param other The other object to compare equality against\n     * @return True of other is equal to this object.\n     */\n    @Override\n    public boolean equals(Object other) {\n        if (other == this) {\n            return true;\n        }\n\n        if (!(other instanceof Tuple5<?, ?, ?, ?, ?>)) {\n            return false;\n        }\n\n        Tuple5<?, ?, ?, ?, ?> asTuple5 = (Tuple5<?, ?, ?, ?, ?>)other;\n        return this.first.equals(asTuple5.first) &&\n            this.second.equals(asTuple5.second) &&\n            this.third.equals(asTuple5.third) &&\n            this.fourth.equals(asTuple5.fourth) &&\n            this.fifth.equals(asTuple5.fifth);\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/variant/Token.java",
    "content": "package com.grammatech.gtirb.variant;\n\n/**\n * This class contains a bunch of marker classes that are used\n * exlusively to control variant construction. An instance of\n * the class TX can be passed to the variant's constructor to\n * indicate that the constructor is being initialized with the\n * Xth field in the variant.\n */\npublic class Token {\n    public static class T0 {}\n    public static class T1 {}\n    public static class T2 {}\n    public static class T3 {}\n    public static class T4 {}\n    public static class T5 {}\n    public static class T6 {}\n    public static class T7 {}\n    public static class T8 {}\n    public static class T9 {}\n    public static class T10 {}\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/variant/Variant11.java",
    "content": "package com.grammatech.gtirb.variant;\n\nimport java.util.Optional;\n\n/**\n * A 11-valued variant. The variant can store a single object that is\n * of one of the generic parameter types provided.\n *\n * Note that this class is abstract. Intended use is to extend this\n * class with a simple wrapper that uses named getters/setters.\n */\npublic abstract class Variant11<A, B, C, D, E, F, G, H, I, J, K> {\n    private Object o;\n    private int index;\n\n    /**\n     * Initialize the variant with an object of the first type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant11(Token.T0 tok, A o) {\n        this.index = 0;\n        this.o = o;\n    }\n\n    /**\n     * Initialize the variant with an object of the second type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant11(Token.T1 tok, B o) {\n        this.index = 1;\n        this.o = o;\n    }\n\n    /**\n     * Initialize the variant with an object of the third type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant11(Token.T2 tok, C o) {\n        this.index = 2;\n        this.o = o;\n    }\n\n    /**\n     * Initialize the variant with an object of the fourth type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant11(Token.T3 tok, D o) {\n        this.index = 3;\n        this.o = o;\n    }\n\n    /**\n     * Initialize the variant with an object of the fifth type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant11(Token.T4 tok, E o) {\n        this.index = 4;\n        this.o = o;\n    }\n\n    /**\n     * Initialize the variant with an object of the sixth type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant11(Token.T5 tok, F o) {\n        this.index = 5;\n        this.o = o;\n    }\n\n    /**\n     * Initialize the variant with an object of the seventh type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant11(Token.T6 tok, G o) {\n        this.index = 6;\n        this.o = o;\n    }\n\n    /**\n     * Initialize the variant with an object of the eighth type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant11(Token.T7 tok, H o) {\n        this.index = 7;\n        this.o = o;\n    }\n\n    /**\n     * Initialize the variant with an object of the ninth type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant11(Token.T8 tok, I o) {\n        this.index = 8;\n        this.o = o;\n    }\n\n    /**\n     * Initialize the variant with an object of the tenth type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant11(Token.T9 tok, J o) {\n        this.index = 9;\n        this.o = o;\n    }\n\n    /**\n     * Initialize the variant with an object of the eleventh type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant11(Token.T10 tok, K o) {\n        this.index = 10;\n        this.o = o;\n    }\n\n    /**\n     * Get the field index that is populated in this variant.\n     *\n     * @return The index (0-based) of the field of the variant.\n     */\n    public int getIndex() { return this.index; }\n\n    /**\n     * Get the object in the first field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n    public Optional<A> get0() {\n        if (this.index == 0) {\n            @SuppressWarnings(\"unchecked\") A a = (A)o;\n            return Optional.of(a);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Get the object in the second field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n    public Optional<B> get1() {\n        if (this.index == 1) {\n            @SuppressWarnings(\"unchecked\") B b = (B)o;\n            return Optional.of(b);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Get the object in the third field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n    public Optional<C> get2() {\n        if (this.index == 2) {\n            @SuppressWarnings(\"unchecked\") C c = (C)o;\n            return Optional.of(c);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Get the object in the fourth field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n    public Optional<D> get3() {\n        if (this.index == 3) {\n            @SuppressWarnings(\"unchecked\") D d = (D)o;\n            return Optional.of(d);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Get the object in the fifth field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n\n    public Optional<E> get4() {\n        if (this.index == 4) {\n            @SuppressWarnings(\"unchecked\") E e = (E)o;\n            return Optional.of(e);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Get the object in the sixth field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n    public Optional<F> get5() {\n        if (this.index == 5) {\n            @SuppressWarnings(\"unchecked\") F f = (F)o;\n            return Optional.of(f);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Get the object in the seventh field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n    public Optional<G> get6() {\n        if (this.index == 6) {\n            @SuppressWarnings(\"unchecked\") G g = (G)o;\n            return Optional.of(g);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Get the object in the eighth field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n    public Optional<H> get7() {\n        if (this.index == 7) {\n            @SuppressWarnings(\"unchecked\") H h = (H)o;\n            return Optional.of(h);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Get the object in the ninth field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n    public Optional<I> get8() {\n        if (this.index == 8) {\n            @SuppressWarnings(\"unchecked\") I i = (I)o;\n            return Optional.of(i);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Get the object in the tenth field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n    public Optional<J> get9() {\n        if (this.index == 9) {\n            @SuppressWarnings(\"unchecked\") J j = (J)o;\n            return Optional.of(j);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Get the object in the eleventh field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n    public Optional<K> get10() {\n        if (this.index == 10) {\n            @SuppressWarnings(\"unchecked\") K k = (K)o;\n            return Optional.of(k);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Set the first field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set0(A o) {\n        this.index = 0;\n        this.o = o;\n    }\n\n    /**\n     * Set the second field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set1(B o) {\n        this.index = 1;\n        this.o = o;\n    }\n\n    /**\n     * Set the third field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set2(C o) {\n        this.index = 2;\n        this.o = o;\n    }\n\n    /**\n     * Set the fourth field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set3(D o) {\n        this.index = 3;\n        this.o = o;\n    }\n\n    /**\n     * Set the fifth field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set4(E o) {\n        this.index = 4;\n        this.o = o;\n    }\n\n    /**\n     * Set the sixth field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set5(F o) {\n        this.index = 5;\n        this.o = o;\n    }\n\n    /**\n     * Set the seventh field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set6(G o) {\n        this.index = 6;\n        this.o = o;\n    }\n\n    /**\n     * Set the eighth field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set7(H o) {\n        this.index = 7;\n        this.o = o;\n    }\n\n    /**\n     * Set the ninth field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set8(I o) {\n        this.index = 8;\n        this.o = o;\n    }\n\n    /**\n     * Set the tenth field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set9(J o) {\n        this.index = 9;\n        this.o = o;\n    }\n\n    /**\n     * Set the eleventh field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set10(K o) {\n        this.index = 10;\n        this.o = o;\n    }\n\n    /**\n     * Implementation of deep equality.\n     * @param other The other object to compare equality against\n     * @return True of other is equal to this object.\n     */\n    @Override\n    public boolean equals(Object other) {\n        if (other == this) {\n            return true;\n        }\n\n        if (!(other instanceof Variant11<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?>)) {\n            return false;\n        }\n\n        Variant11<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> asVariant =\n            (Variant11<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?>)other;\n        return this.index == asVariant.index && this.o.equals(asVariant.o);\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/variant/Variant2.java",
    "content": "package com.grammatech.gtirb.variant;\n\nimport java.util.Optional;\n\n/**\n * A 2-valued variant. The variant can store a single object that is\n * of one of the generic parameter types provided.\n *\n * Note that this class is abstract. Intended use is to extend this\n * class with a simple wrapper that uses named getters/setters.\n */\npublic abstract class Variant2<A, B> {\n    private Object o;\n    private int index;\n\n    /**\n     * Initialize the variant with an object of the first type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant2(Token.T0 tok, A o) {\n        this.index = 0;\n        this.o = o;\n    }\n\n    /**\n     * Initialize the variant with an object of the second type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant2(Token.T1 tok, B o) {\n        this.index = 1;\n        this.o = o;\n    }\n\n    /**\n     * Get the field index that is populated in this variant.\n     *\n     * @return The index (0-based) of the field of the variant.\n     */\n    public int getIndex() { return this.index; }\n\n    /**\n     * Get the object in the first field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n    public Optional<A> get0() {\n        if (this.index == 0) {\n            @SuppressWarnings(\"unchecked\") A a = (A)o;\n            return Optional.of(a);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Get the object in the second field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n    public Optional<B> get1() {\n        if (this.index == 1) {\n            @SuppressWarnings(\"unchecked\") B b = (B)o;\n            return Optional.of(b);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Set the first field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set0(A o) {\n        this.index = 0;\n        this.o = o;\n    }\n\n    /**\n     * Set the second field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set1(B o) {\n        this.index = 1;\n        this.o = o;\n    }\n\n    /**\n     * Implementation of deep equality.\n     * @param other The other object to compare equality against\n     * @return True of other is equal to this object.\n     */\n    @Override\n    public boolean equals(Object other) {\n        if (other == this) {\n            return true;\n        }\n\n        if (!(other instanceof Variant2<?, ?>)) {\n            return false;\n        }\n\n        Variant2<?, ?> asVariant = (Variant2<?, ?>)other;\n        return this.index == asVariant.index && this.o.equals(asVariant.o);\n    }\n}\n"
  },
  {
    "path": "java/com/grammatech/gtirb/variant/Variant3.java",
    "content": "package com.grammatech.gtirb.variant;\n\nimport java.util.Optional;\n\n/**\n * A 3-valued variant. The variant can store a single object that is\n * of one of the generic parameter types provided.\n *\n * Note that this class is abstract. Intended use is to extend this\n * class with a simple wrapper that uses named getters/setters.\n */\npublic abstract class Variant3<A, B, C> {\n    private Object o;\n    private int index;\n\n    /**\n     * Initialize the variant with an object of the first type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant3(Token.T0 tok, A o) {\n        this.index = 0;\n        this.o = o;\n    }\n\n    /**\n     * Initialize the variant with an object of the second type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant3(Token.T1 tok, B o) {\n        this.index = 1;\n        this.o = o;\n    }\n\n    /**\n     * Initialize the variant with an object of the third type.\n     *\n     * @param tok This is a marker parameter indicating which\n     * field of the variant is to be populated by the constructor.\n     * @param o The object to populate the variant with.\n     */\n    protected Variant3(Token.T2 tok, C o) {\n        this.index = 2;\n        this.o = o;\n    }\n\n    /**\n     * Get the field index that is populated in this variant.\n     *\n     * @return The index (0-based) of the field of the variant.\n     */\n    public int getIndex() { return this.index; }\n\n    /**\n     * Get the object in the first field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n    public Optional<A> get0() {\n        if (this.index == 0) {\n            @SuppressWarnings(\"unchecked\") A a = (A)o;\n            return Optional.of(a);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Get the object in the second field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n    public Optional<B> get1() {\n        if (this.index == 1) {\n            @SuppressWarnings(\"unchecked\") B b = (B)o;\n            return Optional.of(b);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Get the object in the third field of the variant.\n     *\n     * @return If the field in the variant is populated, the return\n     * value is the populated object wrapped in Optional. Otherwise\n     * returns Optional.empty().\n     */\n    public Optional<C> get2() {\n        if (this.index == 2) {\n            @SuppressWarnings(\"unchecked\") C c = (C)o;\n            return Optional.of(c);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Set the first field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set0(A o) {\n        this.index = 0;\n        this.o = o;\n    }\n\n    /**\n     * Set the second field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set1(B o) {\n        this.index = 1;\n        this.o = o;\n    }\n\n    /**\n     * Set the third field of the variant. If any other field\n     * is populated, that field is dropped.\n     *\n     * @param o The object to populate the field with.\n     */\n    public void set2(C o) {\n        this.index = 2;\n        this.o = o;\n    }\n\n    /**\n     * Implementation of deep equality.\n     * @param other The other object to compare equality against\n     * @return True of other is equal to this object.\n     */\n    @Override\n    public boolean equals(Object other) {\n        if (other == this) {\n            return true;\n        }\n\n        if (!(other instanceof Variant3<?, ?, ?>)) {\n            return false;\n        }\n\n        Variant3<?, ?, ?> asVariant = (Variant3<?, ?, ?>)other;\n        return this.index == asVariant.index && this.o.equals(asVariant.o);\n    }\n}\n"
  },
  {
    "path": "java/pom.xml.in",
    "content": "<project>\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>com.grammatech.gtirb</groupId>\n  <artifactId>gtirb_api</artifactId>\n  <version>\n    @PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@@GTIRB_JAVA_SNAPSHOT_SUFFIX@\n  </version>\n\n  <name>${project.groupId}:${project.artifactId}</name>\n  <description>\n    The GrammaTech Intermediate Representation for Binaries (GTIRB) is a\n    machine code analysis and rewriting data structure.\n  </description>\n  <url>https://github.com/GrammaTech/gtirb</url>\n\n  <licenses>\n    <license>\n      <name>MIT License</name>\n      <url>\n        https://raw.githubusercontent.com/GrammaTech/gtirb/master/LICENSE.txt\n      </url>\n    </license>\n  </licenses>\n\n  <developers>\n    <developer>\n      <name>Timothy Neale</name>\n      <email>tneale@grammatech.com</email>\n      <organization>GrammaTech</organization>\n      <organizationUrl>https://www.grammatech.com/</organizationUrl>\n    </developer>\n  </developers>\n\n  <scm>\n    <connection>scm:git:git://github.com/GrammaTech/gtirb.git</connection>\n    <developerConnection>scm:git:ssh://github.com:GrammaTech/gtirb.git</developerConnection>\n    <url>http://github.com/GrammaTech/gtirb/tree/master</url>\n  </scm>\n\n  <distributionManagement>\n    <snapshotRepository>\n      <id>central</id>\n      <url>https://central.sonatype.com/repository/maven-snapshots/</url>\n    </snapshotRepository>\n    <repository>\n      <id>central</id>\n      <url>https://central.sonatype.com/</url>\n    </repository>\n  </distributionManagement>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <maven.compiler.source>1.8</maven.compiler.source>\n    <maven.compiler.target>1.8</maven.compiler.target>\n  </properties>\n\n  <build>\n    <sourceDirectory>src</sourceDirectory>\n    <plugins>\n      <plugin>\n        <groupId>org.sonatype.central</groupId>\n        <artifactId>central-publishing-maven-plugin</artifactId>\n        <version>0.8.0</version>\n        <extensions>true</extensions>\n        <configuration>\n          <publishingServerId>central</publishingServerId>\n          <autoPublish>true</autoPublish>\n        </configuration>\n      </plugin>\n\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-source-plugin</artifactId>\n        <version>3.2.1</version>\n        <executions>\n          <execution>\n            <id>attach-sources</id>\n            <goals>\n              <goal>jar</goal>\n            </goals>\n          </execution>\n        </executions>\n      </plugin>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-javadoc-plugin</artifactId>\n        <version>3.3.1</version>\n        <configuration>\n          <detectJavaApiLink>false</detectJavaApiLink>\n          <excludePackageNames>com.grammatech.gtirb.proto</excludePackageNames>\n        </configuration>\n        <executions>\n          <execution>\n            <id>attach-javadocs</id>\n            <goals>\n              <goal>jar</goal>\n            </goals>\n          </execution>\n        </executions>\n      </plugin>\n\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-gpg-plugin</artifactId>\n        <version>1.5</version>\n        <configuration>\n          <useAgent>true</useAgent>\n        </configuration>\n        <executions>\n          <execution>\n            <id>sign-artifacts</id>\n            <phase>verify</phase>\n            <goals>\n              <goal>sign</goal>\n            </goals>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n  </build>\n\n  <dependencies>\n    <dependency>\n      <groupId>com.google.protobuf</groupId>\n      <artifactId>protobuf-java</artifactId>\n      <version>[@Protobuf_VERSION@,@GTIRB_PROTOBUF_UPPER_BOUND@)</version>\n    </dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "java/settings.gradle",
    "content": "/*\n * This file was generated by the Gradle 'init' task.\n *\n * The settings file is used to specify which projects to include in your build.\n *\n * Detailed information about configuring a multi-project build in Gradle can be found\n * in the user manual at https://docs.gradle.org/5.6.4/userguide/multi_project_builds.html\n */\n\nrootProject.name = 'gtirb'\n"
  },
  {
    "path": "java/tests/TestAuxData.java",
    "content": "package tests;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport com.grammatech.gtirb.AuxDataContainer;\nimport com.grammatech.gtirb.AuxDataSchema;\nimport com.grammatech.gtirb.AuxDataSchemas;\nimport com.grammatech.gtirb.IR;\nimport com.grammatech.gtirb.Module;\nimport com.grammatech.gtirb.Offset;\nimport com.grammatech.gtirb.ProxyBlock;\nimport com.grammatech.gtirb.Section;\nimport com.grammatech.gtirb.Symbol;\nimport com.grammatech.gtirb.auxdatacodec.BoolCodec;\nimport com.grammatech.gtirb.auxdatacodec.ByteCodec;\nimport com.grammatech.gtirb.auxdatacodec.Codec;\nimport com.grammatech.gtirb.auxdatacodec.FloatCodec;\nimport com.grammatech.gtirb.auxdatacodec.IntegerCodec;\nimport com.grammatech.gtirb.auxdatacodec.ListCodec;\nimport com.grammatech.gtirb.auxdatacodec.LongCodec;\nimport com.grammatech.gtirb.auxdatacodec.MapCodec;\nimport com.grammatech.gtirb.auxdatacodec.OffsetCodec;\nimport com.grammatech.gtirb.auxdatacodec.SetCodec;\nimport com.grammatech.gtirb.auxdatacodec.ShortCodec;\nimport com.grammatech.gtirb.auxdatacodec.StringCodec;\nimport com.grammatech.gtirb.auxdatacodec.Tuple1Codec;\nimport com.grammatech.gtirb.auxdatacodec.Tuple2Codec;\nimport com.grammatech.gtirb.auxdatacodec.Tuple3Codec;\nimport com.grammatech.gtirb.auxdatacodec.Tuple4Codec;\nimport com.grammatech.gtirb.auxdatacodec.Tuple5Codec;\nimport com.grammatech.gtirb.auxdatacodec.UuidCodec;\nimport com.grammatech.gtirb.auxdatacodec.Variant11Codec;\nimport com.grammatech.gtirb.auxdatacodec.Variant2Codec;\nimport com.grammatech.gtirb.auxdatacodec.Variant3Codec;\nimport com.grammatech.gtirb.tuple.Tuple1;\nimport com.grammatech.gtirb.tuple.Tuple2;\nimport com.grammatech.gtirb.tuple.Tuple3;\nimport com.grammatech.gtirb.tuple.Tuple4;\nimport com.grammatech.gtirb.tuple.Tuple5;\nimport com.grammatech.gtirb.variant.Token;\nimport com.grammatech.gtirb.variant.Variant11;\nimport com.grammatech.gtirb.variant.Variant2;\nimport com.grammatech.gtirb.variant.Variant3;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.UUID;\nimport java.util.stream.Stream;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nclass FooSingle extends Tuple1<String> {\n    public FooSingle(String s) { super(s); }\n}\n\nclass FooPair extends Tuple2<String, Long> {\n    public FooPair(String s, Long l) { super(s, l); }\n}\n\nclass FooTriple extends Tuple3<String, Long, Float> {\n    public FooTriple(String s, Long l, Float f) { super(s, l, f); }\n}\n\nclass FooQuadruple extends Tuple4<String, Long, Float, Boolean> {\n    public FooQuadruple(String s, Long l, Float f, Boolean b) {\n        super(s, l, f, b);\n    }\n}\n\nclass FooQuintuple extends Tuple5<String, Long, Float, Boolean, Integer> {\n    public FooQuintuple(String s, Long l, Float f, Boolean b, Integer i) {\n        super(s, l, f, b, i);\n    }\n}\n\nclass FooVariant2 extends Variant2<Long, Float> {\n    private FooVariant2(Token.T0 tok, Long l) { super(tok, l); }\n    private FooVariant2(Token.T1 tok, Float f) { super(tok, f); }\n    public static FooVariant2 ofLong(Long l) {\n        return new FooVariant2(new Token.T0(), l);\n    }\n    public static FooVariant2 ofFloat(Float f) {\n        return new FooVariant2(new Token.T1(), f);\n    }\n}\n\nclass FooVariant3 extends Variant3<Long, Float, Boolean> {\n    private FooVariant3(Token.T0 tok, Long l) { super(tok, l); }\n    private FooVariant3(Token.T1 tok, Float f) { super(tok, f); }\n    private FooVariant3(Token.T2 tok, Boolean b) { super(tok, b); }\n    public static FooVariant3 ofLong(Long l) {\n        return new FooVariant3(new Token.T0(), l);\n    }\n    public static FooVariant3 ofFloat(Float f) {\n        return new FooVariant3(new Token.T1(), f);\n    }\n    public static FooVariant3 ofBoolean(Boolean b) {\n        return new FooVariant3(new Token.T2(), b);\n    }\n}\n\nclass FooVariant11\n    extends Variant11<Long, Float, Boolean, Integer, String, Long, Float,\n                      Boolean, Integer, String, Offset> {\n    private FooVariant11(Token.T0 tok, Long l) { super(tok, l); }\n    private FooVariant11(Token.T1 tok, Float f) { super(tok, f); }\n    private FooVariant11(Token.T2 tok, Boolean b) { super(tok, b); }\n    private FooVariant11(Token.T3 tok, Integer i) { super(tok, i); }\n    private FooVariant11(Token.T4 tok, String s) { super(tok, s); }\n    private FooVariant11(Token.T5 tok, Long l) { super(tok, l); }\n    private FooVariant11(Token.T6 tok, Float f) { super(tok, f); }\n    private FooVariant11(Token.T7 tok, Boolean b) { super(tok, b); }\n    private FooVariant11(Token.T8 tok, Integer i) { super(tok, i); }\n    private FooVariant11(Token.T9 tok, String s) { super(tok, s); }\n    private FooVariant11(Token.T10 tok, Offset o) { super(tok, o); }\n    public static FooVariant11 ofLong1(Long l) {\n        return new FooVariant11(new Token.T0(), l);\n    }\n    public static FooVariant11 ofFloat1(Float f) {\n        return new FooVariant11(new Token.T1(), f);\n    }\n    public static FooVariant11 ofBoolean1(Boolean b) {\n        return new FooVariant11(new Token.T2(), b);\n    }\n    public static FooVariant11 ofInteger1(Integer i) {\n        return new FooVariant11(new Token.T3(), i);\n    }\n    public static FooVariant11 ofString1(String s) {\n        return new FooVariant11(new Token.T4(), s);\n    }\n    public static FooVariant11 ofLong2(Long l) {\n        return new FooVariant11(new Token.T5(), l);\n    }\n    public static FooVariant11 ofFloat2(Float f) {\n        return new FooVariant11(new Token.T6(), f);\n    }\n    public static FooVariant11 ofBoolean2(Boolean b) {\n        return new FooVariant11(new Token.T7(), b);\n    }\n    public static FooVariant11 ofInteger2(Integer i) {\n        return new FooVariant11(new Token.T8(), i);\n    }\n    public static FooVariant11 ofString2(String s) {\n        return new FooVariant11(new Token.T9(), s);\n    }\n    public static FooVariant11 ofOffset(Offset o) {\n        return new FooVariant11(new Token.T10(), o);\n    }\n}\n\npublic class TestAuxData {\n\n    private static Stream<Arguments> argProviderForTestCodec() {\n\n        List<Integer> ali = new ArrayList<>();\n        ali.add(4);\n        ali.add(2);\n\n        List<Float> alf = new ArrayList<>();\n        alf.add(5.3f);\n        Map<UUID, List<Float>> hm = new HashMap<>();\n        hm.put(new UUID(2, 4), alf);\n\n        Set<String> hs = new HashSet<>();\n        hs.add(\"foo\");\n        hs.add(\"bar\");\n\n        Variant11Codec<FooVariant11, Long, Float, Boolean, Integer, String,\n                       Long, Float, Boolean, Integer, String, Offset>\n            fooV11Codec = new Variant11Codec<>(\n                LongCodec.INT64, new FloatCodec(), new BoolCodec(),\n                IntegerCodec.INT32, new StringCodec(), LongCodec.INT64,\n                new FloatCodec(), new BoolCodec(), IntegerCodec.INT32,\n                new StringCodec(), new OffsetCodec(), FooVariant11::ofLong1,\n                FooVariant11::ofFloat1, FooVariant11::ofBoolean1,\n                FooVariant11::ofInteger1, FooVariant11::ofString1,\n                FooVariant11::ofLong2, FooVariant11::ofFloat2,\n                FooVariant11::ofBoolean2, FooVariant11::ofInteger2,\n                FooVariant11::ofString2, FooVariant11::ofOffset);\n\n        String expFooV11Name =\n            \"variant<int64_t,float,bool,int32_t,string,int64_t,float,bool,int32_t,string,Offset>\";\n\n        return Stream.of(\n            Arguments.of(\"bool\", new BoolCodec(), false),\n            Arguments.of(\"bool\", new BoolCodec(), true),\n            Arguments.of(\"int8_t\", ByteCodec.INT8, (byte)0),\n            Arguments.of(\"int8_t\", ByteCodec.INT8, (byte)42),\n            Arguments.of(\"uint8_t\", ByteCodec.UINT8, (byte)43),\n            Arguments.of(\"float\", new FloatCodec(), 0.0f),\n            Arguments.of(\"float\", new FloatCodec(), 42.5f),\n            Arguments.of(\"int16_t\", ShortCodec.INT16, (short)0),\n            Arguments.of(\"int16_t\", ShortCodec.INT16, (short)42),\n            Arguments.of(\"uint16_t\", ShortCodec.UINT16, (short)43),\n            Arguments.of(\"int32_t\", IntegerCodec.INT32, 0),\n            Arguments.of(\"int32_t\", IntegerCodec.INT32, 42),\n            Arguments.of(\"uint32_t\", IntegerCodec.UINT32, 43),\n            Arguments.of(\"int64_t\", LongCodec.INT64, 0L),\n            Arguments.of(\"int64_t\", LongCodec.INT64, 42000000000L),\n            Arguments.of(\"uint64_t\", LongCodec.UINT64, 43000000000L),\n            Arguments.of(\"string\", new StringCodec(), \"\"),\n            Arguments.of(\"string\", new StringCodec(), \"abcdefg\"),\n            Arguments.of(\"UUID\", new UuidCodec(), new UUID(0, 0)),\n            Arguments.of(\"UUID\", new UuidCodec(),\n                         new UUID(0xFEEDFACECAFEBEEFL, 0xDEADFA11DEADD00DL)),\n            Arguments.of(\"Offset\", new OffsetCodec(),\n                         new Offset(new UUID(4, 2), 1234)),\n            Arguments.of(\"sequence<int32_t>\",\n                         new ListCodec<>(IntegerCodec.INT32, ArrayList::new),\n                         ali),\n            Arguments.of(\"mapping<UUID,sequence<float>>\",\n                         new MapCodec<>(\n                             new UuidCodec(),\n                             new ListCodec<>(new FloatCodec(), ArrayList::new),\n                             HashMap::new),\n                         hm),\n            Arguments.of(\"set<string>\",\n                         new SetCodec<>(new StringCodec(), HashSet::new), hs),\n            Arguments.of(\"tuple<string>\",\n                         new Tuple1Codec<>(new StringCodec(), FooSingle::new),\n                         new FooSingle(\"hello\")),\n            Arguments.of(\"tuple<string,int64_t>\",\n                         new Tuple2Codec<>(new StringCodec(), LongCodec.INT64,\n                                           FooPair::new),\n                         new FooPair(\"hello\", 27L)),\n            Arguments.of(\"tuple<string,int64_t,float>\",\n                         new Tuple3Codec<>(new StringCodec(), LongCodec.INT64,\n                                           new FloatCodec(), FooTriple::new),\n                         new FooTriple(\"hello\", 27L, 3.14f)),\n            Arguments.of(\"tuple<string,int64_t,float,bool>\",\n                         new Tuple4Codec<>(new StringCodec(), LongCodec.INT64,\n                                           new FloatCodec(), new BoolCodec(),\n                                           FooQuadruple::new),\n                         new FooQuadruple(\"hello\", 27L, 3.14f, true)),\n            Arguments.of(\"tuple<string,int64_t,float,bool,int32_t>\",\n                         new Tuple5Codec<>(new StringCodec(), LongCodec.INT64,\n                                           new FloatCodec(), new BoolCodec(),\n                                           IntegerCodec.INT32,\n                                           FooQuintuple::new),\n                         new FooQuintuple(\"hello\", 27L, 3.14f, true, 42)),\n            Arguments.of(\"variant<int64_t,float>\",\n                         new Variant2Codec<>(LongCodec.INT64, new FloatCodec(),\n                                             FooVariant2::ofLong,\n                                             FooVariant2::ofFloat),\n                         FooVariant2.ofLong(42L)),\n            Arguments.of(\"variant<int64_t,float>\",\n                         new Variant2Codec<>(LongCodec.INT64, new FloatCodec(),\n                                             FooVariant2::ofLong,\n                                             FooVariant2::ofFloat),\n                         FooVariant2.ofFloat(3.14f)),\n            Arguments.of(\"variant<int64_t,float,bool>\",\n                         new Variant3Codec<>(\n                             LongCodec.INT64, new FloatCodec(), new BoolCodec(),\n                             FooVariant3::ofLong, FooVariant3::ofFloat,\n                             FooVariant3::ofBoolean),\n                         FooVariant3.ofBoolean(true)),\n            Arguments.of(expFooV11Name, fooV11Codec, FooVariant11.ofLong1(42L)),\n            Arguments.of(expFooV11Name, fooV11Codec,\n                         FooVariant11.ofFloat1(3.14f)),\n            Arguments.of(expFooV11Name, fooV11Codec,\n                         FooVariant11.ofBoolean1(true)),\n            Arguments.of(expFooV11Name, fooV11Codec,\n                         FooVariant11.ofInteger1(43)),\n            Arguments.of(expFooV11Name, fooV11Codec,\n                         FooVariant11.ofString1(\"abc\")),\n            Arguments.of(expFooV11Name, fooV11Codec, FooVariant11.ofLong2(44L)),\n            Arguments.of(expFooV11Name, fooV11Codec,\n                         FooVariant11.ofFloat2(3.145f)),\n            Arguments.of(expFooV11Name, fooV11Codec,\n                         FooVariant11.ofBoolean2(false)),\n            Arguments.of(expFooV11Name, fooV11Codec,\n                         FooVariant11.ofInteger2(45)),\n            Arguments.of(expFooV11Name, fooV11Codec,\n                         FooVariant11.ofString2(\"def\")),\n            Arguments.of(\n                expFooV11Name, fooV11Codec,\n                FooVariant11.ofOffset(new Offset(new UUID(9, 10), 11))));\n    }\n\n    @ParameterizedTest(name = \"Test codec for protobuf type: {0}\")\n    @MethodSource(\"argProviderForTestCodec\")\n    public <T> void testCodec(String typeName, Codec<T> codec, T val)\n        throws IOException {\n        assertEquals(codec.getTypeName(), typeName);\n        ByteArrayOutputStream os = new ByteArrayOutputStream();\n        codec.encode(os, val);\n        ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());\n        T result = codec.decode(is);\n        assertEquals(val, result);\n    }\n\n    @Test\n    public void testAuxDataDecodeEncode() throws IOException {\n        // Construct an IR+Module to dangle AuxData off of\n        IR ir1 = new IR();\n        Module m1 = new Module(\n            \"test\", 0xDEADBEEF, 0, Module.FileFormat.ELF, Module.ISA.IA32,\n            \"test\", new ArrayList<Section>(), new ArrayList<Symbol>(),\n            new ArrayList<ProxyBlock>(), null);\n        ir1.addModule(m1);\n\n        // Add the AuxData\n        assertEquals(Optional.empty(),\n                     m1.getAuxData(AuxDataSchemas.functionNames));\n        Map<UUID, UUID> func_names = new TreeMap<>();\n        func_names.put(new UUID(1, 2), new UUID(3, 4));\n        m1.putAuxData(AuxDataSchemas.functionNames, func_names);\n        Optional<Map<UUID, UUID>> oad1 =\n            m1.getAuxData(AuxDataSchemas.functionNames);\n        assertTrue(oad1.isPresent());\n        assertEquals(func_names, oad1.get());\n\n        // Serialize/unserialize\n        ByteArrayOutputStream os = new ByteArrayOutputStream();\n        ir1.saveFile(os);\n\n        ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());\n        IR ir2 = IR.loadFile(is);\n        assertNotNull(ir2);\n        List<Module> mods2 = ir2.getModules();\n        assertNotNull(mods2);\n        Module m2 = mods2.get(0);\n\n        // Fetch the AuxData back.\n        Optional<Map<UUID, UUID>> oad2 =\n            m2.getAuxData(AuxDataSchemas.functionNames);\n        assertTrue(oad2.isPresent());\n        assertEquals(func_names, oad2.get());\n    }\n\n    AuxDataSchema<Long> aSchema =\n        new AuxDataSchema<>(\"aSchema\", LongCodec.UINT64);\n    AuxDataSchema<Boolean> anotherSchema =\n        new AuxDataSchema<>(\"anotherSchema\", new BoolCodec());\n\n    @Test\n    public void testRemoveAuxData() throws IOException {\n        Module m = new Module(\"test\", 0xDEADBEEF, 0, Module.FileFormat.ELF,\n                              Module.ISA.IA32, \"test\", new ArrayList<Section>(),\n                              new ArrayList<Symbol>(),\n                              new ArrayList<ProxyBlock>(), null);\n\n        m.putAuxData(aSchema, 42L);\n        assertEquals(Optional.of(42L), m.getAuxData(aSchema));\n\n        boolean rv = m.removeAuxData(\"aSchema\");\n        assertTrue(rv);\n        assertEquals(Optional.empty(), m.getAuxData(aSchema));\n        rv = m.removeAuxData(\"aSchema\");\n        assertFalse(rv);\n\n        m.putAuxData(aSchema, 43L);\n        assertEquals(Optional.of(43L), m.getAuxData(aSchema));\n\n        rv = m.removeAuxData(aSchema);\n        assertTrue(rv);\n        assertEquals(Optional.empty(), m.getAuxData(aSchema));\n        rv = m.removeAuxData(aSchema);\n        assertFalse(rv);\n    }\n\n    @Test\n    public void testClearAuxData() throws IOException {\n        Module m = new Module(\"test\", 0xDEADBEEF, 0, Module.FileFormat.ELF,\n                              Module.ISA.IA32, \"test\", new ArrayList<Section>(),\n                              new ArrayList<Symbol>(),\n                              new ArrayList<ProxyBlock>(), null);\n\n        m.putAuxData(aSchema, 42L);\n        m.putAuxData(anotherSchema, true);\n        assertEquals(Optional.of(42L), m.getAuxData(aSchema));\n        assertEquals(Optional.of(true), m.getAuxData(anotherSchema));\n\n        m.clearAuxData();\n        assertEquals(Optional.empty(), m.getAuxData(aSchema));\n        assertEquals(Optional.empty(), m.getAuxData(anotherSchema));\n    }\n\n    @Test\n    public void testGetAuxDataMap() throws IOException {\n        Module m = new Module(\"test\", 0xDEADBEEF, 0, Module.FileFormat.ELF,\n                              Module.ISA.IA32, \"test\", new ArrayList<Section>(),\n                              new ArrayList<Symbol>(),\n                              new ArrayList<ProxyBlock>(), null);\n\n        m.putAuxData(aSchema, 42L);\n        m.putAuxData(anotherSchema, true);\n        assertEquals(Optional.of(42L), m.getAuxData(aSchema));\n        assertEquals(Optional.of(true), m.getAuxData(anotherSchema));\n\n        Map<String, AuxDataContainer.AuxData> adMap = m.getAuxDataMap();\n        assertTrue(adMap.containsKey(aSchema.getName()));\n        assertTrue(adMap.containsKey(anotherSchema.getName()));\n        assertThrows(UnsupportedOperationException.class, () -> adMap.clear());\n    }\n}\n"
  },
  {
    "path": "java/tests/TestByteIntervals.java",
    "content": "package tests;\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport com.grammatech.gtirb.*;\nimport com.grammatech.gtirb.Module;\nimport com.grammatech.gtirb.Module.FileFormat;\nimport com.grammatech.gtirb.Module.ISA;\nimport java.io.File;\nimport java.util.*;\nimport org.junit.jupiter.api.Test;\n\npublic class TestByteIntervals {\n\n    @Test\n    void testByteIntervalSaveAndLoad() throws Exception {\n        IR ir = new IR();\n        Module module = new Module(\"c:/foo.exe\", 0xCAFE, 0xBEEF, FileFormat.ELF,\n                                   ISA.X64, \"myModule\");\n        Section section =\n            new Section(\"mySection\", new HashSet<Section.SectionFlag>(),\n                        new ArrayList<ByteInterval>());\n        ByteInterval byteInterval =\n            new ByteInterval(\"SaveAndLoad\".getBytes(), 0xFEED);\n        section.addByteInterval(byteInterval);\n        ir.addModule(module);\n        module.addSection(section);\n\n        // Reset address\n        byteInterval.clearAddress();\n\n        File file = File.createTempFile(\"temp\", null);\n        String filename = file.getName();\n        try {\n            ir.saveFile(filename);\n        } catch (Exception e) {\n            file.delete();\n            throw e;\n        }\n\n        IR ir_reloaded;\n        try {\n            ir_reloaded = IR.loadFile(filename);\n        } catch (Exception e) {\n            file.delete();\n            throw e;\n        }\n        file.delete();\n\n        ByteInterval biReloaded = ir_reloaded.getModules()\n                                      .get(0)\n                                      .getSections()\n                                      .get(0)\n                                      .getByteIntervals()\n                                      .get(0);\n        // Verify address was reset\n        assertFalse(biReloaded.hasAddress());\n        // Test set and get of address\n        biReloaded.setAddress(0xDEADBEEF);\n        assertEquals(biReloaded.getAddress(), OptionalLong.of(0xDEADBEEF));\n        // Verify byte array content\n        assertTrue(\n            Arrays.equals(biReloaded.getBytes(), \"SaveAndLoad\".getBytes()));\n    }\n\n    @Test\n    void testByteIntervalTruncation() throws Exception {\n        int bytesSize = 1000;\n        int intervalSize = 2000;\n        int truncatedSize = 500;\n\n        byte[] bytes = new byte[bytesSize];\n        ByteInterval bi = new ByteInterval(intervalSize);\n\n        bi.setBytes(bytes);\n        assertEquals(bi.getSize(), intervalSize);\n        assertEquals(bi.getInitializedSize(), bytesSize);\n\n        bi.setSize(truncatedSize);\n        assertEquals(bi.getSize(), truncatedSize);\n        assertEquals(bi.getInitializedSize(), truncatedSize);\n        assertEquals(bi.getBytes().length, truncatedSize);\n    }\n\n    // Run through all blocks with a ByteBlock iterator\n    @Test\n    public void testIterators() {\n        ByteInterval bi = new ByteInterval();\n\n        CodeBlock b1 = new CodeBlock(4, 1, CodeBlock.DecodeMode.Default);\n        CodeBlock b2 = new CodeBlock(3, 3, CodeBlock.DecodeMode.Default);\n        CodeBlock b3 = new CodeBlock(5, 5, CodeBlock.DecodeMode.Thumb);\n        DataBlock b4 = new DataBlock(3, 2);\n        DataBlock b5 = new DataBlock(3, 6);\n\n        bi.insertByteBlock(b1);\n        bi.insertByteBlock(b2);\n        bi.insertByteBlock(b3);\n        bi.insertByteBlock(b4);\n        bi.insertByteBlock(b5);\n\n        List<ByteBlock> blockList = bi.getBlockList();\n        assertEquals(5, blockList.size());\n\n        Iterator<ByteBlock> blocks = bi.byteBlockIterator();\n        // Dump of block types\n        int codeblocks = 0;\n        int datablocks = 0;\n\n        while (blocks.hasNext()) {\n            ByteBlock block = blocks.next();\n            // String blockType;\n            if (block instanceof CodeBlock)\n                codeblocks += 1;\n            //\tblockType = \"CODE\";\n            else\n                datablocks += 1;\n            //\tblockType = \"DATA\";\n        }\n\n        assertEquals(3, codeblocks);\n        assertEquals(2, datablocks);\n    }\n\n    // Try a few ByteBlock retrieval methods\n    @Test\n    public void testBlockRetrieval() {\n        ByteInterval bi = new ByteInterval();\n        bi.setAddress(0x200D90);\n        bi.setSize(14);\n\n        CodeBlock c1 = new CodeBlock(2, 1, CodeBlock.DecodeMode.Default);\n        CodeBlock c2 = new CodeBlock(2, 2, CodeBlock.DecodeMode.Default);\n        CodeBlock c3 = new CodeBlock(6, 3, CodeBlock.DecodeMode.Thumb);\n        CodeBlock c4 = new CodeBlock(1, 4, CodeBlock.DecodeMode.Default);\n        CodeBlock c5 = new CodeBlock(3, 5, CodeBlock.DecodeMode.Default);\n\n        DataBlock d1 = new DataBlock(5, 0);\n        DataBlock d2 = new DataBlock(4, 3);\n        DataBlock d3 = new DataBlock(10, 4);\n        DataBlock d4 = new DataBlock(1, 6);\n        DataBlock d5 = new DataBlock(1, 7);\n\n        bi.insertByteBlock(c1);\n        bi.insertByteBlock(c2);\n        bi.insertByteBlock(c3);\n        bi.insertByteBlock(c4);\n        bi.insertByteBlock(c5);\n\n        bi.insertByteBlock(d1);\n        bi.insertByteBlock(d2);\n        bi.insertByteBlock(d3);\n        bi.insertByteBlock(d4);\n        bi.insertByteBlock(d5);\n\n        List<com.grammatech.gtirb.DataBlock> intersecting =\n            bi.findDataBlocksOn(0x200D96);\n        assertNotNull(intersecting);\n        assertEquals(3, intersecting.size());\n        boolean saw_d2 = false;\n        boolean saw_d3 = false;\n        boolean saw_d4 = false;\n        for (DataBlock dataBlock : intersecting) {\n            if (dataBlock == d2) {\n                saw_d2 = true;\n            }\n            if (dataBlock == d3) {\n                saw_d3 = true;\n            }\n            if (dataBlock == d4) {\n                saw_d4 = true;\n            }\n        }\n        assertTrue(saw_d2);\n        assertTrue(saw_d3);\n        assertTrue(saw_d4);\n\n        List<com.grammatech.gtirb.CodeBlock> startingAt =\n            bi.findCodeBlocksAt(0x200D93, 0x200D95);\n        assertNotNull(startingAt);\n        assertEquals(2, startingAt.size());\n        boolean saw_c3 = false;\n        boolean saw_c4 = false;\n        for (CodeBlock codeBlock : startingAt) {\n            if (codeBlock == c3) {\n                saw_c3 = true;\n            }\n            if (codeBlock == c4) {\n                saw_c4 = true;\n            }\n        }\n        assertTrue(saw_c3);\n        assertTrue(saw_c4);\n    }\n}\n"
  },
  {
    "path": "java/tests/TestIrSanity.java",
    "content": "package tests;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport com.grammatech.gtirb.*;\nimport com.grammatech.gtirb.Edge.EdgeType;\nimport com.grammatech.gtirb.Module;\nimport com.grammatech.gtirb.Module.FileFormat;\nimport com.grammatech.gtirb.Module.ISA;\nimport java.io.*;\nimport java.nio.charset.Charset;\nimport java.util.*;\nimport org.junit.jupiter.api.Test;\n\npublic class TestIrSanity {\n\n    @Test\n    void testCreateSaveAndLoad() throws Exception {\n        // Just create a simple IR w/ 1 module\n        IR ir_orig = new IR();\n        Module mod =\n            new Module(\"c:/foo.exe\", 0xCAFE, 0xBEEF, Module.FileFormat.PE,\n                       Module.ISA.X64, \"foo.exe\");\n        ir_orig.addModule(mod);\n        mod.setByteOrder(Module.ByteOrder.LittleEndian);\n        ir_orig.setCfg(new CFG(new ArrayList<Edge>(), new ArrayList<byte[]>()));\n\n        File file;\n        file = File.createTempFile(\"temp\", null);\n\n        String filename = file.getName();\n        try {\n            ir_orig.saveFile(filename);\n        } catch (Exception e) {\n            file.delete();\n            throw e;\n        }\n\n        IR ir_reloaded;\n        try {\n            ir_reloaded = IR.loadFile(filename);\n        } catch (Exception e) {\n            file.delete();\n            throw e;\n        }\n\n        file.delete();\n\n        assertNotNull(ir_reloaded);\n        Module mod_reloaded = ir_reloaded.getModules().get(0);\n        assertEquals(\"foo.exe\", mod_reloaded.getName());\n        assertEquals(ir_reloaded.getVersion(), Version.gtirbProtobufVersion);\n    }\n\n    @Test\n    void testIrSetAndGet() throws Exception {\n        IR ir = new IR();\n\n        // test addModules (list)\n        List<Module> modules = new ArrayList<Module>();\n        modules.add(new Module(\n            \"/opt/testModules/testModules-1.0.0/testModule0/bin/mod\",\n            0x8FFFFFFF00000201L, 0x0L, FileFormat.ELF, ISA.X64, \"mod0\"));\n        modules.add(new Module(\n            \"/opt/testModules/testModules-1.0.0/testModule1/bin/mod\",\n            0x8FFFFFFF00000401L, 0x0L, FileFormat.ELF, ISA.X64, \"mod1\"));\n        ir.addModules(modules);\n        assertTrue(ir.getModules().equals(modules));\n\n        // test get/set version\n        ir.setVersion(1234);\n        assertEquals(ir.getVersion(), 1234);\n\n        // test set/get CFG\n        List<Edge> edges = new ArrayList<Edge>();\n        edges.add(new Edge(UUID.randomUUID(), UUID.randomUUID(),\n                           EdgeType.Branch, false, false));\n        edges.add(new Edge(UUID.randomUUID(), UUID.randomUUID(), EdgeType.Call,\n                           true, false));\n        List<byte[]> vertices = new ArrayList<byte[]>();\n        vertices.add(\"OneSingleVertice\".getBytes());\n        CFG cfg = new CFG(edges, vertices);\n        ir.setCfg(cfg);\n        assertEquals(ir.getCfg(), cfg);\n    }\n\n    // TODO: The next few tests here each test different ways the loadFile()\n    // function can fail. Unfortunately, in its current form, it only ever\n    // returns null in each case, so we can't really tell that we're getting\n    // the failure we expect. This should be improved if we ever make the\n    // error reporting richer in the Java API.\n\n    @Test\n    void testNonGtirbContents() throws Exception {\n        // A file with non-GTIRB contents.\n        byte contents[] = \"JUNK\".getBytes(Charset.forName(\"ASCII\"));\n        ByteArrayInputStream file_proxy = new ByteArrayInputStream(contents);\n        IR ir;\n        ir = IR.loadFile(file_proxy);\n\n        // IR should be null here\n        assertNull(ir);\n    }\n\n    @Test\n    void testWrongVersion() throws Exception {\n        // A GTIRB file w/ the wrong version.\n        ByteArrayOutputStream content_builder = new ByteArrayOutputStream();\n        content_builder.write(\"GTIRB\".getBytes(Charset.forName(\"ASCII\")));\n        content_builder.write(0);\n        content_builder.write(0);\n        content_builder.write(255);\n\n        byte contents[] = content_builder.toByteArray();\n        ByteArrayInputStream file_proxy = new ByteArrayInputStream(contents);\n        IR ir;\n        ir = IR.loadFile(file_proxy);\n\n        // IR should be null here\n        assertNull(ir);\n    }\n\n    @Test\n    void testCorruptedProtobuf() throws Exception {\n        // A GTIRB file w/ the right version but bad protobuf.\n        ByteArrayOutputStream content_builder = new ByteArrayOutputStream();\n        content_builder.write(\"GTIRB\".getBytes(Charset.forName(\"ASCII\")));\n        content_builder.write(0);\n        content_builder.write(0);\n        content_builder.write(Version.gtirbProtobufVersion);\n        content_builder.write(255);\n\n        byte contents[] = content_builder.toByteArray();\n        ByteArrayInputStream file_proxy = new ByteArrayInputStream(contents);\n        IR ir;\n        ir = IR.loadFile(file_proxy);\n\n        // IR should be null here\n        assertNull(ir);\n    }\n\n    @Test\n    void testAddAndRemoveModules() throws Exception {\n        IR ir = new IR();\n        Module mod0 = new Module(\"/usr/bin/mod0\", 0x0000, 0x0FFF,\n                                 FileFormat.ELF, ISA.X64, \"mod0\");\n        ir.addModule(mod0);\n        Module mod1 = new Module(\"/usr/bin/mod1\", 0x1000, 0x1FFF,\n                                 FileFormat.ELF, ISA.X64, \"mod1\");\n        ir.addModule(mod1);\n        Module mod2 = new Module(\"/usr/bin/mod2\", 0x2000, 0x2FFF,\n                                 FileFormat.ELF, ISA.X64, \"mod2\");\n        ir.addModule(mod2);\n        List<Module> modules = ir.getModules();\n        assertEquals(modules.size(), 3);\n\n        ir.removeModule(mod0);\n        ir.removeModule(mod2);\n\n        // Now the only module left should be \"mod1\"\n        assertEquals(\"mod1\", ir.getModules().get(0).getName());\n        assertEquals(mod1.getIr().get(), ir);\n        assertTrue(mod0.getIr().isEmpty());\n        assertTrue(mod2.getIr().isEmpty());\n    }\n\n    @Test\n    void testIrFindModules() throws Exception {\n        IR ir = new IR();\n\n        // test addModules (list)\n        List<Module> modules = new ArrayList<Module>();\n        modules.add(new Module(\n            \"/opt/testModules/testModules-1.0.0/testModule0/bin/mod\",\n            0x8FFFFFFF00000201L, 0x0L, FileFormat.ELF, ISA.X64, \"mod0\"));\n        modules.add(new Module(\n            \"/opt/testModules/testModules-1.0.0/testModule1/bin/mod\",\n            0x8FFFFFFF00000401L, 0x0L, FileFormat.ELF, ISA.X64, \"mod1\"));\n        modules.add(new Module(\n            \"/opt/testModules/testModules-1.0.0/testModule1/bin/mod-dup\",\n            0x8FFFFFFF00000401L, 0x0L, FileFormat.ELF, ISA.X64, \"mod1\"));\n        ir.addModules(modules);\n        assertTrue(ir.getModules().equals(modules));\n\n        List<Module> mod0_modules = ir.findModules(\"mod0\");\n        assertEquals(1, mod0_modules.size());\n        for (Module module : mod0_modules) {\n            assertEquals(\"mod0\", module.getName());\n        }\n\n        List<Module> mod1_modules = ir.findModules(\"mod1\");\n        assertEquals(2, mod1_modules.size());\n        for (Module module : mod1_modules) {\n            assertEquals(\"mod1\", module.getName());\n        }\n    }\n}\n"
  },
  {
    "path": "java/tests/TestModules.java",
    "content": "package tests;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport com.grammatech.gtirb.*;\nimport com.grammatech.gtirb.CodeBlock.DecodeMode;\nimport com.grammatech.gtirb.Module;\nimport com.grammatech.gtirb.Module.FileFormat;\nimport com.grammatech.gtirb.Module.ISA;\nimport com.grammatech.gtirb.Section.SectionFlag;\nimport java.io.File;\nimport java.util.*;\nimport org.junit.jupiter.api.Test;\n\npublic class TestModules {\n\n    @Test\n    void testModuleSaveAndLoad() throws Exception {\n        // Just create a simple IR w/ 1 module\n        IR ir_orig = new IR();\n        Module mod =\n            new Module(\"c:/foo.exe\", 0xCAFE, 0xBEEF, Module.FileFormat.ELF,\n                       Module.ISA.X64, \"myModule\");\n        mod.setByteOrder(Module.ByteOrder.LittleEndian);\n        ir_orig.addModule(mod);\n\n        Section section =\n            new Section(\"mySection\", new HashSet<Section.SectionFlag>(),\n                        new ArrayList<ByteInterval>());\n        mod.addSection(section);\n\n        Symbol symbol = new Symbol(\"mySymbol\");\n        mod.addSymbol(symbol);\n\n        ProxyBlock proxyBlock = new ProxyBlock();\n        mod.addProxyBlock(proxyBlock);\n\n        File file;\n        file = File.createTempFile(\"temp\", null);\n\n        String filename = file.getName();\n        try {\n            ir_orig.saveFile(filename);\n        } catch (Exception e) {\n            file.delete();\n            throw e;\n        }\n\n        IR ir_reloaded;\n        try {\n            ir_reloaded = IR.loadFile(filename);\n        } catch (Exception e) {\n            file.delete();\n            throw e;\n        }\n\n        file.delete();\n\n        assertNotNull(ir_reloaded);\n        Module mod_reloaded = ir_reloaded.getModules().get(0);\n        assertEquals(\"myModule\", mod_reloaded.getName());\n        assertEquals(Module.FileFormat.ELF, mod_reloaded.getFileFormat());\n        assertEquals(Module.ISA.X64, mod_reloaded.getIsa());\n        assertEquals(Module.ByteOrder.LittleEndian,\n                     mod_reloaded.getByteOrder());\n        assertEquals(0xCAFE, mod_reloaded.getPreferredAddr());\n        assertEquals(0xBEEF, mod_reloaded.getRebaseDelta());\n        assertEquals(\"mySymbol\", mod_reloaded.getSymbols().get(0).getName());\n        assertEquals(\"mySection\", mod_reloaded.getSections().get(0).getName());\n        assertEquals(1, mod_reloaded.getProxyBlocks().size());\n    }\n\n    @Test\n    void testModuleSetAndGet() throws Exception {\n\n        CodeBlock entryPoint =\n            new CodeBlock(0, 0, CodeBlock.DecodeMode.Default);\n        String binaryPath = \"/home/away/from/home.bin\";\n        String name = \"myModule\";\n        long preferredAddr = 0xABCD;\n        long rebaseDelta = 0x1234;\n        FileFormat fileFormat = FileFormat.PE;\n        ISA isa = ISA.IA32;\n\n        Module module =\n            new Module(\"/my/module\", 0x0000, 0x0FFF, FileFormat.ELF, ISA.X64,\n                       \"module\", new ArrayList<Section>(),\n                       new ArrayList<Symbol>(), new ArrayList<ProxyBlock>(),\n                       new CodeBlock(0, 0, DecodeMode.Default));\n        assertNotNull(module);\n\n        module.setBinaryPath(binaryPath);\n        assertEquals(module.getBinaryPath(), binaryPath);\n\n        module.setPreferredAddr(preferredAddr);\n        assertEquals(module.getPreferredAddr(), preferredAddr);\n\n        module.setRebaseDelta(rebaseDelta);\n        assertEquals(module.getRebaseDelta(), rebaseDelta);\n\n        module.setFileFormat(fileFormat);\n        assertEquals(module.getFileFormat(), fileFormat);\n\n        module.setIsa(isa);\n        assertEquals(module.getIsa(), isa);\n\n        module.setName(name);\n        assertEquals(module.getName(), name);\n\n        module.setEntryPoint(entryPoint);\n        assertEquals(module.getEntryPoint(), entryPoint);\n    }\n\n    @Test\n    void testAddAndRemoveSections() throws Exception {\n        Module module =\n            new Module(\"/my/module\", 0x0000, 0x0FFF, Module.FileFormat.ELF,\n                       Module.ISA.X64, \"module\");\n        Section section0 =\n            new Section(\"section0\", new HashSet<Section.SectionFlag>(),\n                        new ArrayList<ByteInterval>());\n        Section section1 =\n            new Section(\"section1\", new HashSet<Section.SectionFlag>(),\n                        new ArrayList<ByteInterval>());\n        Section section2 =\n            new Section(\"section2\", new HashSet<Section.SectionFlag>(),\n                        new ArrayList<ByteInterval>());\n\n        module.addSection(section0);\n        module.addSection(section1);\n        module.addSection(section2);\n\n        List<Section> sections = module.getSections();\n        assertEquals(sections.size(), 3);\n\n        assertEquals(section0.getModule(), Optional.of(module));\n        assertEquals(section1.getModule(), Optional.of(module));\n        assertEquals(section2.getModule(), Optional.of(module));\n        module.removeSection(section0);\n        module.removeSection(section1);\n        assertTrue(section0.getModule().isEmpty());\n        assertTrue(section1.getModule().isEmpty());\n        assertEquals(section2.getModule(), Optional.of(module));\n\n        // Now the only section left should be \"section2\"\n        sections = module.getSections();\n        assertEquals(sections.size(), 1);\n        assertEquals(\"section2\", sections.get(0).getName());\n    }\n\n    @Test\n    void testAddAndRemoveSymbols() throws Exception {\n        Module module =\n            new Module(\"/my/module\", 0x0000, 0x0FFF, Module.FileFormat.ELF,\n                       Module.ISA.X64, \"module\");\n        Symbol symbol0 = new Symbol(\"symbol0\");\n        Symbol symbol1 = new Symbol(\"symbol1\");\n        Symbol symbol2 = new Symbol(\"symbol2\");\n\n        module.addSymbol(symbol0);\n        module.addSymbol(symbol2);\n        module.addSymbol(symbol1);\n\n        List<Symbol> symbols = module.getSymbols();\n        assertEquals(symbols.size(), 3);\n\n        assertEquals(symbol0.getModule(), Optional.of(module));\n        assertEquals(symbol1.getModule(), Optional.of(module));\n        assertEquals(symbol2.getModule(), Optional.of(module));\n        module.removeSymbol(symbol2);\n        module.removeSymbol(symbol0);\n        assertTrue(symbol0.getModule().isEmpty());\n        assertEquals(symbol1.getModule(), Optional.of(module));\n        assertTrue(symbol2.getModule().isEmpty());\n\n        // Now the only symbol left should be \"symbol1\"\n        symbols = module.getSymbols();\n        assertEquals(symbols.size(), 1);\n        assertEquals(\"symbol1\", symbols.get(0).getName());\n    }\n\n    @Test\n    void testAddAndRemoveProxyBlocks() throws Exception {\n        Module module =\n            new Module(\"/my/module\", 0x0000, 0x0FFF, Module.FileFormat.ELF,\n                       Module.ISA.X64, \"module\");\n        ProxyBlock proxyBlock0 = new ProxyBlock();\n        ProxyBlock proxyBlock1 = new ProxyBlock();\n        ProxyBlock proxyBlock2 = new ProxyBlock();\n\n        module.addProxyBlock(proxyBlock2);\n        module.addProxyBlock(proxyBlock1);\n        module.addProxyBlock(proxyBlock0);\n\n        List<ProxyBlock> proxyBlocks = module.getProxyBlocks();\n        assertEquals(proxyBlocks.size(), 3);\n\n        assertEquals(proxyBlock0.getModule(), Optional.of(module));\n        assertEquals(proxyBlock1.getModule(), Optional.of(module));\n        assertEquals(proxyBlock2.getModule(), Optional.of(module));\n        module.removeProxyBlock(proxyBlock0);\n        module.removeProxyBlock(proxyBlock2);\n        module.removeProxyBlock(proxyBlock1);\n        assertTrue(proxyBlock0.getModule().isEmpty());\n        assertTrue(proxyBlock1.getModule().isEmpty());\n        assertTrue(proxyBlock2.getModule().isEmpty());\n\n        assertEquals(module.getProxyBlocks().size(), 0);\n    }\n\n    @Test\n    void testModuleFindSections() throws Exception {\n\n        Module module = new Module(\"module\", 0x0000, 0x0FFF, FileFormat.ELF,\n                                   ISA.X64, \"module\");\n        Set<SectionFlag> flags = new HashSet<SectionFlag>();\n        flags.add(SectionFlag.Readable);\n        flags.add(SectionFlag.Writable);\n\n        ArrayList<ByteInterval> biList1 = new ArrayList<ByteInterval>();\n        biList1.add(new ByteInterval(null, 0x0));\n        biList1.get(0).setSize(0x100000);\n        Section section1 = new Section(\"Section1\", flags, biList1);\n        module.addSection(section1);\n\n        ArrayList<ByteInterval> biList2 = new ArrayList<ByteInterval>();\n        biList2.add(new ByteInterval(null, 0x100000));\n        biList2.get(0).setSize(0x100000);\n        Section section2 = new Section(\"Section2\", flags, biList2);\n        module.addSection(section2);\n\n        ArrayList<ByteInterval> biList3 = new ArrayList<ByteInterval>();\n        biList3.add(new ByteInterval(null, 0x200000));\n        biList3.get(0).setSize(0x100000);\n        Section section3 = new Section(\"Section3\", flags, biList3);\n        module.addSection(section3);\n\n        // Find sections that contain an address - single\n        List<Section> sectionsOn1 = module.findSectionsOn(0x7FFF);\n        assertEquals(sectionsOn1.size(), 1);\n        assertEquals(sectionsOn1.get(0), section1);\n\n        // Find sections that contain an address - range\n        List<Section> sectionsOn2 = module.findSectionsOn(0x180000, 0x280000);\n        assertEquals(sectionsOn2.size(), 2);\n        assertEquals(sectionsOn2.get(0), section2);\n        assertEquals(sectionsOn2.get(1), section3);\n\n        // Find sections that start at an address - single\n        List<Section> sectionsAt1 = module.findSectionsAt(0x0);\n        assertEquals(sectionsAt1.size(), 1);\n        assertEquals(sectionsAt1.get(0), section1);\n\n        // Find sections that start at an address - range\n        List<Section> sectionsAt2 = module.findSectionsAt(0x180000, 0x280000);\n        assertEquals(sectionsAt2.size(), 1);\n        assertEquals(sectionsAt2.get(0), section3);\n    }\n}\n"
  },
  {
    "path": "java/tests/TestSections.java",
    "content": "package tests;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport com.grammatech.gtirb.*;\nimport com.grammatech.gtirb.Module;\nimport java.io.File;\nimport java.util.*;\nimport org.junit.jupiter.api.Test;\n\npublic class TestSections {\n\n    @Test\n    void testSectionSaveAndLoad() throws Exception {\n        // Just create a simple IR w/ 1 module\n        IR ir_orig = new IR();\n        Module mod =\n            new Module(\"c:/foo.exe\", 0xCAFE, 0xBEEF, Module.FileFormat.ELF,\n                       Module.ISA.X64, \"myModule\");\n        ir_orig.addModule(mod);\n\n        Section section =\n            new Section(\"mySection\", new HashSet<Section.SectionFlag>(),\n                        new ArrayList<ByteInterval>());\n        mod.addSection(section);\n\n        section.addSectionFlag(Section.SectionFlag.Readable);\n        section.addSectionFlag(Section.SectionFlag.Writable);\n        section.addSectionFlag(Section.SectionFlag.Executable);\n\n        ByteInterval bi = new ByteInterval();\n        section.addByteInterval(bi);\n\n        section.removeSectionFlag(Section.SectionFlag.Executable);\n\n        File file;\n        file = File.createTempFile(\"temp\", null);\n\n        String filename = file.getName();\n        try {\n            ir_orig.saveFile(filename);\n        } catch (Exception e) {\n            file.delete();\n            throw e;\n        }\n\n        IR ir_reloaded;\n        try {\n            ir_reloaded = IR.loadFile(filename);\n        } catch (Exception e) {\n            file.delete();\n            throw e;\n        }\n\n        file.delete();\n\n        assertNotNull(ir_reloaded);\n        Module mod_reloaded = ir_reloaded.getModules().get(0);\n        Section section_reloaded = mod_reloaded.getSections().get(0);\n        Set<Section.SectionFlag> flagSet = section_reloaded.getSectionFlags();\n\n        assertTrue(flagSet.contains(Section.SectionFlag.Readable));\n        assertTrue(flagSet.contains(Section.SectionFlag.Writable));\n        assertFalse(flagSet.contains(Section.SectionFlag.Executable));\n        assertEquals(section_reloaded.getByteIntervals().size(), 1);\n    }\n\n    @Test\n    void testSectionSetAndGet() throws Exception {\n        String name = \".code\";\n        long address = 0x8FFFFFFF;\n        long size = 0x40000;\n\n        Section section =\n            new Section(\"newSection\", new HashSet<Section.SectionFlag>(),\n                        new ArrayList<ByteInterval>());\n        section.setName(name);\n        assertEquals(section.getName(), name);\n\n        ByteInterval bi = new ByteInterval();\n        bi.setAddress(address);\n        bi.setSize(size);\n\n        CodeBlock b1 = new CodeBlock(4, 1, CodeBlock.DecodeMode.Default);\n        bi.insertByteBlock(b1);\n\n        section.addByteInterval(bi);\n\n        assertEquals(section.getAddress(), OptionalLong.of(address));\n        assertEquals(section.getSize(), size);\n    }\n\n    @Test\n    void testSectionWithIntervalAddresses() throws Exception {\n        ArrayList<ByteInterval> biList = new ArrayList<ByteInterval>();\n        ByteInterval bi1 = new ByteInterval(null, 0x0);\n        bi1.setSize(0x100000);\n        biList.add(bi1);\n        ByteInterval bi2 = new ByteInterval(null, 0x100000);\n        bi2.setSize(0x100000);\n        biList.add(bi2);\n        ByteInterval bi3 = new ByteInterval(null, 0x200000);\n        bi3.setSize(0x100000);\n        biList.add(bi3);\n        Section section =\n            new Section(\"Section\", new HashSet<Section.SectionFlag>(), biList);\n        assertEquals(section.getAddress(), OptionalLong.of(0x0));\n        assertEquals(section.getSize(), 0x300000L);\n\n        // Find intervals that contain an address - single\n        List<ByteInterval> biOn1 = section.findByteIntervalsOn(0x180000);\n        assertEquals(biOn1.size(), 1);\n        assertEquals(biOn1.get(0), bi2);\n\n        // Find intervals that contain an address - range\n        List<ByteInterval> biOn2 =\n            section.findByteIntervalsOn(0x80000, 0x180000);\n        assertEquals(biOn2.size(), 2);\n        assertEquals(biOn2.get(0), bi1);\n        assertEquals(biOn2.get(1), bi2);\n\n        // Find intervals that start at an address - single\n        List<ByteInterval> biAt1 = section.findByteIntervalsAt(0x100000);\n        assertEquals(biAt1.size(), 1);\n        assertEquals(biAt1.get(0), bi2);\n\n        // Find intervals that start at an address - range\n        List<ByteInterval> biAt2 =\n            section.findByteIntervalsAt(0x80000, 0x180000);\n        assertEquals(biAt2.size(), 1);\n        assertEquals(biAt2.get(0), bi2);\n    }\n\n    @Test\n    void testSectionNoAddressIntervals() throws Exception {\n        Section section =\n            new Section(\"aSection\", new HashSet<Section.SectionFlag>(),\n                        new ArrayList<ByteInterval>());\n\n        ByteInterval bi1 = new ByteInterval(null, 0x0);\n        bi1.setSize(0x100000);\n        section.addByteInterval(bi1);\n\n        // bi2 is a ByteInterval without an address, making the calculation of\n        // address and size for the section impossible\n        ByteInterval bi2 = new ByteInterval();\n        bi2.setSize(0x100000);\n        section.addByteInterval(bi2);\n\n        ByteInterval bi3 = new ByteInterval(null, 0x400000);\n        bi3.setSize(0x100000);\n        section.addByteInterval(bi3);\n\n        assertEquals(section.getAddress(), OptionalLong.empty());\n        assertEquals(section.getSize(), 0L);\n    }\n\n    @Test\n    void testAddAndRemoveFlags() throws Exception {\n        Section section =\n            new Section(\"section\", new HashSet<Section.SectionFlag>(),\n                        new ArrayList<ByteInterval>());\n\n        section.addSectionFlag(Section.SectionFlag.ThreadLocal);\n        section.addSectionFlag(Section.SectionFlag.Loaded);\n        assertEquals(section.getSectionFlags().size(), 2);\n\n        // Add same flag again should not increase list size\n        section.addSectionFlag(Section.SectionFlag.Loaded);\n        assertEquals(section.getSectionFlags().size(), 2);\n\n        // Remove a flag not set should return false\n        assertFalse(section.removeSectionFlag(Section.SectionFlag.Initialized));\n\n        // Remove a flag that is set\n        section.removeSectionFlag(Section.SectionFlag.ThreadLocal);\n        assertEquals(section.getSectionFlags().size(), 1);\n    }\n\n    @Test\n    void testAddAndRemoveByteIntervals() throws Exception {\n        Section section =\n            new Section(\"section\", new HashSet<Section.SectionFlag>(),\n                        new ArrayList<ByteInterval>());\n\n        ByteInterval bi = new ByteInterval();\n        assertTrue(section.getModule().isEmpty());\n        assertTrue(bi.getSection().isEmpty());\n\n        section.addByteInterval(bi);\n        assertEquals(bi.getSection().get(), section);\n        assertTrue(section.getByteIntervals().contains(bi));\n\n        assertTrue(section.removeByteInterval(bi));\n        assertTrue(bi.getSection().isEmpty());\n        assertEquals(section.getByteIntervals().size(), 0);\n    }\n}\n"
  },
  {
    "path": "java/tests/TestSymbolicExpressions.java",
    "content": "package tests;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport com.grammatech.gtirb.*;\nimport com.grammatech.gtirb.CodeBlock.DecodeMode;\nimport com.grammatech.gtirb.Module;\nimport com.grammatech.gtirb.Module.FileFormat;\nimport com.grammatech.gtirb.Module.ISA;\nimport com.grammatech.gtirb.SymbolicExpression.AttributeFlag;\nimport java.io.*;\nimport java.util.*;\nimport org.junit.jupiter.api.Test;\n\nclass TestSymbolicExpressions {\n\n    // Test forward compatibility for unknown symbolic expression attributes.\n    @Test\n    void testUnknownAttributes() throws Exception {\n        // Build minimal IR.\n\n        IR ir = new IR();\n        Module module = new Module(\"\", 0, 0, FileFormat.ELF, ISA.X64, \"test\");\n        Section section = new Section(\"foo\", new HashSet<Section.SectionFlag>(),\n                                      new ArrayList<ByteInterval>());\n        Symbol symbol = new Symbol(\"bar\", 0);\n        ByteInterval byteInterval = new ByteInterval();\n        SymbolicExpression expr =\n            new SymAddrConst(0, symbol.getUuid(), new HashSet<AttributeFlag>());\n        expr.addAttributeFlag(AttributeFlag.GOT);\n        expr.addUnknownFlag(0xBEEF);\n        byteInterval.insertSymbolicExpression(0, expr);\n\n        // byteIntervals.add(byteInterval);\n        section.addByteInterval(byteInterval);\n        module.addSection(section);\n        ir.addModule(module);\n\n        // Write IR to file.\n        ByteArrayOutputStream output = new ByteArrayOutputStream();\n        ir.saveFile(output);\n\n        // Load IR from file.\n        ByteArrayInputStream input =\n            new ByteArrayInputStream(output.toByteArray());\n        ir = IR.loadFile(input);\n\n        module = ir.getModules().get(0);\n        section = module.getSections().get(0);\n        byteInterval = section.getByteIntervals().get(0);\n        expr = (SymbolicExpression)byteInterval.symbolicExpressionIterator()\n                   .next()\n                   .getValue();\n\n        assertTrue(expr.getAttributeFlags().contains(AttributeFlag.GOT));\n        assertTrue(expr.getUnknownAttributeFlags().contains(0xBEEF));\n    }\n\n    @Test\n    void testSexprSetAndGet() throws Exception {\n        Set<AttributeFlag> flags = new HashSet<AttributeFlag>();\n        flags.add(AttributeFlag.PLT);\n        CodeBlock codeBlockA = new CodeBlock(0x10L, 0x400L, DecodeMode.Default);\n        CodeBlock codeBlockB = new CodeBlock(0x10L, 0x500L, DecodeMode.Default);\n\n        // test set/get of decode mode\n        codeBlockB.setDecodeMode(DecodeMode.Thumb);\n        assertEquals(codeBlockB.getDecodeMode(), DecodeMode.Thumb);\n\n        // test SymAddrAddr constructor\n        Symbol symbolA = new Symbol(\"CodeBlockA\", codeBlockA.getUuid());\n        Symbol symbolB = new Symbol(\"CodeBlockB\", codeBlockB.getUuid());\n        SymbolicExpression expr = new SymAddrAddr(0x100L, 1L, symbolA.getUuid(),\n                                                  symbolB.getUuid(), flags);\n\n        // test adding and removing attribute flags\n        expr.addAttributeFlag(AttributeFlag.S);\n        assertEquals(expr.getAttributeFlags().size(), 2);\n        expr.addAttributeFlag(AttributeFlag.PLT);\n        assertEquals(expr.getAttributeFlags().size(), 2);\n        expr.removeAttributeFlag(AttributeFlag.S);\n        assertEquals(expr.getAttributeFlags().size(), 1);\n        expr.removeUnknownFlag(0xF00eee);\n        assertEquals(expr.getUnknownAttributeFlags().size(), 0);\n    }\n}\n"
  },
  {
    "path": "java/tests/TestSymbols.java",
    "content": "package tests;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport com.grammatech.gtirb.*;\nimport com.grammatech.gtirb.Module;\nimport java.io.File;\nimport java.util.*;\nimport org.junit.jupiter.api.Test;\n\npublic class TestSymbols {\n\n    @Test\n    void testSymbolSaveAndLoad() throws Exception {\n        // Just create a simple IR w/ 1 module\n        IR ir_orig = new IR();\n        Module mod =\n            new Module(\"c:/foo.exe\", 0xCAFE, 0xBEEF, Module.FileFormat.ELF,\n                       Module.ISA.X64, \"myModule\");\n        ir_orig.addModule(mod);\n\n        UUID referentUuid = UUID.randomUUID();\n        long symbolValue = 0x5A3C;\n        // Symbol with no payload\n        Symbol symbol0 = new Symbol(\"symbol0\");\n        // Symbol with value payload\n        Symbol symbol1 = new Symbol(\"symbol1\", symbolValue);\n        // Symbol with referent payload\n        Symbol symbol2 = new Symbol(\"symbol2\", referentUuid);\n\n        mod.addSymbol(symbol2);\n        mod.addSymbol(symbol1);\n        mod.addSymbol(symbol0);\n\n        File file;\n        file = File.createTempFile(\"temp\", null);\n\n        String filename = file.getName();\n        try {\n            ir_orig.saveFile(filename);\n        } catch (Exception e) {\n            file.delete();\n            throw e;\n        }\n\n        IR ir_reloaded;\n        try {\n            ir_reloaded = IR.loadFile(filename);\n        } catch (Exception e) {\n            file.delete();\n            throw e;\n        }\n\n        file.delete();\n\n        assertNotNull(ir_reloaded);\n        Module mod_reloaded = ir_reloaded.getModules().get(0);\n\n        List<Symbol> symbols = mod_reloaded.getSymbols();\n        for (Symbol symbol : symbols) {\n            assertEquals(symbol.getModule(), Optional.of(mod_reloaded));\n            if (symbol.getName().equals(\"symbol0\")) {\n                assertEquals(symbol.getPayloadType(), Symbol.PayloadType.NONE);\n                assertEquals(symbol.getValue(), OptionalLong.empty());\n                assertEquals(symbol.getReferentUuid(), Optional.empty());\n            } else if (symbol.getName().equals(\"symbol1\")) {\n                assertEquals(symbol.getPayloadType(), Symbol.PayloadType.VALUE);\n                assertEquals(symbol.getValue(), OptionalLong.of(symbolValue));\n                assertEquals(symbol.getReferentUuid(), Optional.empty());\n            } else if (symbol.getName().equals(\"symbol2\")) {\n                assertEquals(symbol.getPayloadType(),\n                             Symbol.PayloadType.REFERENT);\n                assertEquals(symbol.getValue(), OptionalLong.empty());\n                assertEquals(symbol.getReferentUuid(),\n                             Optional.of(referentUuid));\n            } else\n                fail(\"Found an unrecognized symbol: \" + symbol.getName());\n        }\n    }\n\n    @Test\n    void testSymbolSetAndGet() throws Exception {\n\n        Symbol symbol = new Symbol(\"badName\");\n        symbol.setAtEnd(true);\n        symbol.setName(\"goodName\");\n\n        CodeBlock codeBlock =\n            new CodeBlock(0x10L, 0x400L, CodeBlock.DecodeMode.Default);\n        long symbolValue = 0x5A3C;\n\n        // test that setting a referent sets the payload type to REFERENT\n        symbol.setReferentUuid(codeBlock.getUuid());\n        assertEquals(symbol.getReferentUuid(),\n                     Optional.of(codeBlock.getUuid()));\n        assertEquals(symbol.getPayloadType(), Symbol.PayloadType.REFERENT);\n        assertEquals(symbol.getReferent(), codeBlock);\n\n        // test that setting a value sets the payload type to VALUE\n        symbol.setValue(symbolValue);\n        assertEquals(symbol.getValue(), OptionalLong.of(symbolValue));\n        assertEquals(symbol.getPayloadType(), Symbol.PayloadType.VALUE);\n\n        // test that symbol properties have held\n        assertEquals(symbol.getModule(), Optional.empty());\n        assertEquals(symbol.isAtEnd(), true);\n        assertEquals(symbol.getName(), \"goodName\");\n    }\n}\n"
  },
  {
    "path": "java/tests/TestTuple.java",
    "content": "package tests;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport com.grammatech.gtirb.tuple.Tuple1;\nimport com.grammatech.gtirb.tuple.Tuple2;\nimport com.grammatech.gtirb.tuple.Tuple3;\nimport com.grammatech.gtirb.tuple.Tuple4;\nimport com.grammatech.gtirb.tuple.Tuple5;\nimport org.junit.jupiter.api.Test;\n\nclass BarSingle extends Tuple1<String> {\n    public BarSingle(String s) { super(s); }\n    public String getString() { return this.get0(); }\n}\n\nclass BarPair extends Tuple2<String, Long> {\n    public BarPair(String s, Long l) { super(s, l); }\n    public String getString() { return this.get0(); }\n    public Long getLong() { return this.get1(); }\n}\n\nclass BarTriple extends Tuple3<String, Long, Float> {\n    public BarTriple(String s, Long l, Float f) { super(s, l, f); }\n    public String getString() { return this.get0(); }\n    public Long getLong() { return this.get1(); }\n    public Float getFloat() { return this.get2(); }\n}\n\nclass BarQuadruple extends Tuple4<String, Long, Float, Boolean> {\n    public BarQuadruple(String s, Long l, Float f, Boolean b) {\n        super(s, l, f, b);\n    }\n    public String getString() { return this.get0(); }\n    public Long getLong() { return this.get1(); }\n    public Float getFloat() { return this.get2(); }\n    public Boolean getBoolean() { return this.get3(); }\n}\n\nclass BarQuintuple extends Tuple5<String, Long, Float, Boolean, Integer> {\n    public BarQuintuple(String s, Long l, Float f, Boolean b, Integer i) {\n        super(s, l, f, b, i);\n    }\n    public String getString() { return this.get0(); }\n    public Long getLong() { return this.get1(); }\n    public Float getFloat() { return this.get2(); }\n    public Boolean getBoolean() { return this.get3(); }\n    public Integer getInteger() { return this.get4(); }\n}\n\npublic class TestTuple {\n    @Test\n    public void testTuple1() {\n        BarSingle f1 = new BarSingle(\"abc\");\n        assertEquals(\"abc\", f1.getString());\n        BarSingle f2 = new BarSingle(\"abc\");\n        assertEquals(f1, f2);\n        BarSingle f3 = new BarSingle(\"def\");\n        assertNotEquals(f1, f3);\n    }\n\n    @Test\n    public void testTuple2() {\n        BarPair f1 = new BarPair(\"abc\", 42L);\n        assertEquals(\"abc\", f1.getString());\n        assertEquals(42L, f1.getLong());\n        BarPair f2 = new BarPair(\"abc\", 42L);\n        assertEquals(f1, f2);\n        BarPair f3 = new BarPair(\"def\", 43L);\n        assertNotEquals(f1, f3);\n        BarPair f4 = new BarPair(\"abc\", 43L);\n        assertNotEquals(f1, f4);\n    }\n\n    @Test\n    public void testTuple3() {\n        BarTriple f1 = new BarTriple(\"abc\", 42L, 3.14f);\n        assertEquals(\"abc\", f1.getString());\n        assertEquals(42L, f1.getLong());\n        assertEquals(3.14f, f1.getFloat());\n        BarTriple f2 = new BarTriple(\"abc\", 42L, 3.14f);\n        assertEquals(f1, f2);\n        BarTriple f3 = new BarTriple(\"def\", 42L, 3.14f);\n        assertNotEquals(f1, f3);\n        BarTriple f4 = new BarTriple(\"abc\", 43L, 3.14f);\n        assertNotEquals(f1, f4);\n        BarTriple f5 = new BarTriple(\"abc\", 42L, 3.15f);\n        assertNotEquals(f1, f5);\n    }\n\n    @Test\n    public void testTuple4() {\n        BarQuadruple f1 = new BarQuadruple(\"abc\", 42L, 3.14f, true);\n        assertEquals(\"abc\", f1.getString());\n        assertEquals(42L, f1.getLong());\n        assertEquals(3.14f, f1.getFloat());\n        assertEquals(true, f1.getBoolean());\n        BarQuadruple f2 = new BarQuadruple(\"abc\", 42L, 3.14f, true);\n        assertEquals(f1, f2);\n        BarQuadruple f3 = new BarQuadruple(\"def\", 42L, 3.14f, true);\n        assertNotEquals(f1, f3);\n        BarQuadruple f4 = new BarQuadruple(\"abc\", 43L, 3.14f, true);\n        assertNotEquals(f1, f4);\n        BarQuadruple f5 = new BarQuadruple(\"abc\", 42L, 3.15f, true);\n        assertNotEquals(f1, f5);\n        BarQuadruple f6 = new BarQuadruple(\"abc\", 42L, 3.14f, false);\n        assertNotEquals(f1, f6);\n    }\n\n    @Test\n    public void testTuple5() {\n        BarQuintuple f1 = new BarQuintuple(\"abc\", 42L, 3.14f, true, 10);\n        assertEquals(\"abc\", f1.getString());\n        assertEquals(42L, f1.getLong());\n        assertEquals(3.14f, f1.getFloat());\n        assertEquals(true, f1.getBoolean());\n        assertEquals(10, f1.getInteger());\n        BarQuintuple f2 = new BarQuintuple(\"abc\", 42L, 3.14f, true, 10);\n        assertEquals(f1, f2);\n        BarQuintuple f3 = new BarQuintuple(\"def\", 42L, 3.14f, true, 10);\n        assertNotEquals(f1, f3);\n        BarQuintuple f4 = new BarQuintuple(\"abc\", 43L, 3.14f, true, 10);\n        assertNotEquals(f1, f4);\n        BarQuintuple f5 = new BarQuintuple(\"abc\", 42L, 3.15f, true, 10);\n        assertNotEquals(f1, f5);\n        BarQuintuple f6 = new BarQuintuple(\"abc\", 42L, 3.14f, false, 10);\n        assertNotEquals(f1, f6);\n        BarQuintuple f7 = new BarQuintuple(\"abc\", 42L, 3.14f, true, 11);\n        assertNotEquals(f1, f7);\n    }\n}\n"
  },
  {
    "path": "java/tests/TestVariant.java",
    "content": "package tests;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport com.grammatech.gtirb.Offset;\nimport com.grammatech.gtirb.variant.Token;\nimport com.grammatech.gtirb.variant.Variant11;\nimport com.grammatech.gtirb.variant.Variant2;\nimport com.grammatech.gtirb.variant.Variant3;\nimport java.util.Optional;\nimport java.util.UUID;\nimport org.junit.jupiter.api.Test;\n\nclass BarVariant2 extends Variant2<Long, Float> {\n    private BarVariant2(Token.T0 tok, Long l) { super(tok, l); }\n    private BarVariant2(Token.T1 tok, Float f) { super(tok, f); }\n    public Optional<Long> getLong() { return this.get0(); }\n    public Optional<Float> getFloat() { return this.get1(); }\n    public void setLong(Long l) { this.set0(l); }\n    public void setFloat(Float f) { this.set1(f); }\n    public static BarVariant2 ofLong(Long l) {\n        return new BarVariant2(new Token.T0(), l);\n    }\n    public static BarVariant2 ofFloat(Float f) {\n        return new BarVariant2(new Token.T1(), f);\n    }\n}\n\nclass BarVariant3 extends Variant3<Long, Float, Boolean> {\n    private BarVariant3(Token.T0 tok, Long l) { super(tok, l); }\n    private BarVariant3(Token.T1 tok, Float f) { super(tok, f); }\n    private BarVariant3(Token.T2 tok, Boolean b) { super(tok, b); }\n    public Optional<Long> getLong() { return this.get0(); }\n    public Optional<Float> getFloat() { return this.get1(); }\n    public Optional<Boolean> getBoolean() { return this.get2(); }\n    public void setLong(Long l) { this.set0(l); }\n    public void setFloat(Float f) { this.set1(f); }\n    public void setBoolean(Boolean b) { this.set2(b); }\n    public static BarVariant3 ofLong(Long l) {\n        return new BarVariant3(new Token.T0(), l);\n    }\n    public static BarVariant3 ofFloat(Float f) {\n        return new BarVariant3(new Token.T1(), f);\n    }\n    public static BarVariant3 ofBoolean(Boolean b) {\n        return new BarVariant3(new Token.T2(), b);\n    }\n}\n\nclass BarVariant11\n    extends Variant11<Long, Float, Boolean, Integer, String, Long, Float,\n                      Boolean, Integer, String, Offset> {\n    private BarVariant11(Token.T0 tok, Long l) { super(tok, l); }\n    private BarVariant11(Token.T1 tok, Float f) { super(tok, f); }\n    private BarVariant11(Token.T2 tok, Boolean b) { super(tok, b); }\n    private BarVariant11(Token.T3 tok, Integer i) { super(tok, i); }\n    private BarVariant11(Token.T4 tok, String s) { super(tok, s); }\n    private BarVariant11(Token.T5 tok, Long l) { super(tok, l); }\n    private BarVariant11(Token.T6 tok, Float f) { super(tok, f); }\n    private BarVariant11(Token.T7 tok, Boolean b) { super(tok, b); }\n    private BarVariant11(Token.T8 tok, Integer i) { super(tok, i); }\n    private BarVariant11(Token.T9 tok, String s) { super(tok, s); }\n    private BarVariant11(Token.T10 tok, Offset o) { super(tok, o); }\n    public Optional<Long> getLong1() { return this.get0(); }\n    public Optional<Float> getFloat1() { return this.get1(); }\n    public Optional<Boolean> getBoolean1() { return this.get2(); }\n    public Optional<Integer> getInteger1() { return this.get3(); }\n    public Optional<String> getString1() { return this.get4(); }\n    public Optional<Long> getLong2() { return this.get5(); }\n    public Optional<Float> getFloat2() { return this.get6(); }\n    public Optional<Boolean> getBoolean2() { return this.get7(); }\n    public Optional<Integer> getInteger2() { return this.get8(); }\n    public Optional<String> getString2() { return this.get9(); }\n    public Optional<Offset> getOffset() { return this.get10(); }\n    public void setLong1(Long l) { this.set0(l); }\n    public void setFloat1(Float f) { this.set1(f); }\n    public void setBoolean1(Boolean b) { this.set2(b); }\n    public void setInteger1(Integer i) { this.set3(i); }\n    public void setString1(String s) { this.set4(s); }\n    public void setLong2(Long l) { this.set5(l); }\n    public void setFloat2(Float f) { this.set6(f); }\n    public void setBoolean2(Boolean b) { this.set7(b); }\n    public void setInteger2(Integer i) { this.set8(i); }\n    public void setString2(String s) { this.set9(s); }\n    public void setOffset(Offset o) { this.set10(o); }\n    public static BarVariant11 ofLong1(Long l) {\n        return new BarVariant11(new Token.T0(), l);\n    }\n    public static BarVariant11 ofFloat1(Float f) {\n        return new BarVariant11(new Token.T1(), f);\n    }\n    public static BarVariant11 ofBoolean1(Boolean b) {\n        return new BarVariant11(new Token.T2(), b);\n    }\n    public static BarVariant11 ofInteger1(Integer i) {\n        return new BarVariant11(new Token.T3(), i);\n    }\n    public static BarVariant11 ofString1(String s) {\n        return new BarVariant11(new Token.T4(), s);\n    }\n    public static BarVariant11 ofLong2(Long l) {\n        return new BarVariant11(new Token.T5(), l);\n    }\n    public static BarVariant11 ofFloat2(Float f) {\n        return new BarVariant11(new Token.T6(), f);\n    }\n    public static BarVariant11 ofBoolean2(Boolean b) {\n        return new BarVariant11(new Token.T7(), b);\n    }\n    public static BarVariant11 ofInteger2(Integer i) {\n        return new BarVariant11(new Token.T8(), i);\n    }\n    public static BarVariant11 ofString2(String s) {\n        return new BarVariant11(new Token.T9(), s);\n    }\n    public static BarVariant11 ofOffset(Offset o) {\n        return new BarVariant11(new Token.T10(), o);\n    }\n}\n\npublic class TestVariant {\n    @Test\n    public void testVariant2() {\n        BarVariant2 fv1 = BarVariant2.ofLong(42L);\n        assertEquals(Optional.of(42L), fv1.getLong());\n        assertEquals(Optional.empty(), fv1.getFloat());\n        fv1.setLong(43L);\n        assertEquals(Optional.of(43L), fv1.getLong());\n        assertEquals(Optional.empty(), fv1.getFloat());\n        fv1.setFloat(3.14f);\n        assertEquals(Optional.empty(), fv1.getLong());\n        assertEquals(Optional.of(3.14f), fv1.getFloat());\n\n        BarVariant2 fv2 = BarVariant2.ofFloat(3.14f);\n        assertEquals(Optional.empty(), fv2.getLong());\n        assertEquals(Optional.of(3.14f), fv2.getFloat());\n        assertEquals(fv1, fv2);\n    }\n\n    @Test\n    public void testVariant3() {\n        BarVariant3 fv1 = BarVariant3.ofLong(42L);\n        assertEquals(Optional.of(42L), fv1.getLong());\n        assertEquals(Optional.empty(), fv1.getFloat());\n        assertEquals(Optional.empty(), fv1.getBoolean());\n        fv1.setLong(43L);\n        assertEquals(Optional.of(43L), fv1.getLong());\n        assertEquals(Optional.empty(), fv1.getFloat());\n        assertEquals(Optional.empty(), fv1.getBoolean());\n        fv1.setBoolean(true);\n        assertEquals(Optional.empty(), fv1.getLong());\n        assertEquals(Optional.empty(), fv1.getFloat());\n        assertEquals(Optional.of(true), fv1.getBoolean());\n        fv1.setFloat(3.14f);\n        assertEquals(Optional.empty(), fv1.getLong());\n        assertEquals(Optional.of(3.14f), fv1.getFloat());\n        assertEquals(Optional.empty(), fv1.getBoolean());\n\n        BarVariant3 fv2 = BarVariant3.ofFloat(3.14f);\n        assertEquals(Optional.empty(), fv2.getLong());\n        assertEquals(Optional.of(3.14f), fv2.getFloat());\n        assertEquals(Optional.empty(), fv2.getBoolean());\n        assertEquals(fv1, fv2);\n\n        BarVariant3 fv3 = BarVariant3.ofBoolean(false);\n        assertEquals(Optional.empty(), fv3.getLong());\n        assertEquals(Optional.empty(), fv3.getFloat());\n        assertEquals(Optional.of(false), fv3.getBoolean());\n    }\n\n    @Test\n    public void testVariant11() {\n        BarVariant11 fv1 = BarVariant11.ofLong1(42L);\n        assertEquals(Optional.of(42L), fv1.getLong1());\n        assertEquals(Optional.empty(), fv1.getFloat1());\n        assertEquals(Optional.empty(), fv1.getBoolean1());\n        assertEquals(Optional.empty(), fv1.getInteger1());\n        assertEquals(Optional.empty(), fv1.getString1());\n        assertEquals(Optional.empty(), fv1.getLong2());\n        assertEquals(Optional.empty(), fv1.getFloat2());\n        assertEquals(Optional.empty(), fv1.getBoolean2());\n        assertEquals(Optional.empty(), fv1.getInteger2());\n        assertEquals(Optional.empty(), fv1.getString2());\n        assertEquals(Optional.empty(), fv1.getOffset());\n        fv1.setLong1(43L);\n        assertEquals(Optional.of(43L), fv1.getLong1());\n        assertEquals(Optional.empty(), fv1.getFloat1());\n        assertEquals(Optional.empty(), fv1.getBoolean1());\n        assertEquals(Optional.empty(), fv1.getInteger1());\n        assertEquals(Optional.empty(), fv1.getString1());\n        assertEquals(Optional.empty(), fv1.getLong2());\n        assertEquals(Optional.empty(), fv1.getFloat2());\n        assertEquals(Optional.empty(), fv1.getBoolean2());\n        assertEquals(Optional.empty(), fv1.getInteger2());\n        assertEquals(Optional.empty(), fv1.getString2());\n        assertEquals(Optional.empty(), fv1.getOffset());\n        fv1.setBoolean1(true);\n        assertEquals(Optional.empty(), fv1.getLong1());\n        assertEquals(Optional.empty(), fv1.getFloat1());\n        assertEquals(Optional.of(true), fv1.getBoolean1());\n        assertEquals(Optional.empty(), fv1.getInteger1());\n        assertEquals(Optional.empty(), fv1.getString1());\n        assertEquals(Optional.empty(), fv1.getLong2());\n        assertEquals(Optional.empty(), fv1.getFloat2());\n        assertEquals(Optional.empty(), fv1.getBoolean2());\n        assertEquals(Optional.empty(), fv1.getInteger2());\n        assertEquals(Optional.empty(), fv1.getString2());\n        assertEquals(Optional.empty(), fv1.getOffset());\n        fv1.setInteger1(44);\n        assertEquals(Optional.empty(), fv1.getLong1());\n        assertEquals(Optional.empty(), fv1.getFloat1());\n        assertEquals(Optional.empty(), fv1.getBoolean1());\n        assertEquals(Optional.of(44), fv1.getInteger1());\n        assertEquals(Optional.empty(), fv1.getString1());\n        assertEquals(Optional.empty(), fv1.getLong2());\n        assertEquals(Optional.empty(), fv1.getFloat2());\n        assertEquals(Optional.empty(), fv1.getBoolean2());\n        assertEquals(Optional.empty(), fv1.getInteger2());\n        assertEquals(Optional.empty(), fv1.getString2());\n        assertEquals(Optional.empty(), fv1.getOffset());\n        fv1.setString1(\"abc\");\n        assertEquals(Optional.empty(), fv1.getLong1());\n        assertEquals(Optional.empty(), fv1.getFloat1());\n        assertEquals(Optional.empty(), fv1.getBoolean1());\n        assertEquals(Optional.empty(), fv1.getInteger1());\n        assertEquals(Optional.of(\"abc\"), fv1.getString1());\n        assertEquals(Optional.empty(), fv1.getLong2());\n        assertEquals(Optional.empty(), fv1.getFloat2());\n        assertEquals(Optional.empty(), fv1.getBoolean2());\n        assertEquals(Optional.empty(), fv1.getInteger2());\n        assertEquals(Optional.empty(), fv1.getString2());\n        assertEquals(Optional.empty(), fv1.getOffset());\n        fv1.setLong2(45L);\n        assertEquals(Optional.empty(), fv1.getLong1());\n        assertEquals(Optional.empty(), fv1.getFloat1());\n        assertEquals(Optional.empty(), fv1.getBoolean1());\n        assertEquals(Optional.empty(), fv1.getInteger1());\n        assertEquals(Optional.empty(), fv1.getString1());\n        assertEquals(Optional.of(45L), fv1.getLong2());\n        assertEquals(Optional.empty(), fv1.getFloat2());\n        assertEquals(Optional.empty(), fv1.getBoolean2());\n        assertEquals(Optional.empty(), fv1.getInteger2());\n        assertEquals(Optional.empty(), fv1.getString2());\n        assertEquals(Optional.empty(), fv1.getOffset());\n        fv1.setFloat2(3.16f);\n        assertEquals(Optional.empty(), fv1.getLong1());\n        assertEquals(Optional.empty(), fv1.getFloat1());\n        assertEquals(Optional.empty(), fv1.getBoolean1());\n        assertEquals(Optional.empty(), fv1.getInteger1());\n        assertEquals(Optional.empty(), fv1.getString1());\n        assertEquals(Optional.empty(), fv1.getLong2());\n        assertEquals(Optional.of(3.16f), fv1.getFloat2());\n        assertEquals(Optional.empty(), fv1.getBoolean2());\n        assertEquals(Optional.empty(), fv1.getInteger2());\n        assertEquals(Optional.empty(), fv1.getString2());\n        assertEquals(Optional.empty(), fv1.getOffset());\n        fv1.setBoolean2(false);\n        assertEquals(Optional.empty(), fv1.getLong1());\n        assertEquals(Optional.empty(), fv1.getFloat1());\n        assertEquals(Optional.empty(), fv1.getBoolean1());\n        assertEquals(Optional.empty(), fv1.getInteger1());\n        assertEquals(Optional.empty(), fv1.getString1());\n        assertEquals(Optional.empty(), fv1.getLong2());\n        assertEquals(Optional.empty(), fv1.getFloat2());\n        assertEquals(Optional.of(false), fv1.getBoolean2());\n        assertEquals(Optional.empty(), fv1.getInteger2());\n        assertEquals(Optional.empty(), fv1.getString2());\n        assertEquals(Optional.empty(), fv1.getOffset());\n        fv1.setInteger2(46);\n        assertEquals(Optional.empty(), fv1.getLong1());\n        assertEquals(Optional.empty(), fv1.getFloat1());\n        assertEquals(Optional.empty(), fv1.getBoolean1());\n        assertEquals(Optional.empty(), fv1.getInteger1());\n        assertEquals(Optional.empty(), fv1.getString1());\n        assertEquals(Optional.empty(), fv1.getLong2());\n        assertEquals(Optional.empty(), fv1.getFloat2());\n        assertEquals(Optional.empty(), fv1.getBoolean2());\n        assertEquals(Optional.of(46), fv1.getInteger2());\n        assertEquals(Optional.empty(), fv1.getString2());\n        assertEquals(Optional.empty(), fv1.getOffset());\n        fv1.setString2(\"def\");\n        assertEquals(Optional.empty(), fv1.getLong1());\n        assertEquals(Optional.empty(), fv1.getFloat1());\n        assertEquals(Optional.empty(), fv1.getBoolean1());\n        assertEquals(Optional.empty(), fv1.getInteger1());\n        assertEquals(Optional.empty(), fv1.getString1());\n        assertEquals(Optional.empty(), fv1.getLong2());\n        assertEquals(Optional.empty(), fv1.getFloat2());\n        assertEquals(Optional.empty(), fv1.getBoolean2());\n        assertEquals(Optional.empty(), fv1.getInteger2());\n        assertEquals(Optional.of(\"def\"), fv1.getString2());\n        assertEquals(Optional.empty(), fv1.getOffset());\n        fv1.setOffset(new Offset(new UUID(7, 8), 9));\n        assertEquals(Optional.empty(), fv1.getLong1());\n        assertEquals(Optional.empty(), fv1.getFloat1());\n        assertEquals(Optional.empty(), fv1.getBoolean1());\n        assertEquals(Optional.empty(), fv1.getInteger1());\n        assertEquals(Optional.empty(), fv1.getString1());\n        assertEquals(Optional.empty(), fv1.getLong2());\n        assertEquals(Optional.empty(), fv1.getFloat2());\n        assertEquals(Optional.empty(), fv1.getBoolean2());\n        assertEquals(Optional.empty(), fv1.getInteger2());\n        assertEquals(Optional.empty(), fv1.getString2());\n        assertEquals(Optional.of(new Offset(new UUID(7, 8), 9)),\n                     fv1.getOffset());\n        fv1.setFloat1(3.14f);\n        assertEquals(Optional.empty(), fv1.getLong1());\n        assertEquals(Optional.of(3.14f), fv1.getFloat1());\n        assertEquals(Optional.empty(), fv1.getBoolean1());\n        assertEquals(Optional.empty(), fv1.getInteger1());\n        assertEquals(Optional.empty(), fv1.getString1());\n        assertEquals(Optional.empty(), fv1.getLong2());\n        assertEquals(Optional.empty(), fv1.getFloat2());\n        assertEquals(Optional.empty(), fv1.getBoolean2());\n        assertEquals(Optional.empty(), fv1.getInteger2());\n        assertEquals(Optional.empty(), fv1.getString2());\n        assertEquals(Optional.empty(), fv1.getOffset());\n\n        BarVariant11 fv2 = BarVariant11.ofFloat1(3.14f);\n        assertEquals(Optional.empty(), fv2.getLong1());\n        assertEquals(Optional.of(3.14f), fv2.getFloat1());\n        assertEquals(Optional.empty(), fv2.getBoolean1());\n        assertEquals(Optional.empty(), fv2.getInteger1());\n        assertEquals(Optional.empty(), fv2.getString1());\n        assertEquals(Optional.empty(), fv2.getLong2());\n        assertEquals(Optional.empty(), fv2.getFloat2());\n        assertEquals(Optional.empty(), fv2.getBoolean2());\n        assertEquals(Optional.empty(), fv2.getInteger2());\n        assertEquals(Optional.empty(), fv2.getString2());\n        assertEquals(Optional.empty(), fv2.getOffset());\n        assertEquals(fv1, fv2);\n\n        BarVariant11 fv3 = BarVariant11.ofBoolean1(false);\n        assertEquals(Optional.empty(), fv3.getLong1());\n        assertEquals(Optional.empty(), fv3.getFloat1());\n        assertEquals(Optional.of(false), fv3.getBoolean1());\n        assertEquals(Optional.empty(), fv3.getInteger1());\n        assertEquals(Optional.empty(), fv3.getString1());\n        assertEquals(Optional.empty(), fv3.getLong2());\n        assertEquals(Optional.empty(), fv3.getFloat2());\n        assertEquals(Optional.empty(), fv3.getBoolean2());\n        assertEquals(Optional.empty(), fv3.getInteger2());\n        assertEquals(Optional.empty(), fv3.getString2());\n        assertEquals(Optional.empty(), fv3.getOffset());\n\n        BarVariant11 fv4 = BarVariant11.ofInteger1(47);\n        assertEquals(Optional.empty(), fv4.getLong1());\n        assertEquals(Optional.empty(), fv4.getFloat1());\n        assertEquals(Optional.empty(), fv4.getBoolean1());\n        assertEquals(Optional.of(47), fv4.getInteger1());\n        assertEquals(Optional.empty(), fv4.getString1());\n        assertEquals(Optional.empty(), fv4.getLong2());\n        assertEquals(Optional.empty(), fv4.getFloat2());\n        assertEquals(Optional.empty(), fv4.getBoolean2());\n        assertEquals(Optional.empty(), fv4.getInteger2());\n        assertEquals(Optional.empty(), fv4.getString2());\n        assertEquals(Optional.empty(), fv4.getOffset());\n\n        BarVariant11 fv5 = BarVariant11.ofString1(\"ghi\");\n        assertEquals(Optional.empty(), fv5.getLong1());\n        assertEquals(Optional.empty(), fv5.getFloat1());\n        assertEquals(Optional.empty(), fv5.getBoolean1());\n        assertEquals(Optional.empty(), fv5.getInteger1());\n        assertEquals(Optional.of(\"ghi\"), fv5.getString1());\n        assertEquals(Optional.empty(), fv5.getLong2());\n        assertEquals(Optional.empty(), fv5.getFloat2());\n        assertEquals(Optional.empty(), fv5.getBoolean2());\n        assertEquals(Optional.empty(), fv5.getInteger2());\n        assertEquals(Optional.empty(), fv5.getString2());\n        assertEquals(Optional.empty(), fv5.getOffset());\n\n        BarVariant11 fv6 = BarVariant11.ofLong2(48L);\n        assertEquals(Optional.empty(), fv6.getLong1());\n        assertEquals(Optional.empty(), fv6.getFloat1());\n        assertEquals(Optional.empty(), fv6.getBoolean1());\n        assertEquals(Optional.empty(), fv6.getInteger1());\n        assertEquals(Optional.empty(), fv6.getString1());\n        assertEquals(Optional.of(48L), fv6.getLong2());\n        assertEquals(Optional.empty(), fv6.getFloat2());\n        assertEquals(Optional.empty(), fv6.getBoolean2());\n        assertEquals(Optional.empty(), fv6.getInteger2());\n        assertEquals(Optional.empty(), fv6.getString2());\n        assertEquals(Optional.empty(), fv6.getOffset());\n\n        BarVariant11 fv7 = BarVariant11.ofFloat2(3.17f);\n        assertEquals(Optional.empty(), fv7.getLong1());\n        assertEquals(Optional.empty(), fv7.getFloat1());\n        assertEquals(Optional.empty(), fv7.getBoolean1());\n        assertEquals(Optional.empty(), fv7.getInteger1());\n        assertEquals(Optional.empty(), fv7.getString1());\n        assertEquals(Optional.empty(), fv7.getLong2());\n        assertEquals(Optional.of(3.17f), fv7.getFloat2());\n        assertEquals(Optional.empty(), fv7.getBoolean2());\n        assertEquals(Optional.empty(), fv7.getInteger2());\n        assertEquals(Optional.empty(), fv7.getString2());\n        assertEquals(Optional.empty(), fv7.getOffset());\n\n        BarVariant11 fv8 = BarVariant11.ofBoolean2(true);\n        assertEquals(Optional.empty(), fv8.getLong1());\n        assertEquals(Optional.empty(), fv8.getFloat1());\n        assertEquals(Optional.empty(), fv8.getBoolean1());\n        assertEquals(Optional.empty(), fv8.getInteger1());\n        assertEquals(Optional.empty(), fv8.getString1());\n        assertEquals(Optional.empty(), fv8.getLong2());\n        assertEquals(Optional.empty(), fv8.getFloat2());\n        assertEquals(Optional.of(true), fv8.getBoolean2());\n        assertEquals(Optional.empty(), fv8.getInteger2());\n        assertEquals(Optional.empty(), fv8.getString2());\n        assertEquals(Optional.empty(), fv8.getOffset());\n\n        BarVariant11 fv9 = BarVariant11.ofInteger2(49);\n        assertEquals(Optional.empty(), fv9.getLong1());\n        assertEquals(Optional.empty(), fv9.getFloat1());\n        assertEquals(Optional.empty(), fv9.getBoolean1());\n        assertEquals(Optional.empty(), fv9.getInteger1());\n        assertEquals(Optional.empty(), fv9.getString1());\n        assertEquals(Optional.empty(), fv9.getLong2());\n        assertEquals(Optional.empty(), fv9.getFloat2());\n        assertEquals(Optional.empty(), fv9.getBoolean2());\n        assertEquals(Optional.of(49), fv9.getInteger2());\n        assertEquals(Optional.empty(), fv9.getString2());\n        assertEquals(Optional.empty(), fv9.getOffset());\n\n        BarVariant11 fv10 = BarVariant11.ofString2(\"jkl\");\n        assertEquals(Optional.empty(), fv10.getLong1());\n        assertEquals(Optional.empty(), fv10.getFloat1());\n        assertEquals(Optional.empty(), fv10.getBoolean1());\n        assertEquals(Optional.empty(), fv10.getInteger1());\n        assertEquals(Optional.empty(), fv10.getString1());\n        assertEquals(Optional.empty(), fv10.getLong2());\n        assertEquals(Optional.empty(), fv10.getFloat2());\n        assertEquals(Optional.empty(), fv10.getBoolean2());\n        assertEquals(Optional.empty(), fv10.getInteger2());\n        assertEquals(Optional.of(\"jkl\"), fv10.getString2());\n        assertEquals(Optional.empty(), fv10.getOffset());\n\n        BarVariant11 fv11 =\n            BarVariant11.ofOffset(new Offset(new UUID(21, 22), 23));\n        assertEquals(Optional.empty(), fv11.getLong1());\n        assertEquals(Optional.empty(), fv11.getFloat1());\n        assertEquals(Optional.empty(), fv11.getBoolean1());\n        assertEquals(Optional.empty(), fv11.getInteger1());\n        assertEquals(Optional.empty(), fv11.getString1());\n        assertEquals(Optional.empty(), fv11.getLong2());\n        assertEquals(Optional.empty(), fv11.getFloat2());\n        assertEquals(Optional.empty(), fv11.getBoolean2());\n        assertEquals(Optional.empty(), fv11.getInteger2());\n        assertEquals(Optional.empty(), fv11.getString2());\n        assertEquals(Optional.of(new Offset(new UUID(21, 22), 23)),\n                     fv11.getOffset());\n    }\n}\n"
  },
  {
    "path": "proto/AuxData.proto",
    "content": "//===- AuxData.proto ------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage gtirb.proto;\noption java_package = \"com.grammatech.gtirb.proto\";\n\nmessage AuxData {\n  string type_name = 1;\n  bytes data = 2;\n}\n"
  },
  {
    "path": "proto/ByteInterval.proto",
    "content": "//===- ByteInterval.proto -------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage gtirb.proto;\noption java_package = \"com.grammatech.gtirb.proto\";\n\nimport \"CodeBlock.proto\";\nimport \"DataBlock.proto\";\nimport \"SymbolicExpression.proto\";\n\nmessage Block {\n  uint64 offset = 1;\n  oneof value {\n    CodeBlock code = 2;\n    DataBlock data = 3;\n  }\n}\n\nmessage ByteInterval {\n  bytes uuid = 1;\n  repeated Block blocks = 2;\n  map<uint64, SymbolicExpression> symbolic_expressions = 3;\n  bool has_address = 4;\n  uint64 address = 5;\n  uint64 size = 6;\n  bytes contents = 7;\n}\n"
  },
  {
    "path": "proto/CFG.proto",
    "content": "//===- CFG.proto ----------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage gtirb.proto;\noption java_package = \"com.grammatech.gtirb.proto\";\n\nenum EdgeType {\n  Type_Branch = 0;\n  Type_Call = 1;\n  Type_Fallthrough = 2;\n  Type_Return = 3;\n  Type_Syscall = 4;\n  Type_Sysret = 5;\n}\n\nmessage EdgeLabel {\n  bool conditional = 1;\n  bool direct = 2;\n  EdgeType type = 3;\n}\n\nmessage Edge {\n  reserved 3, 4;\n  reserved \"boolean\", \"integer\";\n\n  bytes source_uuid = 1;\n  bytes target_uuid = 2;\n  EdgeLabel label = 5;\n}\n\nmessage CFG {\n  reserved 1;\n  reserved \"blocks\";\n\n  repeated bytes vertices = 3;\n  repeated Edge edges = 2;\n}\n"
  },
  {
    "path": "proto/CMakeLists.txt",
    "content": "# GTIRB_PROTO_DIR\n#\n# Directory containing the default *.proto files.\n\nset(GTIRB_PROTO_DIR\n    ${CMAKE_CURRENT_SOURCE_DIR}\n    PARENT_SCOPE\n)\n\n# GTIRB_PROTO_FILES\n#\n# List of *.proto definition files.\n\nfile(GLOB GTIRB_PROTO_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.proto)\nset(GTIRB_PROTO_FILES\n    ${GTIRB_PROTO_FILES}\n    PARENT_SCOPE\n)\n"
  },
  {
    "path": "proto/CodeBlock.proto",
    "content": "//===- CodeBlock.proto ----------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage gtirb.proto;\noption java_package = \"com.grammatech.gtirb.proto\";\n\nenum DecodeMode {\n  All_Default = 0;\n  ARM_Thumb = 1;\n};\n\nmessage CodeBlock {\n  reserved \"address\";\n  reserved 2;\n\n  bytes uuid = 1;\n  uint64 size = 3;\n  DecodeMode decode_mode = 4;\n}\n"
  },
  {
    "path": "proto/DataBlock.proto",
    "content": "//===- DataBlock.proto ----------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage gtirb.proto;\noption java_package = \"com.grammatech.gtirb.proto\";\n\nmessage DataBlock {\n  reserved \"address\";\n  reserved 2;\n\n  bytes uuid = 1;\n  uint64 size = 3;\n}\n"
  },
  {
    "path": "proto/IR.proto",
    "content": "//===- IR.proto -----------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage gtirb.proto;\noption java_package = \"com.grammatech.gtirb.proto\";\n\nimport \"AuxData.proto\";\nimport \"CFG.proto\";\nimport \"Module.proto\";\n\nmessage IR {\n  // slot 4 has been used for multiple fields in the past\n  // (more specifically, main_module_id and aux_data_container),\n  // which is a Protobuf compatibility violation, but explains why we\n  // reserve more field names than field numbers.\n  reserved \"tables\", \"main_module_id\", \"aux_data_container\";\n  reserved 2, 4;\n\n  bytes uuid = 1;\n  repeated Module modules = 3;\n  map<string, AuxData> aux_data = 5;\n  uint32 version = 6;\n  CFG cfg = 7;\n}\n"
  },
  {
    "path": "proto/Module.proto",
    "content": "//===- Module.proto -------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage gtirb.proto;\noption java_package = \"com.grammatech.gtirb.proto\";\n\nimport \"AuxData.proto\";\nimport \"ProxyBlock.proto\";\nimport \"Section.proto\";\nimport \"Symbol.proto\";\n\nenum FileFormat {\n  Format_Undefined = 0;\n  COFF = 1;\n  ELF = 2;\n  PE = 3;\n  IdaProDb32 = 4;\n  IdaProDb64 = 5;\n  XCOFF = 6;\n  MACHO = 7;\n  RAW = 8;\n};\n\nenum ISA {\n  ISA_Undefined = 0;\n  IA32 = 1;\n  PPC32 = 2;\n  X64 = 3;\n  ARM = 4;\n  ValidButUnsupported = 5;\n  PPC64 = 6;\n  ARM64 = 7;\n  MIPS32 = 8;\n  MIPS64 = 9;\n};\n\nenum ByteOrder {\n  ByteOrder_Undefined = 0;\n  BigEndian = 1;\n  LittleEndian = 2;\n}\n\nmessage Module {\n  reserved \"image_byte_map\", \"data\", \"symbolic_operands\", \"aux_data_container\",\n      \"blocks\", \"cfg\";\n  reserved 8, 10, 11, 13, 14, 15;\n\n  bytes uuid = 1;\n  string binary_path = 2;\n  uint64 preferred_addr = 3;\n  int64 rebase_delta = 4;\n  FileFormat file_format = 5;\n  ISA isa = 6;\n  string name = 7;\n  repeated Symbol symbols = 9;\n  repeated ProxyBlock proxies = 16;\n  repeated Section sections = 12;\n  map<string, AuxData> aux_data = 17;\n  bytes entry_point = 18;\n  ByteOrder byte_order = 19;\n}\n"
  },
  {
    "path": "proto/Offset.proto",
    "content": "//===- Offset.proto -------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage gtirb.proto;\noption java_package = \"com.grammatech.gtirb.proto\";\n\nmessage Offset {\n  bytes element_id = 1;\n  uint64 displacement = 2;\n}\n"
  },
  {
    "path": "proto/ProxyBlock.proto",
    "content": "//===- ProxyBlock.proto ---------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage gtirb.proto;\noption java_package = \"com.grammatech.gtirb.proto\";\n\nmessage ProxyBlock { bytes uuid = 1; }\n"
  },
  {
    "path": "proto/Section.proto",
    "content": "//===- Section.proto ------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage gtirb.proto;\noption java_package = \"com.grammatech.gtirb.proto\";\n\nimport \"ByteInterval.proto\";\n\nenum SectionFlag {\n  Section_Undefined = 0;\n  Readable = 1;\n  Writable = 2;\n  Executable = 3;\n  Loaded = 4;\n  Initialized = 5;\n  ThreadLocal = 6;\n}\n\nmessage Section {\n  reserved \"address\", \"size\";\n  reserved 3, 4;\n\n  bytes uuid = 1;\n  string name = 2;\n  repeated ByteInterval byte_intervals = 5;\n  repeated SectionFlag section_flags = 6;\n}\n"
  },
  {
    "path": "proto/Symbol.proto",
    "content": "//===- Symbol.proto -------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage gtirb.proto;\noption java_package = \"com.grammatech.gtirb.proto\";\n\nmessage Symbol {\n  reserved 4;\n  reserved \"storage_kind\";\n\n  bytes uuid = 1;\n  oneof optional_payload {\n    uint64 value = 2;\n    bytes referent_uuid = 5;\n  }\n  string name = 3;\n  bool at_end = 6;\n}\n"
  },
  {
    "path": "proto/SymbolicExpression.proto",
    "content": "//===- SymbolicExpression.proto -------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage gtirb.proto;\noption java_package = \"com.grammatech.gtirb.proto\";\n\nmessage SymStackConst {\n  int32 offset = 1;\n  bytes symbol_uuid = 2;\n}\n\nmessage SymAddrConst {\n  int64 offset = 1;\n  bytes symbol_uuid = 2;\n}\n\nmessage SymAddrAddr {\n  int64 scale = 1;\n  int64 offset = 2;\n  bytes symbol1_uuid = 3;\n  bytes symbol2_uuid = 4;\n}\n\n// NOTE:\n// We do not generalize or otherwise unify relocation attributes across\n// architectures and instead prefer an explicit mapping of attributes names\n// to the labels used in the assembly of each architecture.\nenum SymAttribute {\n  // ELF\n  GOT = 0;\n  GOTPC = 1;\n  GOTOFF = 2;\n  GOTREL = 3;\n  PLT = 4;\n  PLTOFF = 5;\n  PCREL = 6;\n  SECREL = 7;\n  TLS = 8;\n  TLSGD = 9;\n  TLSLD = 10;\n  TLSLDM = 11;\n  TLSCALL = 12;\n  TLSDESC = 13;\n  TPREL = 14;\n  TPOFF = 15;\n  DTPREL = 16;\n  DTPOFF = 17;\n  NTPOFF = 18;\n  DTPMOD = 19;\n  PAGE = 20;\n  PAGEOFF = 21;\n  CALL = 22;\n  LO = 23;\n  HI = 24;\n  HIGHER = 25;\n  HIGHEST = 26;\n\n  // X86\n  GOTNTPOFF = 1000;\n  INDNTPOFF = 1001;\n\n  // ARM\n  G0 = 2001;\n  G1 = 2002;\n  G2 = 2003;\n  G3 = 2004;\n  UPPER16 = 2005;\n  LOWER16 = 2006;\n  LO12 = 2007;\n  LO15 = 2008;\n  LO14 = 2009;\n  HI12 = 2010;\n  HI21 = 2011;\n  S = 2012;\n  PG = 2013;\n  NC = 2014;\n  ABS = 2015;\n  PREL = 2016;\n  PREL31 = 2017;\n  TARGET1 = 2018;\n  TARGET2 = 2019;\n  SBREL = 2020;\n  TLSLDO = 2021;\n\n  // MIPS\n  HI16 = 3000;\n  LO16 = 3001;\n  GPREL = 3002;\n  DISP = 3003;\n  OFST = 3004;\n\n  // PPC\n  H = 4000;\n  L = 4001;\n  HA = 4002;\n  HIGH = 4003;\n  HIGHA = 4004;\n  HIGHERA = 4005;\n  HIGHESTA = 4006;\n  TOCBASE = 4007;\n  TOC = 4008;\n  NOTOC = 4009;\n}\n\nmessage SymbolicExpression {\n  reserved \"stack_const\";\n  reserved 1;\n  oneof value {\n    SymAddrConst addr_const = 2;\n    SymAddrAddr addr_addr = 3;\n  }\n  repeated SymAttribute attribute_flags = 4;\n}\n"
  },
  {
    "path": "proto/v0/AuxData.proto",
    "content": "//===- AuxData.proto ------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2018 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage protoV0;\n\nmessage AuxData {\n  string type_name = 1;\n  bytes data = 2;\n}\n"
  },
  {
    "path": "proto/v0/AuxDataContainer.proto",
    "content": "//===- AuxDataContainer.proto ---------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2018 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n\nsyntax = \"proto3\";\npackage protoV0;\n\nimport \"AuxData.proto\";\n\nmessage AuxDataContainer { map<string, AuxData> aux_data = 1; }\n"
  },
  {
    "path": "proto/v0/Block.proto",
    "content": "//===- Block.proto --------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2018 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage protoV0;\n\nmessage Block {\n  bytes uuid = 1;\n  uint64 address = 2;\n  uint64 size = 3;\n  uint64 decode_mode = 4;\n}\n"
  },
  {
    "path": "proto/v0/ByteMap.proto",
    "content": "//===- ByteMap.proto ------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2018 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage protoV0;\n\nmessage Region {\n  uint64 address = 1;\n  bytes data = 2;\n}\n\nmessage ByteMap { repeated Region regions = 1; }\n"
  },
  {
    "path": "proto/v0/CFG.proto",
    "content": "//===- CFG.proto ----------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2018 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage protoV0;\n\nenum EdgeType {\n  Type_Branch = 0;\n  Type_Call = 1;\n  Type_Fallthrough = 2;\n  Type_Return = 3;\n  Type_Syscall = 4;\n  Type_Sysret = 5;\n}\n\nmessage EdgeLabel {\n  bool conditional = 1;\n  bool direct = 2;\n  EdgeType type = 3;\n}\n\nmessage Edge {\n  reserved 3, 4;\n  reserved \"boolean\", \"integer\";\n\n  bytes source_uuid = 1;\n  bytes target_uuid = 2;\n  EdgeLabel label = 5;\n}\n\nmessage CFG {\n  reserved 1;\n  reserved \"blocks\";\n\n  repeated bytes vertices = 3;\n  repeated Edge edges = 2;\n}\n"
  },
  {
    "path": "proto/v0/CMakeLists.txt",
    "content": "file(GLOB PROTO_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.proto)\nset(PROTO_FILES\n    ${PROTO_FILES}\n    PARENT_SCOPE\n)\n"
  },
  {
    "path": "proto/v0/DataObject.proto",
    "content": "//===- DataObject.proto ---------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2018 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage protoV0;\n\nmessage DataObject {\n  bytes uuid = 1;\n  uint64 address = 2;\n  uint64 size = 3;\n}\n"
  },
  {
    "path": "proto/v0/IR.proto",
    "content": "//===- IR.proto -----------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2018 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage protoV0;\n\nimport \"AuxDataContainer.proto\";\nimport \"Module.proto\";\n\nmessage IR {\n  bytes uuid = 1;\n  repeated Module modules = 3;\n  AuxDataContainer aux_data_container = 4;\n}\n"
  },
  {
    "path": "proto/v0/ImageByteMap.proto",
    "content": "//===- ImageByteMap.proto -------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2018 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage protoV0;\n\nimport \"ByteMap.proto\";\n\nmessage ImageByteMap {\n  bytes uuid = 1;\n  ByteMap byte_map = 2;\n  uint64 addr_min = 3;\n  uint64 addr_max = 4;\n  uint64 base_address = 5;\n  uint64 entry_point_address = 6;\n}\n"
  },
  {
    "path": "proto/v0/Module.proto",
    "content": "//===- Module.proto -------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2018 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage protoV0;\n\nimport \"AuxDataContainer.proto\";\nimport \"Block.proto\";\nimport \"CFG.proto\";\nimport \"DataObject.proto\";\nimport \"ImageByteMap.proto\";\nimport \"ProxyBlock.proto\";\nimport \"Section.proto\";\nimport \"Symbol.proto\";\nimport \"SymbolicExpression.proto\";\n\nenum FileFormat {\n  Format_Undefined = 0;\n  COFF = 1;\n  ELF = 2;\n  PE = 3;\n  IdaProDb32 = 4;\n  IdaProDb64 = 5;\n  XCOFF = 6;\n  MACHO = 7;\n  RAW = 8;\n};\n\nenum ISAID {\n  ISA_Undefined = 0;\n  IA32 = 1;\n  PPC32 = 2;\n  X64 = 3;\n  ARM = 4;\n  ValidButUnsupported = 5;\n};\n\nmessage Module {\n  bytes uuid = 1;\n  string binary_path = 2;\n  uint64 preferred_addr = 3;\n  int64 rebase_delta = 4;\n  FileFormat file_format = 5;\n  ISAID isa_id = 6;\n  string name = 7;\n  ImageByteMap image_byte_map = 8;\n  repeated Symbol symbols = 9;\n  CFG cfg = 10;\n  repeated Block blocks = 15;\n  repeated DataObject data = 11;\n  repeated ProxyBlock proxies = 16;\n  repeated Section sections = 12;\n  map<uint64, SymbolicExpression> symbolic_operands = 13;\n  AuxDataContainer aux_data_container = 14;\n}\n"
  },
  {
    "path": "proto/v0/Offset.proto",
    "content": "//===- Offset.proto -------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2018 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage protoV0;\n\nmessage Offset {\n  bytes element_id = 1;\n  uint64 displacement = 2;\n}\n"
  },
  {
    "path": "proto/v0/ProxyBlock.proto",
    "content": "//===- ProxyBlock.proto ---------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2018 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage protoV0;\n\nmessage ProxyBlock { bytes uuid = 1; }\n"
  },
  {
    "path": "proto/v0/Section.proto",
    "content": "//===- Section.proto ------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2018 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage protoV0;\n\nmessage Section {\n  bytes uuid = 1;\n  string name = 2;\n  uint64 address = 3;\n  uint64 size = 4;\n}\n"
  },
  {
    "path": "proto/v0/Symbol.proto",
    "content": "//===- Symbol.proto -------------------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2018 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage protoV0;\n\nenum StorageKind {\n  Storage_Undefined = 0;\n  Storage_Normal = 1;\n  Storage_Static = 2;\n  Storage_Extern = 3;\n  Storage_Local = 4;\n};\n\nmessage Symbol {\n  bytes uuid = 1;\n  oneof optional_payload {\n    uint64 value = 2;\n    bytes referent_uuid = 5;\n  }\n  string name = 3;\n  StorageKind storage_kind = 4;\n}\n"
  },
  {
    "path": "proto/v0/SymbolicExpression.proto",
    "content": "//===- SymbolicExpression.proto -------------------------------*- Proto -*-===//\n//\n//  Copyright (C) 2018 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\nsyntax = \"proto3\";\npackage protoV0;\n\nmessage SymStackConst {\n  int32 offset = 1;\n  bytes symbol_uuid = 2;\n}\n\nmessage SymAddrConst {\n  int64 offset = 1;\n  bytes symbol_uuid = 2;\n}\n\nmessage SymAddrAddr {\n  int64 scale = 1;\n  int64 offset = 2;\n  bytes symbol1_uuid = 3;\n  bytes symbol2_uuid = 4;\n}\n\nmessage SymbolicExpression {\n  oneof value {\n    SymStackConst stack_const = 1;\n    SymAddrConst addr_const = 2;\n    SymAddrAddr addr_addr = 3;\n  }\n}\n"
  },
  {
    "path": "python/CMakeLists.txt",
    "content": "if(GTIRB_ENABLE_MYPY)\n  find_program(MYPY mypy)\n  find_program(MYPY_PROTOBUF protoc-gen-mypy)\n  if(MYPY AND MYPY_PROTOBUF)\n    set(ENABLE_MYPY ON)\n    set(MYPY_PROTOBUF_FLAGS --mypy_out=${CMAKE_CURRENT_BINARY_DIR})\n    configure_file(mypy.ini.in mypy.ini @ONLY)\n  else()\n    set(ENABLE_MYPY OFF)\n    if(NOT MYPY)\n      message(\n        WARNING \"mypy not found. Type checking with mypy will be disabled.\"\n      )\n    endif()\n    if(NOT MYPY_PROTOBUF)\n      message(\n        WARNING\n          \"protoc-gen-mypy not found. Type checking with mypy will be disabled.\"\n      )\n    endif()\n  endif()\nendif()\n\n# Create a PEP 561 py.typed to let clients find the inline type annotations.\nfile(WRITE ${CMAKE_CURRENT_BINARY_DIR}/gtirb/py.typed \"\")\n\nif(\"${Protobuf_VERSION}\" VERSION_LESS \"3.19.0\")\n  # Older protobuf compilers generate code incompatible with newer runtimes.\n  set(GTIRB_PROTOBUF_CONSTRAINT \"protobuf >= ${Protobuf_VERSION}, < 4.0\")\nelse()\n  set(GTIRB_PROTOBUF_CONSTRAINT \"protobuf >= 4.0\")\nendif()\n\nconfigure_file(pyproject.toml.in pyproject.toml @ONLY)\nconfigure_file(README.md README COPYONLY)\nconfigure_file(requirements-dev.txt requirements-dev.txt COPYONLY)\nconfigure_file(requirements-mypy.txt requirements-mypy.txt COPYONLY)\nconfigure_file(tox.ini tox.ini COPYONLY)\n# Copy the license from the top-level of the source repo.\nconfigure_file(${CMAKE_SOURCE_DIR}/LICENSE.txt LICENSE COPYONLY)\n\n# ---------------------------------------------------------------------------\n# Building the gtirb protobuf files into python\n# ---------------------------------------------------------------------------\n\nset(PROTO_PY_DIR ${CMAKE_CURRENT_BINARY_DIR}/gtirb/proto)\n\n# Rewrite the proto definitions to use paths when including other definitions.\n# We do this instead of using the one-line configure_file() command so that the\n# proto/*.proto files in the source directory do not need to be rewritten for\n# the CL API.\n\nforeach(GTIRB_PROTO_FILE ${GTIRB_PROTO_FILES})\n  get_filename_component(PROTO_BASE ${GTIRB_PROTO_FILE} NAME_WE)\n  set(PROTO_PY_OUT \"${PROTO_PY_DIR}/${PROTO_BASE}.proto\")\n  file(READ ${GTIRB_PROTO_FILE} PROTO_DEF_STR)\n  string(REGEX REPLACE \"import \\\"\" \"import \\\"gtirb/proto/\" PROTO_DEF_STR\n                       \"${PROTO_DEF_STR}\"\n  )\n  file(WRITE ${PROTO_PY_OUT} \"${PROTO_DEF_STR}\")\n\n  set(PROTO_PY_SOURCE \"${PROTO_PY_DIR}/${PROTO_BASE}_pb2.py\")\n  add_custom_command(\n    OUTPUT \"${PROTO_PY_SOURCE}\"\n    COMMAND\n      protobuf::protoc --python_out ${CMAKE_CURRENT_BINARY_DIR}\n      ${MYPY_PROTOBUF_FLAGS} -I \"${CMAKE_CURRENT_BINARY_DIR}\" ${PROTO_PY_OUT}\n    DEPENDS ${PROTO_PY_OUT} protobuf::protoc\n    VERBATIM\n  )\n  list(APPEND PROTO_PY_SOURCES \"${PROTO_PY_SOURCE}\")\nendforeach()\nadd_custom_target(py-proto DEPENDS ${PROTO_PY_SOURCES})\n\n# existing Python files\nfile(GLOB PY_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/gtirb/*.py\n     ${CMAKE_CURRENT_SOURCE_DIR}/tests/*.py\n)\n\nadd_custom_target(pygtirb ALL DEPENDS ${PY_SOURCES} py-proto)\nadd_custom_command(\n  TARGET pygtirb\n  COMMAND ${CMAKE_COMMAND} -E make_directory \"${CMAKE_CURRENT_BINARY_DIR}/gtirb\"\n          \"${CMAKE_CURRENT_BINARY_DIR}/tests\"\n  COMMAND ${CMAKE_COMMAND} -E copy_directory \"${CMAKE_CURRENT_SOURCE_DIR}/gtirb\"\n          \"${CMAKE_CURRENT_BINARY_DIR}/gtirb\"\n  COMMAND ${CMAKE_COMMAND} -E copy_directory\n          \"${CMAKE_CURRENT_SOURCE_DIR}/tests\"\n          \"${CMAKE_CURRENT_BINARY_DIR}/tests\"\n)\n\nif(GTIRB_RELEASE_VERSION)\n  set(GTIRB_PYTHON_DEV_SUFFIX \"\")\nelse()\n  set(GTIRB_PYTHON_DEV_SUFFIX \".dev\")\nendif()\n\nconfigure_file(\n  ${CMAKE_CURRENT_SOURCE_DIR}/version.py.in\n  ${CMAKE_CURRENT_BINARY_DIR}/gtirb/version.py @ONLY\n)\n\nif(GTIRB_ENABLE_TESTS)\n  find_program(TOX tox)\n  if(TOX)\n    if(ENABLE_MYPY)\n      # Only run mypy if we actually generated stubs for the protobuf\n      # definitions.\n      add_test(\n        NAME mypy\n        COMMAND tox run -e mypy\n        WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}/\"\n      )\n    endif()\n\n    if(ENABLE_CODE_COVERAGE)\n      set(GTIRB_TOX_FLAGS)\n    else()\n      set(GTIRB_TOX_FLAGS \"--\")\n    endif()\n    execute_process(\n      COMMAND ${TOX} -l\n      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}\n      OUTPUT_VARIABLE TOX_ENVIRONMENTS\n    )\n    string(REGEX MATCHALL \"py3[0-9a-z-]*\" TOX_ENVIRONMENTS ${TOX_ENVIRONMENTS})\n    foreach(TOX_ENVIRONMENT ${TOX_ENVIRONMENTS})\n      add_test(\n        NAME ${TOX_ENVIRONMENT}\n        COMMAND ${TOX} run -e ${TOX_ENVIRONMENT} ${GTIRB_TOX_FLAGS}\n        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}\n      )\n    endforeach()\n  else()\n    message(SEND_ERROR \"Python tests require tox to be installed\")\n  endif()\nendif()\n\n# Convenience targets for installing python\nadd_custom_target(\n  python-wheel\n  DEPENDS pygtirb\n  COMMAND \"${PYTHON}\" -m pip wheel --no-deps \"${CMAKE_CURRENT_BINARY_DIR}\"\n)\n"
  },
  {
    "path": "python/README.md",
    "content": "Python library for GTIRB.\n"
  },
  {
    "path": "python/gtirb/__init__.py",
    "content": "__all__ = [\n    \"AuxData\",\n    \"AuxDataContainer\",\n    \"Block\",\n    \"ByteBlock\",\n    \"ByteInterval\",\n    \"CFG\",\n    \"CfgNode\",\n    \"CodeBlock\",\n    \"DataBlock\",\n    \"Edge\",\n    \"EdgeLabel\",\n    \"EdgeType\",\n    \"IR\",\n    \"Module\",\n    \"Node\",\n    \"Offset\",\n    \"ProxyBlock\",\n    \"Section\",\n    \"Serialization\",\n    \"Symbol\",\n    \"SymbolicExpression\",\n    \"SymAddrAddr\",\n    \"SymAddrConst\",\n    \"Variant\",\n]\n\nfrom .auxdata import AuxData, AuxDataContainer\nfrom .block import Block, ByteBlock, CfgNode, CodeBlock, DataBlock, ProxyBlock\nfrom .byteinterval import ByteInterval\nfrom .cfg import CFG, Edge, EdgeLabel, EdgeType\nfrom .ir import IR\nfrom .module import Module\nfrom .node import Node\nfrom .offset import Offset\nfrom .section import Section\nfrom .serialization import Serialization, Variant\nfrom .symbol import Symbol\nfrom .symbolicexpression import SymAddrAddr, SymAddrConst, SymbolicExpression\nfrom .version import API_VERSION\n\n__version__ = API_VERSION\n"
  },
  {
    "path": "python/gtirb/auxdata.py",
    "content": "from io import BytesIO\nfrom typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, Optional\nfrom uuid import UUID\n\nfrom google.protobuf.internal.containers import MessageMap\n\nfrom .node import Node\nfrom .proto import AuxData_pb2\nfrom .serialization import Serialization\nfrom .util import DictLike\n\nif TYPE_CHECKING:  # pragma: no cover\n    # Ignore flake8 \"imported but unused\" errors.\n    from .ir import IR  # noqa: F401\n\n\nclass _LazyDataContainer:\n    \"\"\"\n    Container that holds the raw byte stream until it is read, then releases\n    it. If it is never read, then serialization skips re-encoding (and\n    deserializing) the data.\n    \"\"\"\n\n    def __init__(\n        self,\n        raw_data: bytes,\n        type_name: str,\n        get_by_uuid: Callable[[UUID], Optional[Node]],\n    ):\n        self.raw_data: Optional[bytes] = raw_data\n        self.type_name = type_name\n        self.get_by_uuid = get_by_uuid\n\n    def get_data(self) -> object:\n        \"\"\"\n        Get any pending still-serialized data, or return the passed data\n        instead (the default).\n        \"\"\"\n        assert self.raw_data is not None\n        rv = AuxData.serializer.decode(\n            self.raw_data, self.type_name, self.get_by_uuid\n        )\n        self.raw_data = None\n        return rv\n\n    def get_raw_data(self) -> bytes:\n        \"\"\" \"\"\"\n        assert self.raw_data is not None\n        return self.raw_data\n\n\nclass AuxData:\n    \"\"\"AuxData objects can be attached to the :class:`gtirb.IR` or individual\n    :class:`gtirb.Module` s to store additional client-specific data in a\n    portable way.\n\n    AuxData represents a portable, language-independent manner of encoding\n    rich data. To do this, all data is stored on disk as a series of bytes\n    with a string describing the format of the data, called a *type name*. See\n    :mod:`gtirb.serialization` for the list of all default types. Types may\n    also be parameterized; for example, ``mapping<string,UUID>`` is a ``dict``\n    from ``str`` objects to ``UUID`` objects. All ``AuxData`` requires\n    a valid type name in order to be serialized.\n\n    :ivar ~.data: The value stored in this AuxData.\n    :ivar ~.type_name: A string describing the type of ``data``.\n        Used to determine the proper codec for serializing this AuxData.\n    \"\"\"\n\n    serializer: ClassVar[Serialization] = Serialization()\n    \"\"\"This is a :class:`gtirb.Serialization` instance, used to\n    encode and decode ``data`` fields of all ``AuxData``. See\n    :mod:`gtirb.serialization` for details.\n    \"\"\"\n\n    def __init__(\n        self,\n        data: object,\n        type_name: str,\n        lazy_container: Optional[_LazyDataContainer] = None,\n    ):\n        \"\"\"\n        :param data: The value stored in this AuxData.\n        :param type_name: A string describing the type of ``data``.\n            Used to determine the proper codec for serializing this AuxData.\n        :param lazy_container: An object that will lazily deserialize the\n            auxdata table backing this object, or None.\n        \"\"\"\n        self._lazy_container = lazy_container\n        # _data has type Any to avoid disrupting clients want to type check\n        # their use of gtirb. If _data had type object, they would have to\n        # verify the element types of potentially large containers, or else\n        # just subvert the type system by casting anyway.\n        self._data: Any = data  # type: ignore[misc]\n        self.type_name = type_name\n\n    @property\n    def data(self) -> Any:  # type: ignore[misc]\n        if self._lazy_container is not None:\n            self._data = self._lazy_container.get_data()\n            self._lazy_container = None\n        return self._data\n\n    @data.setter\n    def data(self, value: object) -> None:\n        self._data = value\n        self._lazy_container = None\n\n    @classmethod\n    def _from_protobuf(\n        cls,\n        aux_data: AuxData_pb2.AuxData,\n        ir: Optional[\"IR\"],\n    ) -> \"AuxData\":\n        \"\"\"Deserialize AuxData from Protobuf. Lazy, will not perform\n        deserialization until .data is accessed.\n\n        :param aux_data: The Protobuf AuxData object.\n        \"\"\"\n\n        # Defer deserialization until someone accesses .data\n        assert ir\n        lazy_container = _LazyDataContainer(\n            aux_data.data, aux_data.type_name, ir.get_by_uuid\n        )\n        return cls(\n            data=None,\n            type_name=aux_data.type_name,\n            lazy_container=lazy_container,\n        )\n\n    def _to_protobuf(self) -> AuxData_pb2.AuxData:\n        \"\"\"Get a Protobuf representation of the AuxData.\"\"\"\n\n        proto_auxdata = AuxData_pb2.AuxData()\n        proto_auxdata.type_name = self.type_name\n        # If we are serializing the same data, and the way that data is encoded\n        # has not changed, then just use the already serialized copy.\n        if self._lazy_container is not None and (\n            self.type_name == self._lazy_container.type_name\n        ):\n            proto_auxdata.data = self._lazy_container.get_raw_data()\n        else:\n            data_stream = BytesIO()\n            AuxData.serializer.encode(data_stream, self.data, self.type_name)\n            proto_auxdata.data = data_stream.getvalue()\n        return proto_auxdata\n\n    def __repr__(self) -> str:\n        return (\n            \"AuxData(\"\n            \"type_name={type_name!r}, \"\n            \"data={data!r}, \"\n            \")\".format(type_name=self.type_name, data=self.data)\n        )\n\n\nclass AuxDataContainer(Node):\n    \"\"\"The base class for anything that holds AuxData tables; that is,\n    :class:`gtirb.IR` and :class:`gtirb.Module`.\n\n    :ivar ~.aux_data: The auxiliary data associated\n            with the object, as a mapping from names to\n            :class:`gtirb.AuxData`.\n    \"\"\"\n\n    def __init__(\n        self,\n        aux_data: DictLike[str, AuxData] = {},\n        uuid: Optional[UUID] = None,\n    ):\n        \"\"\"\n        :param aux_data: The initial auxiliary data to be associated\n            with the object, as a mapping from names to\n            :class:`gtirb.AuxData`. Defaults to an empty :class:`dict`.\n        :param uuid: the UUID of this ``AuxDataContainer``,\n            or None if a new UUID needs generated via :func:`uuid.uuid4`.\n            Defaults to None.\n        \"\"\"\n        super().__init__(uuid)\n        self.aux_data: Dict[str, AuxData] = dict(aux_data)\n\n    @classmethod\n    def _read_protobuf_aux_data(\n        cls,\n        proto_container: \"MessageMap[str, AuxData_pb2.AuxData]\",\n        ir: Optional[\"IR\"],\n    ) -> Dict[str, AuxData]:\n        \"\"\"\n        Instead of the overrided _decode_protobuf, this method requires the\n        Protobuf message to read from. AuxDataContainers need to call this\n        method in their own _decode_protobuf overrides.\n\n        :param proto_container: A Protobuf message with a field called\n            ``aux_data``.\n        \"\"\"\n        return {\n            key: AuxData._from_protobuf(val, ir)\n            for key, val in proto_container.items()\n        }\n\n    def _write_protobuf_aux_data(\n        self, proto_container: \"MessageMap[str, AuxData_pb2.AuxData]\"\n    ) -> None:\n        \"\"\"\n        Instead of the overrided _to_protobuf, this method requires the\n        Protobuf message to write into. AuxDataContainers need to call this\n        method in their own _to_protobuf overrides.\n\n        :param proto_container: A Protobuf message with a field called\n            ``aux_data``.\n        \"\"\"\n        for k, v in self.aux_data.items():\n            proto_container[k].CopyFrom(v._to_protobuf())\n\n    def deep_eq(self, other: object) -> bool:\n        \"\"\"This overrides :func:`gtirb.Node.deep_eq` to check for\n        AuxData equality.\n\n        Because the values stored by AuxData are not necessarily\n        amenable to deep checking, the auxiliary data dictionaries\n        stored for ``self`` and ``other`` are not deeply checked. Instead,\n        they are considered to be equal if their sets of keys are equal.\n        \"\"\"\n\n        if not isinstance(other, AuxDataContainer):\n            return False\n        if (\n            self.uuid != other.uuid\n            or self.aux_data.keys() != other.aux_data.keys()\n        ):\n            return False\n        return True\n"
  },
  {
    "path": "python/gtirb/block.py",
    "content": "import typing\nfrom enum import Enum\nfrom uuid import UUID\n\nfrom .node import Node, _NodeMessage\nfrom .proto import CodeBlock_pb2, DataBlock_pb2, ProxyBlock_pb2\nfrom .util import _IndexedAttribute\n\nif typing.TYPE_CHECKING:  # pragma: no cover\n    # Ignore flake8 \"imported but unused\" errors.\n    from .byteinterval import ByteInterval  # noqa: F401\n    from .cfg import Edge  # noqa: F401\n    from .ir import IR  # noqa: F401\n    from .module import Module  # noqa: F401\n    from .section import Section  # noqa: F401\n    from .symbol import Symbol  # noqa: F401\n\n\nclass Block(Node):\n    \"\"\"The base class for blocks. Symbols may have references to any subclass\n    of Block.\n    \"\"\"\n\n    @property\n    def module(self) -> typing.Optional[\"Module\"]:\n        \"\"\"Get the module this node ultimately belongs to.\"\"\"\n\n        raise NotImplementedError  # pragma: no cover\n\n    @property\n    def references(self) -> typing.Iterator[\"Symbol\"]:\n        \"\"\"Get all the symbols that refer to this block.\"\"\"\n\n        if not self.module:\n            return\n\n        symbol_set = self.module._symbol_referent_index.get(self)\n        if symbol_set:\n            yield from symbol_set\n\n    def _add_to_uuid_cache(self, cache: typing.Dict[UUID, Node]) -> None:\n        \"\"\"Update the UUID cache when this node is added.\"\"\"\n\n        cache[self.uuid] = self\n\n    def _remove_from_uuid_cache(self, cache: typing.Dict[UUID, Node]) -> None:\n        \"\"\"Update the UUID cache when this node is removed.\"\"\"\n\n        del cache[self.uuid]\n\n\nclass ByteBlock(Block):\n    \"\"\"The base class for blocks that belong to a :class:`ByteInterval` and\n    store their bytes there.\n\n    :ivar ~.size: The size of the block in bytes.\n    :ivar ~.offset: The offset from the beginning of the byte interval to which\n        this block belongs. Multiple blocks in the same interval may have the\n        same offset.\n    \"\"\"\n\n    size = _IndexedAttribute[int]()(lambda self: self.byte_interval)\n    offset = _IndexedAttribute[int]()(lambda self: self.byte_interval)\n\n    def __init__(\n        self,\n        *,\n        size: int = 0,\n        offset: int = 0,\n        uuid: typing.Optional[UUID] = None,\n        byte_interval: typing.Optional[\"ByteInterval\"] = None,\n    ):\n        \"\"\"\n        :param size: The size of the data object in bytes.\n        :param offset: The offset from the beginning of the byte interval to\n            which this block belongs.\n        :param uuid: The UUID of this ``ByteBlock``,\n            or None if a new UUID needs generated via :func:`uuid.uuid4`.\n            Defaults to None.\n        :param byte_interval: The :class:`ByteInterval` this block belongs to.\n        \"\"\"\n\n        super().__init__(uuid=uuid)\n        self._byte_interval: typing.Optional[\"ByteInterval\"] = None\n        self.size = size\n        self.offset = offset\n        # Use the property setter to ensure correct invariants.\n        self.byte_interval = byte_interval\n\n    @property\n    def byte_interval(self) -> typing.Optional[\"ByteInterval\"]:\n        \"\"\"The :class:`ByteInterval` this block belongs to.\"\"\"\n\n        return self._byte_interval\n\n    @byte_interval.setter\n    def byte_interval(self, value: typing.Optional[\"ByteInterval\"]) -> None:\n        if self._byte_interval is not None:\n            self._byte_interval.blocks.discard(self)\n        if value is not None:\n            value.blocks.add(self)\n\n    def deep_eq(self, other: object) -> bool:\n        # Do not move __eq__. See docstring for Node.deep_eq for more info.\n        if not isinstance(other, ByteBlock):\n            return False\n        return (\n            self.offset == other.offset\n            and self.uuid == other.uuid\n            and self.size == other.size\n        )\n\n    @property\n    def contents(self) -> bytes:\n        \"\"\"Get the bytes in this block.\"\"\"\n\n        if self.byte_interval is None:\n            return b\"\"\n        return self.byte_interval.contents[\n            self.offset : self.offset + self.size\n        ]\n\n    @property\n    def address(self) -> typing.Optional[int]:\n        \"\"\"Get the address of this block, or None if not present.\"\"\"\n\n        if self.byte_interval is None or self.byte_interval.address is None:\n            return None\n        return self.byte_interval.address + self.offset\n\n    @property\n    def section(self) -> typing.Optional[\"Section\"]:\n        \"\"\"Get the section this node ultimately belongs to.\"\"\"\n        byte_interval = self.byte_interval\n        if byte_interval is None:\n            return None\n        return byte_interval.section\n\n    @property\n    def module(self) -> typing.Optional[\"Module\"]:\n        \"\"\"Get the module this node ultimately belongs to.\"\"\"\n        section = self.section\n        if section is None:\n            return None\n        return section.module\n\n    @property\n    def ir(self) -> typing.Optional[\"IR\"]:\n        \"\"\"Get the IR this node ultimately belongs to.\"\"\"\n        module = self.module\n        if module is None:\n            return None\n        return module.ir\n\n    def contains_offset(self, offset: int) -> bool:\n        \"\"\"Indicate if the provided offset is within this block.\"\"\"\n        return self.offset <= offset < (self.offset + self.size)\n\n    def contains_address(self, address: int) -> bool:\n        \"\"\"Indicate if the provided address is within this block.\n        Returns False if the block has no address.\n        \"\"\"\n        byte_interval = self.byte_interval\n        if byte_interval is not None:\n            base = byte_interval.address\n            if base is not None:\n                return self.contains_offset(address - base)\n        return False\n\n\nclass CfgNode(Block):\n    \"\"\"The base class for blocks that may appear as vertices in the CFG.\"\"\"\n\n    @property\n    def incoming_edges(self) -> typing.Iterable[\"Edge\"]:\n        \"\"\"Get the edges that point to this CFG node.\"\"\"\n\n        raise NotImplementedError  # pragma: no cover\n\n    @property\n    def outgoing_edges(self) -> typing.Iterable[\"Edge\"]:\n        \"\"\"Get the edges that start at this CFG node.\"\"\"\n\n        raise NotImplementedError  # pragma: no cover\n\n\nclass DataBlock(ByteBlock):\n    \"\"\"Represents a data object, possibly symbolic.\"\"\"\n\n    def __init__(\n        self,\n        *,\n        size: int = 0,\n        offset: int = 0,\n        uuid: typing.Optional[UUID] = None,\n        byte_interval: typing.Optional[\"ByteInterval\"] = None,\n    ):\n        \"\"\"\n        :param size: The size of the data object in bytes.\n        :param offset: The offset from the beginning of the byte interval to\n            which this block belongs.\n        :param uuid: The UUID of this ``DataBlock``,\n            or None if a new UUID needs generated via :func:`uuid.uuid4`.\n            Defaults to None.\n        :param byte_interval: The :class:`ByteInterval` this block belongs to.\n        \"\"\"\n\n        super().__init__(\n            size=size, offset=offset, uuid=uuid, byte_interval=byte_interval\n        )\n\n    @classmethod\n    def _decode_protobuf(\n        cls,\n        proto_dataobject: _NodeMessage,\n        uuid: UUID,\n        ir: typing.Optional[\"IR\"],\n    ) -> \"DataBlock\":\n        assert ir\n        assert isinstance(proto_dataobject, DataBlock_pb2.DataBlock)\n        b = cls(size=proto_dataobject.size, uuid=uuid)\n        b._add_to_uuid_cache(ir._local_uuid_cache)\n        return b\n\n    def _to_protobuf(self) -> DataBlock_pb2.DataBlock:\n        proto_dataobject = DataBlock_pb2.DataBlock()\n        proto_dataobject.uuid = self.uuid.bytes\n        proto_dataobject.size = self.size\n        return proto_dataobject\n\n    def __repr__(self) -> str:\n        return (\n            \"DataBlock(\"\n            \"uuid={uuid!r}, \"\n            \"size={size}, \"\n            \"offset={offset}, \"\n            \")\".format(uuid=self.uuid, size=self.size, offset=self.offset)\n        )\n\n\nclass CodeBlock(ByteBlock, CfgNode):\n    \"\"\"A basic block in the binary.\n\n    Does not directly store data bytes, which are kept in a\n    :class:`ByteInterval`.\n\n    :ivar ~.decode_mode: The decode mode of the block,\n        used in some ISAs to differentiate between sub-ISAs\n        (e.g. differentiating blocks written in ARM and Thumb).\n    \"\"\"\n\n    class DecodeMode(Enum):\n        \"\"\"Variations on decoding a particular ISA\"\"\"\n\n        Default = CodeBlock_pb2.DecodeMode.Value(\"All_Default\")\n        \"\"\"Default decode mode for all ISAs\"\"\"\n\n        Thumb = CodeBlock_pb2.DecodeMode.Value(\"ARM_Thumb\")\n        \"\"\"Thumb decode mode for ARM32\"\"\"\n\n    def __init__(\n        self,\n        *,\n        decode_mode: DecodeMode = DecodeMode.Default,\n        size: int = 0,\n        offset: int = 0,\n        uuid: typing.Optional[UUID] = None,\n        byte_interval: typing.Optional[\"ByteInterval\"] = None,\n    ):\n        \"\"\"\n        :param size: The length of the block in bytes.\n        :param decode_mode: The decode mode of the block,\n            used in some ISAs to differentiate between sub-ISAs\n            (e.g. differentiating blocks written in ARM and Thumb).\n            Defaults to DecodeMode.Default.\n        :param offset: The offset from the beginning of the byte interval to\n            which this block belongs.\n        :param uuid: The UUID of this ``CodeBlock``,\n            or None if a new UUID needs generated via :func:`uuid.uuid4`.\n            Defaults to None.\n        :param byte_interval: The :class:`ByteInterval` this block belongs to.\n        \"\"\"\n\n        super().__init__(\n            size=size, offset=offset, uuid=uuid, byte_interval=byte_interval\n        )\n        self.decode_mode = decode_mode  # type: CodeBlock.DecodeMode\n\n    @classmethod\n    def _decode_protobuf(\n        cls,\n        proto_block: _NodeMessage,\n        uuid: UUID,\n        ir: typing.Optional[\"IR\"],\n    ) -> \"CodeBlock\":\n        assert ir\n        assert isinstance(proto_block, CodeBlock_pb2.CodeBlock)\n        b = cls(\n            decode_mode=cls.DecodeMode(proto_block.decode_mode),\n            size=proto_block.size,\n            uuid=uuid,\n        )\n        b._add_to_uuid_cache(ir._local_uuid_cache)\n        return b\n\n    def _to_protobuf(self) -> CodeBlock_pb2.CodeBlock:\n        proto_block = CodeBlock_pb2.CodeBlock()\n        proto_block.uuid = self.uuid.bytes\n        proto_block.size = self.size\n        proto_block.decode_mode = self.decode_mode.value\n        return proto_block\n\n    def deep_eq(self, other: object) -> bool:\n        # Do not move __eq__. See docstring for Node.deep_eq for more info.\n        if not isinstance(other, CodeBlock):\n            return False\n        return super().deep_eq(other) and self.decode_mode == other.decode_mode\n\n    def __repr__(self) -> str:\n        return (\n            \"CodeBlock(\"\n            \"uuid={uuid!r}, \"\n            \"size={size}, \"\n            \"offset={offset}, \"\n            \"decode_mode=CodeBlock.{decode_mode!s}, \"\n            \")\".format(\n                uuid=self.uuid,\n                size=self.size,\n                offset=self.offset,\n                decode_mode=self.decode_mode,\n            )\n        )\n\n    @property\n    def incoming_edges(self) -> typing.Iterator[\"Edge\"]:\n        ir = self.ir\n        if ir is None:\n            return iter(())\n        return ir.cfg.in_edges(self)\n\n    @property\n    def outgoing_edges(self) -> typing.Iterator[\"Edge\"]:\n        ir = self.ir\n        if ir is None:\n            return iter(())\n        return ir.cfg.out_edges(self)\n\n\nclass ProxyBlock(CfgNode):\n    \"\"\"A placeholder that serves as the endpoint (source or target) of a\n    :class:`gtirb.Edge`.\n\n    ProxyBlock objects allow the construction of CFG edges to or from\n    another node. For example, a call to a function in another module\n    may be represented by a :class:`gtirb.Edge` that originates at the\n    calling :class:`gtirb.CodeBlock` and targets a ProxyBlock. Another\n    example would be a :class:`gtirb.Edge` that represents an indirect\n    jump whose target is not known.\n\n    A ProxyBlock does not represent any instructions and so has neither\n    an address nor a size.\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        uuid: typing.Optional[UUID] = None,\n        module: typing.Optional[\"Module\"] = None,\n    ):\n        super().__init__(uuid=uuid)\n        self._module: typing.Optional[\"Module\"] = None\n        # Use the property setter to ensure correct invariants.\n        self.module = module\n\n    @classmethod\n    def _decode_protobuf(\n        cls,\n        proto_proxy: _NodeMessage,\n        uuid: UUID,\n        ir: typing.Optional[\"IR\"],\n    ) -> \"ProxyBlock\":\n        assert ir\n        assert isinstance(proto_proxy, ProxyBlock_pb2.ProxyBlock)\n        b = cls(uuid=uuid)\n        b._add_to_uuid_cache(ir._local_uuid_cache)\n        return b\n\n    def _to_protobuf(self) -> ProxyBlock_pb2.ProxyBlock:\n        proto_proxyblock = ProxyBlock_pb2.ProxyBlock()\n        proto_proxyblock.uuid = self.uuid.bytes\n        return proto_proxyblock\n\n    def deep_eq(self, other: object) -> bool:\n        # Do not move __eq__. See docstring for Node.deep_eq for more info.\n        if not isinstance(other, ProxyBlock):\n            return False\n        return self.uuid == other.uuid\n\n    def __repr__(self) -> str:\n        return \"ProxyBlock(\" \"uuid={uuid!r}, \" \")\".format(**self.__dict__)\n\n    @property\n    def module(self) -> typing.Optional[\"Module\"]:\n        return self._module\n\n    @module.setter\n    def module(self, value: typing.Optional[\"Module\"]) -> None:\n        if self._module is not None:\n            self._module.proxies.discard(self)\n        if value is not None:\n            value.proxies.add(self)\n\n    @property\n    def incoming_edges(self) -> typing.Iterator[\"Edge\"]:\n        ir = self.ir\n        if ir is None:\n            return iter(())\n        return ir.cfg.in_edges(self)\n\n    @property\n    def outgoing_edges(self) -> typing.Iterator[\"Edge\"]:\n        ir = self.ir\n        if ir is None:\n            return iter(())\n        return ir.cfg.out_edges(self)\n\n    @property\n    def ir(self) -> typing.Optional[\"IR\"]:\n        \"\"\"Get the IR this node ultimately belongs to.\"\"\"\n        module = self.module\n        if module is None:\n            return None\n        return module.ir\n"
  },
  {
    "path": "python/gtirb/byteinterval.py",
    "content": "import typing\nfrom uuid import UUID\n\nfrom sortedcontainers import SortedDict\n\nfrom .block import ByteBlock, CodeBlock, DataBlock\nfrom .lazyintervaltree import LazyIntervalTree\nfrom .node import Node, _NodeMessage\nfrom .proto import ByteInterval_pb2, SymbolicExpression_pb2\nfrom .symbolicexpression import SymAddrAddr, SymAddrConst, SymbolicExpression\nfrom .util import (\n    DictLike,\n    DictWrapper,\n    SetWrapper,\n    _IndexedAttribute,\n    _nodes_at_interval_tree,\n    _nodes_at_interval_tree_offset,\n    _nodes_on_interval_tree,\n    _nodes_on_interval_tree_offset,\n    _offset_interval,\n    get_desired_range,\n)\n\nif typing.TYPE_CHECKING:  # pragma: no cover\n    # Ignore flake8 \"imported but unused\" errors.\n    from .ir import IR  # noqa: F401\n    from .module import Module  # noqa: F401\n    from .section import Section  # noqa: F401\n\n\nSymbolicExpressionElement = typing.Tuple[\n    \"ByteInterval\", int, SymbolicExpression\n]\n\n\nclass ByteInterval(Node):\n    \"\"\"A contiguous region of bytes in a binary.\n\n    A ByteInterval defines a relative ordering for a group of\n    :class:`ByteBlock`\\\\s, optionally at a fixed address in memory. It also\n    stores the bytes associated with these blocks.\n\n    If two blocks are in two different ByteIntervals, then it should be\n    considered safe (that is, preserving of program semantics) to move one\n    block relative to the other in memory. If two blocks are in the same\n    ByteInterval, then it should be considered unknown if moving the two blocks\n    relative to one another in memory is a safe operation.\n\n    :ivar ~.address: The fixed address of this interval, if present. If this\n        field is present, it may indicate the original address at which this\n        interval was located at in memory, or it may indicate that this block's\n        address is fixed and must not be changed. If this field is not present,\n        it indicates that the interval is free to be moved around in memory\n        while preserving program semantics.\n    :ivar ~.size: The size of this interval in bytes. If this number is greater\n        than ``initialized_size``, this indicates that the high addresses taken\n        up by this interval consist of uninitialized bytes. This often occurs\n        in BSS sections, where data is zero-initialized rather than stored as\n        zeroes in the binary.\n    :ivar ~.contents: The bytes stored in this interval.\n    :ivar ~.blocks: A set of all :class:`ByteBlock`\\\\s in this interval.\n    :ivar ~.symbolic_expressions: A mapping, from offset in the interval, to a\n        :class:`SymbolicExpression` in the interval.\n    \"\"\"\n\n    class _BlockSet(SetWrapper[ByteBlock]):\n        def __init__(\n            self, node: \"ByteInterval\", *args: typing.Iterable[ByteBlock]\n        ):\n            super().__init__()\n            self._node = node\n            self.update(*args)\n\n        def add(self, v: ByteBlock) -> None:\n            # We're defining add in terms of update so that we can optimize\n            # adding multiple blocks at once.\n            self.update((v,))\n\n        def update(self, *iterables: typing.Iterable[ByteBlock]) -> None:\n            node_ir = self._node.ir\n            new_items = set(*iterables) - self._data\n            for v in new_items:\n                if v._byte_interval is not None:\n                    v._byte_interval.blocks.discard(v)\n                v._byte_interval = self._node\n                if node_ir is not None:\n                    v._add_to_uuid_cache(node_ir._local_uuid_cache)\n\n            self._node._index_add_multiple(self._data, new_items)\n            self._data.update(new_items)\n\n        def discard(self, v: ByteBlock) -> None:\n            if v not in self:\n                return\n            self._node._index_discard(v)\n            v._byte_interval = None\n            if self._node.ir is not None:\n                v._remove_from_uuid_cache(self._node.ir._local_uuid_cache)\n            return super().discard(v)\n\n    class _SymbolicExprDict(DictWrapper[int, SymbolicExpression]):\n        def __init__(\n            self,\n            interval: \"ByteInterval\",\n            *args: DictLike[int, SymbolicExpression],\n        ):\n            # Do not call the DictWrapper constructor: _SymbolicExprDict needs\n            # to store data in a SortedDict, not a regular dict.\n            self._interval = interval\n            self._data: \"SortedDict[int, SymbolicExpression]\" = SortedDict()\n            temp: typing.Dict[int, SymbolicExpression] = dict(*args)\n            for i, v in temp.items():\n                self[i] = v\n\n        def __repr__(self) -> str:\n            # We can't just return the repr of self._data because it will\n            # create a SortedDict and that isn't part of our public interface.\n            items = (\n                \"{!r}: {!r}\".format(key, value)\n                for key, value in self._data.items()\n            )\n            return \"{\" + \", \".join(items) + \"}\"\n\n    address = _IndexedAttribute[typing.Optional[int]]()(\n        lambda self: self.section\n    )\n    size = _IndexedAttribute[int]()(lambda self: self.section)\n\n    def __init__(\n        self,\n        *,\n        address: typing.Optional[int] = None,\n        size: typing.Optional[int] = None,\n        initialized_size: typing.Optional[int] = None,\n        contents: typing.ByteString = b\"\",\n        blocks: typing.Iterable[ByteBlock] = (),\n        symbolic_expressions: DictLike[int, SymbolicExpression] = {},\n        uuid: typing.Optional[UUID] = None,\n        section: typing.Optional[\"Section\"] = None,\n    ):\n        \"\"\"\n        :param address: The fixed address of this interval, if present.\n        :param size: The size of this interval in bytes.\n        :param initialized_size: The number of initialized bytes in this\n            interval.\n        :param contents: The bytes stored in this interval.\n        :param blocks: A set of all :class:`ByteBlock`\\\\s in this interval.\n        :param symbolic_expressions: A mapping, from offset in the interval, to\n            a :class:`SymbolicExpression` in the interval.\n        :param uuid: The UUID of this ``ByteInterval``,\n            or None if a new UUID needs generated via :func:`uuid.uuid4`.\n            Defaults to None.\n        :param section: The :class:`Section` this interval belongs to.\n        \"\"\"\n\n        if size is None:\n            size = len(contents)\n        if initialized_size is None:\n            initialized_size = len(contents)\n        if initialized_size > size:\n            raise ValueError(\"initialized_size must be <= size!\")\n\n        super().__init__(uuid=uuid)\n        self._section: typing.Optional[\"Section\"] = None\n        self.address = address\n        self.size = size\n        self.contents = bytearray(contents)\n        self.initialized_size = initialized_size\n\n        # Both blocks and _interval_tree must exist before adding any blocks.\n        self.blocks: SetWrapper[ByteBlock] = ByteInterval._BlockSet(self)\n        self._interval_tree = LazyIntervalTree[int, ByteBlock](\n            self.blocks, _offset_interval\n        )\n        self.blocks.update(blocks)\n\n        self._symbolic_expressions = ByteInterval._SymbolicExprDict(\n            self, symbolic_expressions\n        )\n        self._proto_interval: typing.Optional[\n            ByteInterval_pb2.ByteInterval\n        ] = None\n\n        # Use the property setter to ensure correct invariants.\n        self.section = section\n\n    def _index_add_multiple(\n        self,\n        old_blocks: typing.Collection[ByteBlock],\n        new_blocks: typing.Collection[ByteBlock],\n    ) -> None:\n        for block in new_blocks:\n            self._interval_tree.add(block)\n\n    def _index_add(self, block: ByteBlock) -> None:\n        self._interval_tree.add(block)\n\n    def _index_discard(self, block: ByteBlock) -> None:\n        self._interval_tree.discard(block)\n\n    @property\n    def initialized_size(self) -> int:\n        \"\"\"The number of initialized bytes in this interval.\n\n        Not all bytes in this interval may correspond to bytes physically\n        stored in the underlying file format. This can occur, for example, in\n        BSS sections, which are zero-initialized at loadtime, but these zeroes\n        are not stored in the file itself. If this number is smaller than\n        ``size``, this indicates that any bytes past this number are\n        unitialized bytes with values determined at loadtime. As such, all\n        bytes past this number in this interval's byte vector are truncated\n        when saving to file.\n        \"\"\"\n\n        return len(self.contents)\n\n    @initialized_size.setter\n    def initialized_size(self, value: int) -> None:\n        if value > len(self.contents):\n            self.contents += b\"\\0\" * (value - len(self.contents))\n        elif value < len(self.contents):\n            self.contents = self.contents[:value]\n\n    @classmethod\n    def _decode_protobuf(\n        cls,\n        proto_interval: _NodeMessage,\n        uuid: UUID,\n        ir: typing.Optional[\"IR\"],\n    ) -> \"ByteInterval\":\n        assert ir\n        assert isinstance(proto_interval, ByteInterval_pb2.ByteInterval)\n\n        def decode_block(proto_block: ByteInterval_pb2.Block) -> ByteBlock:\n            block: ByteBlock\n            if proto_block.HasField(\"code\"):\n                block = CodeBlock._from_protobuf(proto_block.code, ir)\n            elif proto_block.HasField(\"data\"):\n                block = DataBlock._from_protobuf(proto_block.data, ir)\n            else:\n                raise TypeError(\n                    \"Unknown type inside proto block: %s\"\n                    % proto_block.WhichOneof(\"value\")\n                )\n\n            block.offset = proto_block.offset\n            return block\n\n        # we do not decode symbolic expressions yet, because symbols have\n        # not yet been decoded at this point.\n        result = cls(\n            address=proto_interval.address\n            if proto_interval.has_address\n            else None,\n            size=proto_interval.size,\n            contents=proto_interval.contents,\n            uuid=uuid,\n            blocks=(decode_block(b) for b in proto_interval.blocks),\n        )\n        result._add_to_uuid_cache(ir._local_uuid_cache)\n        # We store the interval and IR here so we can use it later, when\n        # _decode_symbolic_expressions is called.\n        result._proto_interval = proto_interval\n        # Return the new BI.\n        return result\n\n    def _decode_symbolic_expressions(self, ir: \"IR\") -> None:\n        \"\"\"Called by modules after symbols are decoded, but before the module\n        is done decoding.\n        \"\"\"\n        assert self._proto_interval\n\n        def decode_symbolic_expression(\n            proto_expr: SymbolicExpression_pb2.SymbolicExpression,\n        ) -> SymbolicExpression:\n            if proto_expr.HasField(\"addr_const\"):\n                return SymAddrConst._from_protobuf(\n                    proto_expr.addr_const, ir.get_by_uuid\n                )\n            elif proto_expr.HasField(\"addr_addr\"):\n                return SymAddrAddr._from_protobuf(\n                    proto_expr.addr_addr, ir.get_by_uuid\n                )\n            else:\n                raise TypeError(\n                    \"Unknown type inside proto sym expr: %s\"\n                    % proto_expr.WhichOneof(\"value\")\n                )\n\n        self.symbolic_expressions = {}\n        for i, v in self._proto_interval.symbolic_expressions.items():\n            expr = decode_symbolic_expression(v)\n            for f in v.attribute_flags:\n                try:\n                    expr.attributes.add(SymbolicExpression.Attribute(f))\n                except ValueError:\n                    expr.attributes.add(f)\n            self.symbolic_expressions[i] = expr\n\n        del self._proto_interval\n\n    def _to_protobuf(self) -> ByteInterval_pb2.ByteInterval:\n        proto_interval = ByteInterval_pb2.ByteInterval()\n\n        proto_interval.uuid = self.uuid.bytes\n        if self.address is None:\n            proto_interval.has_address = False\n        else:\n            proto_interval.has_address = True\n            proto_interval.address = self.address\n        proto_interval.size = self.size\n        proto_interval.contents = bytes(self.contents)\n\n        # Cannot insert blocks using proto_interval.blocks.append() in a loop\n        # because append() isn't supported in older versions of protobuf. Use a\n        # comprehension and extend() instead.\n\n        def to_proto_block(block: ByteBlock) -> ByteInterval_pb2.Block:\n            proto_block = ByteInterval_pb2.Block()\n            proto_block.offset = block.offset\n            if isinstance(block, CodeBlock):\n                proto_block.code.CopyFrom(block._to_protobuf())\n            elif isinstance(block, DataBlock):\n                proto_block.data.CopyFrom(block._to_protobuf())\n            else:\n                raise TypeError(\n                    \"Unknown block type in interval: %s\" % type(block)\n                )\n            return proto_block\n\n        proto_interval.blocks.extend(to_proto_block(b) for b in self.blocks)\n\n        for k, v in self.symbolic_expressions.items():\n            sym_exp = SymbolicExpression_pb2.SymbolicExpression()\n            if isinstance(v, SymAddrConst):\n                sym_exp.addr_const.CopyFrom(v._to_protobuf())\n            elif isinstance(v, SymAddrAddr):\n                sym_exp.addr_addr.CopyFrom(v._to_protobuf())\n            else:\n                raise ValueError(\n                    \"Expected sym expr type in interval: %s\" % type(v)\n                )\n            attrs = (\n                a.value if isinstance(a, SymbolicExpression.Attribute) else a\n                for a in v.attributes\n            )\n            sym_exp.attribute_flags.extend(attrs)\n            proto_interval.symbolic_expressions[k].CopyFrom(sym_exp)\n\n        return proto_interval\n\n    @property\n    def section(self) -> typing.Optional[\"Section\"]:\n        \"\"\"The :class:`Section` this interval belongs to.\"\"\"\n\n        return self._section\n\n    @section.setter\n    def section(self, value: typing.Optional[\"Section\"]) -> None:\n        if self._section is not None:\n            self._section.byte_intervals.discard(self)\n        if value is not None:\n            value.byte_intervals.add(self)\n\n    @property\n    def symbolic_expressions(\n        self,\n    ) -> typing.MutableMapping[int, SymbolicExpression]:\n        return self._symbolic_expressions\n\n    @symbolic_expressions.setter\n    def symbolic_expressions(\n        self, value: typing.Dict[int, SymbolicExpression]\n    ) -> None:\n        self._symbolic_expressions.clear()\n        self._symbolic_expressions.update(value)\n\n    def deep_eq(self, other: object) -> bool:\n        # Do not move __eq__. See docstring for Node.deep_eq for more info.\n        if not isinstance(other, ByteInterval):\n            return False\n        return (\n            self.uuid == other.uuid\n            and self.address == other.address\n            and self.contents == other.contents\n            and self.size == other.size\n            and len(self.blocks) == len(other.blocks)\n            and all(\n                self_node.deep_eq(other_node)\n                for self_node, other_node in zip(\n                    sorted(self.blocks, key=lambda b: b.uuid),\n                    sorted(other.blocks, key=lambda b: b.uuid),\n                )\n            )\n            and len(self.symbolic_expressions)\n            == len(other.symbolic_expressions)\n            and all(\n                self_kv[0] == other_kv[0] and self_kv[1].deep_eq(other_kv[1])\n                for self_kv, other_kv in zip(\n                    sorted(\n                        self.symbolic_expressions.items(), key=lambda kv: kv[0]\n                    ),\n                    sorted(\n                        other.symbolic_expressions.items(),\n                        key=lambda kv: kv[0],\n                    ),\n                )\n            )\n        )\n\n    def __repr__(self) -> str:\n\n        return (\n            \"ByteInterval(\"\n            \"uuid={uuid!r}, \"\n            \"address={address}, \"\n            \"size={size}, \"\n            \"contents={contents!r}, \"\n            \"blocks={blocks!r}, \"\n            \"symbolic_expressions={symbolic_expressions!r}, \"\n            \")\".format(\n                uuid=self.uuid,\n                address=self.address,\n                size=self.size,\n                contents=self.contents,\n                blocks=self.blocks,\n                symbolic_expressions=self.symbolic_expressions,\n            )\n        )\n\n    def byte_blocks_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[ByteBlock]:\n        \"\"\"Finds all the byte blocks that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        if self.address is None:\n            return ()\n\n        return _nodes_on_interval_tree(\n            self._interval_tree.get(), addrs, -self.address\n        )\n\n    def byte_blocks_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[ByteBlock]:\n        \"\"\"Finds all the byte blocks that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        if self.address is None:\n            return ()\n\n        return _nodes_at_interval_tree(\n            self._interval_tree.get(), addrs, -self.address\n        )\n\n    def code_blocks_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[CodeBlock]:\n        \"\"\"Finds all the code blocks that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return (\n            b for b in self.byte_blocks_on(addrs) if isinstance(b, CodeBlock)\n        )\n\n    def code_blocks_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[CodeBlock]:\n        \"\"\"Finds all the code blocks that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return (\n            b for b in self.byte_blocks_at(addrs) if isinstance(b, CodeBlock)\n        )\n\n    def data_blocks_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[DataBlock]:\n        \"\"\"Finds all the data blocks that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return (\n            b for b in self.byte_blocks_on(addrs) if isinstance(b, DataBlock)\n        )\n\n    def data_blocks_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[DataBlock]:\n        \"\"\"Finds all the data blocks that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return (\n            b for b in self.byte_blocks_at(addrs) if isinstance(b, DataBlock)\n        )\n\n    def byte_blocks_on_offset(\n        self, offsets: typing.Union[int, range]\n    ) -> typing.Iterable[ByteBlock]:\n        \"\"\"\n        Finds all the byte blocks that overlap an offset or range of offsets.\n\n        :param offsets: Either a ``range`` object or a single offset.\n        \"\"\"\n\n        return _nodes_on_interval_tree_offset(\n            self._interval_tree.get(), offsets\n        )\n\n    def byte_blocks_at_offset(\n        self, offsets: typing.Union[int, range]\n    ) -> typing.Iterable[ByteBlock]:\n        \"\"\"\n        Finds all the byte blocks that begin at an offset or range of offsets.\n\n        :param offsets: Either a ``range`` object or a single offset.\n        \"\"\"\n\n        return _nodes_at_interval_tree_offset(\n            self._interval_tree.get(), offsets\n        )\n\n    def code_blocks_on_offset(\n        self, offsets: typing.Union[int, range]\n    ) -> typing.Iterable[CodeBlock]:\n        \"\"\"\n        Finds all the code blocks that overlap an offset or range of offsets.\n\n        :param offsets: Either a ``range`` object or a single offset.\n        \"\"\"\n\n        return (\n            b\n            for b in self.byte_blocks_on_offset(offsets)\n            if isinstance(b, CodeBlock)\n        )\n\n    def code_blocks_at_offset(\n        self, offsets: typing.Union[int, range]\n    ) -> typing.Iterable[CodeBlock]:\n        \"\"\"\n        Finds all the code blocks that begin at an offset or range of offsets.\n\n        :param offsets: Either a ``range`` object or a single offset.\n        \"\"\"\n\n        return (\n            b\n            for b in self.byte_blocks_at_offset(offsets)\n            if isinstance(b, CodeBlock)\n        )\n\n    def data_blocks_on_offset(\n        self, offsets: typing.Union[int, range]\n    ) -> typing.Iterable[DataBlock]:\n        \"\"\"\n        Finds all the data blocks that overlap an offset or range of offsets.\n\n        :param offsets: Either a ``range`` object or a single offset.\n        \"\"\"\n\n        return (\n            b\n            for b in self.byte_blocks_on_offset(offsets)\n            if isinstance(b, DataBlock)\n        )\n\n    def data_blocks_at_offset(\n        self, offsets: typing.Union[int, range]\n    ) -> typing.Iterable[DataBlock]:\n        \"\"\"\n        Finds all the data blocks that begin at an offset or range of offsets.\n\n        :param offsets: Either a ``range`` object or a single offset.\n        \"\"\"\n\n        return (\n            b\n            for b in self.byte_blocks_at_offset(offsets)\n            if isinstance(b, DataBlock)\n        )\n\n    def symbolic_expressions_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[SymbolicExpressionElement]:\n        \"\"\"Finds all the symbolic expressions that begin at an address or\n        range of addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        :returns: Yields ``(interval, offset, symexpr)`` tuples for every\n            symbolic expression in the range.\n        \"\"\"\n\n        if self.address is None:\n            return\n\n        addrs = get_desired_range(addrs)\n        for i in self._symbolic_expressions._data.irange(\n            addrs.start - self.address,\n            addrs.stop - self.address,\n            inclusive=(True, False),\n        ):\n            if self.address + i in addrs:\n                yield (self, i, self.symbolic_expressions[i])\n\n    def symbolic_expressions_at_offset(\n        self, offsets: typing.Union[int, range]\n    ) -> typing.Iterable[SymbolicExpressionElement]:\n        \"\"\"\n        Finds all the symbolic expressions that begin at an offset or range of\n        offsets.\n\n        :param addrs: Either a ``range`` object or a single offset.\n        :returns: Yields ``(interval, offset, symexpr)`` tuples for every\n            symbolic expression in the range.\n        \"\"\"\n\n        offsets = get_desired_range(offsets)\n        for i in self._symbolic_expressions._data.irange(\n            offsets.start,\n            offsets.stop,\n            inclusive=(True, False),\n        ):\n            if i in offsets:\n                yield (self, i, self.symbolic_expressions[i])\n\n    def _add_to_uuid_cache(self, cache: typing.Dict[UUID, Node]) -> None:\n        \"\"\"Update the UUID cache when this node is added.\"\"\"\n\n        cache[self.uuid] = self\n        for block in self.blocks:\n            block._add_to_uuid_cache(cache)\n\n    def _remove_from_uuid_cache(self, cache: typing.Dict[UUID, Node]) -> None:\n        \"\"\"Update the UUID cache when this node is removed.\"\"\"\n\n        del cache[self.uuid]\n        for block in self.blocks:\n            block._remove_from_uuid_cache(cache)\n\n    @property\n    def module(self) -> typing.Optional[\"Module\"]:\n        \"\"\"Get the module this node ultimately belongs to.\"\"\"\n        if self.section is None:\n            return None\n        return self.section.module\n\n    @property\n    def ir(self) -> typing.Optional[\"IR\"]:\n        \"\"\"Get the IR this node ultimately belongs to.\"\"\"\n        if self.module is None:\n            return None\n        return self.module.ir\n"
  },
  {
    "path": "python/gtirb/cfg.py",
    "content": "from enum import Enum\nfrom typing import (\n    TYPE_CHECKING,\n    Hashable,\n    Iterable,\n    Iterator,\n    MutableSet,\n    NamedTuple,\n    Optional,\n    Tuple,\n)\nfrom uuid import UUID\n\nfrom networkx import MultiDiGraph\n\nfrom .block import CfgNode\nfrom .proto import CFG_pb2\nfrom .util import DeserializationError\n\nif TYPE_CHECKING:  # pragma: no cover\n    from .ir import IR\n\n\nclass EdgeType(Enum):\n    \"\"\"The type of control flow transfer indicated by a\n    :class:`gtirb.Edge`.\n    \"\"\"\n\n    Branch = CFG_pb2.EdgeType.Value(\"Type_Branch\")\n    \"\"\"This edge is the explicit target of a jump instruction.\n    May be conditional or unconditional. If conditional, there will be\n    a corresponding edge of type :attr:`gtirb.Edge.Type.Fallthrough`.\n    \"\"\"\n\n    Call = CFG_pb2.EdgeType.Value(\"Type_Call\")\n    \"\"\"This edge is the explicit target of a call instruction.\n    Unless the function does not return, there will also be a\n    corresponding edge of type :attr:`gtirb.Edge.Type.Fallthrough`.\n    \"\"\"\n\n    Fallthrough = CFG_pb2.EdgeType.Value(\"Type_Fallthrough\")\n    \"\"\"This edge represents two blocks executing in sequence.\n    This occurs on the non-branching paths of conditional branch\n    instructions, after call instructons have returned, and when two\n    blocks have no control flow between them, but another\n    :class:`gtirb.Edge` targets the target block.\n    If there exists a fallthrough edge from block ``A`` to block ``B``,\n    then ``A`` must immediately precede ``B`` in memory.\n    \"\"\"\n\n    Return = CFG_pb2.EdgeType.Value(\"Type_Return\")\n    \"\"\"This edge represents a return from a function, generally via a\n    return instruction. Return edges may either go to a symbolless\n    :class:`gtirb.ProxyBlock`, which indicates that the set of possible\n    return targets is unknown, or there may be one return edge per\n    return target, which indicates that the set of possible return targets\n    if fully known.\n    \"\"\"\n\n    Syscall = CFG_pb2.EdgeType.Value(\"Type_Syscall\")\n    \"\"\"This edge is the explicit target of a system call instruction.\n    Unless the function does not return, there will also be a\n    corresponding edge of type :attr:`gtirb.Edge.Type.Fallthrough`. This\n    is the system call equivalent to :class:`gtirb.Edge.Type.Call`.\n    \"\"\"\n\n    Sysret = CFG_pb2.EdgeType.Value(\"Type_Sysret\")\n    \"\"\"This edge represents a return from a system call, generally via a\n    return instruction. Return edges may either go to a symbolless\n    :class:`gtirb.ProxyBlock`, which indicates that the set of possible\n    return targets is unknown, or there may be one return edge per\n    return target, which indicates that the set of possible return targets\n    if fully known. This is the system call equivalent to\n    :class:`gtirb.Edge.Type.Return`.\n    \"\"\"\n\n\nclass EdgeLabel(NamedTuple):\n    \"\"\"Contains a more detailed description of a :class:`gtirb.Edge`\n    in the CFG.\n\n    :ivar ~.conditional: When this edge is part of a conditional branch,\n        ``conditional`` is ``True`` when the edge represents the control\n        flow taken when the branch's condition is met, and ``False``\n        when it represents the control flow taken when the branch's\n        condition is not met. Otherwise, it is always ``False``.\n    :ivar ~.direct: ``True`` if the branch or call is direct,\n            and ``False`` if it is indirect. If an edge is indirect,\n            then all outgoing indirect edges represent the set of\n            possible locations the edge may branch to. If there\n            exists an indirect outgoing edge to a :class:`gtirb.ProxyBlock`\n            without any :class:`gtirb.Symbol` objects referring to it,\n            then the set of all possible branch locations is unknown.\n    :ivar ~.type: The type of control flow the :class:`gtirb.Edge`\n        represents.\n    \"\"\"\n\n    type: EdgeType\n    conditional: bool = False\n    direct: bool = True\n\n    def __repr__(self) -> str:\n        return (\n            \"Edge.Label(\"\n            \"type=Edge.Type.{type.name}, \"\n            \"conditional={conditional!r}, \"\n            \"direct={direct!r}, \"\n            \")\".format(**self._asdict())\n        )\n\n\nclass Edge(\n    NamedTuple(\n        \"NamedTuple\",\n        (\n            (\"source\", CfgNode),\n            (\"target\", CfgNode),\n            (\"label\", Optional[EdgeLabel]),\n        ),\n    )\n):\n    \"\"\"An edge in the CFG from ``source`` to ``target``, with optional\n    control-flow details in ``label``.\n\n    :ivar ~.source: The source CFG node.\n    :ivar ~.target: The target CFG node.\n    :ivar ~.label: An optional label containing more control flow information.\n    \"\"\"\n\n    __slots__ = ()\n\n    def __new__(\n        cls,\n        source: CfgNode,\n        target: CfgNode,\n        label: Optional[EdgeLabel] = None,\n    ) -> \"Edge\":\n        return super().__new__(cls, source, target, label)\n\n    Type = EdgeType\n    Label = EdgeLabel\n\n\nclass CFG(MutableSet[Edge]):\n    \"\"\"A control-flow graph for an :class:`IR`. Vertices are\n    :class:`CfgNode`\\\\s, and edges may optionally contain\n    :class:`Edge.Label`\\\\s.\n\n    The graph may be viewed simply as a set of :class:`Edge`\\\\s. For\n    convenience, the :meth:`out_edges` and :meth:`in_edges` methods provide\n    access to the outgoing or incoming edges of individual nodes.\n\n    For efficency, only vertices with edges are guaranteed to be stored in this\n    graph. If you want to find all vertices possible (that is, all\n    :class:`CfgNode`\\\\s), use :meth:`IR.cfg_nodes` instead.\n\n    Internally, the graph is stored as a NetworkX instance, which can be\n    accessed using :meth:`nx`. This allows NetworkX's large library of graph\n    algorithms to be used on CFGs, if desired.\n    \"\"\"\n\n    def __init__(self, edges: Optional[Iterable[Edge]] = None):\n        self._nxg: \"MultiDiGraph[CfgNode, Hashable, Optional[EdgeLabel]]\" = (\n            MultiDiGraph()\n        )\n        if edges is not None:\n            self.update(edges)\n\n    def _edge_key(self, edge: Edge) -> Optional[Hashable]:\n        if edge.source in self._nxg:\n            neighbors = self._nxg[edge.source]\n            if edge.target in neighbors:\n                for key, e in neighbors[edge.target].items():\n                    if \"label\" in e and e[\"label\"] == edge.label:\n                        return key\n        return None\n\n    def __contains__(self, edge: object) -> bool:\n        return isinstance(edge, Edge) and self._edge_key(edge) is not None\n\n    def __iter__(self) -> Iterator[Edge]:\n        for s, t, l in self._nxg.edges(data=\"label\"):\n            yield Edge(s, t, l)\n\n    def __len__(self) -> int:\n        return len(self._nxg.edges())\n\n    def update(self, edges: Iterable[Edge]) -> None:\n        for edge in edges:\n            self.add(edge)\n\n    def add(self, edge: Edge) -> None:\n        if edge not in self:\n            self._nxg.add_edge(edge.source, edge.target, label=edge.label)\n\n    def clear(self) -> None:\n        self._nxg.clear()\n\n    def discard(self, edge: Edge) -> None:\n        key = self._edge_key(edge)\n        if key is not None:\n            self._nxg.remove_edge(edge.source, edge.target, key=key)\n\n    def out_edges(self, node: CfgNode) -> Iterator[Edge]:\n        if node in self._nxg:\n            for s, t, l in self._nxg.out_edges(node, data=\"label\"):\n                yield Edge(s, t, l)\n\n    def in_edges(self, node: CfgNode) -> Iterator[Edge]:\n        if node in self._nxg:\n            for s, t, l in self._nxg.in_edges(node, data=\"label\"):\n                yield Edge(s, t, l)\n\n    @classmethod\n    def _from_protobuf(\n        cls, edges: Iterable[CFG_pb2.Edge], ir: Optional[\"IR\"]\n    ) -> \"CFG\":\n        assert ir\n\n        def make_edge(ir: \"IR\", edge: CFG_pb2.Edge) -> Edge:\n            source_uuid = UUID(bytes=edge.source_uuid)\n            source = ir.get_by_uuid(source_uuid)\n            if not isinstance(source, CfgNode):\n                raise DeserializationError(\n                    \"CFG: UUID %s is not a CfgNode\" % source_uuid\n                )\n\n            target_uuid = UUID(bytes=edge.target_uuid)\n            target = ir.get_by_uuid(target_uuid)\n            if not isinstance(target, CfgNode):\n                raise DeserializationError(\n                    \"CFG: UUID %s is not a CfgNode\" % target_uuid\n                )\n\n            label: Optional[EdgeLabel] = None\n            if edge.HasField(\"label\"):\n                label = Edge.Label(\n                    Edge.Type(edge.label.type),\n                    edge.label.conditional,\n                    edge.label.direct,\n                )\n\n            return Edge(source, target, label)\n\n        return CFG(make_edge(ir, edge) for edge in edges)\n\n    def _to_protobuf(self) -> Iterable[CFG_pb2.Edge]:\n        for s, t, l in self._nxg.edges(data=\"label\"):\n            proto_edge = CFG_pb2.Edge()\n            proto_edge.source_uuid = s.uuid.bytes\n            proto_edge.target_uuid = t.uuid.bytes\n            if l:\n                proto_edge.label.type = l.type.value\n                proto_edge.label.conditional = l.conditional\n                proto_edge.label.direct = l.direct\n            yield proto_edge\n\n    # Note: This returns a \"bare\" MultiDiGraph because MultiDiGraph is not\n    # actually a generic type.\n    def nx(self) -> MultiDiGraph:  # type: ignore[type-arg]\n        return self._nxg\n\n    def deep_eq(self, other: \"CFG\") -> bool:\n        # Do not move __eq__. See docstring for Node.deep_eq for more info.\n\n        def edge_sort_key(\n            edge: Edge,\n        ) -> Tuple[UUID, UUID, Optional[Tuple[int, bool, bool]]]:\n            label_key = -1, False, False\n            if edge.label is not None:\n                label_key = (\n                    edge.label.type.value,\n                    edge.label.conditional,\n                    edge.label.direct,\n                )\n            return (edge.source.uuid, edge.target.uuid, label_key)\n\n        if not isinstance(other, CFG):\n            return False\n\n        # We don't have to compare nodes for deep_eq because if an node has no\n        # edges, then we do not guarantee that graphs have that node as a\n        # vertex, and if it has edges, a failure of deep_eq will be detected\n        # when comparing edges.\n\n        if self._nxg.number_of_edges() != other._nxg.number_of_edges():\n            return False\n\n        self_edges = sorted(self, key=edge_sort_key)\n        other_edges = sorted(other, key=edge_sort_key)\n\n        for self_edge, other_edge in zip(self_edges, other_edges):\n            if self_edge.label != other_edge.label:\n                return False\n            if not self_edge.source.deep_eq(other_edge.source):\n                return False\n            if not self_edge.target.deep_eq(other_edge.target):\n                return False\n\n        return True\n\n    def __repr__(self) -> str:\n        return \"CFG(%r)\" % list(self)\n"
  },
  {
    "path": "python/gtirb/ir.py",
    "content": "\"\"\"The IR is the core class for reading and writing GTIRB files.\n\n    You can open a GTIRB Protobuf file and load it into an IR instance:\n\n    >>> ir = IR.load_protobuf('filename.gtirb')\n\n    And then you can write the IR instance as a Protobuf file:\n\n    >>> ir.save_protobuf('filename.gtirb')\n\"\"\"\n\nimport itertools\nimport os\nimport typing\nfrom uuid import UUID\n\nfrom .auxdata import AuxData, AuxDataContainer\nfrom .block import ByteBlock, CfgNode, CodeBlock, DataBlock, ProxyBlock\nfrom .byteinterval import ByteInterval, SymbolicExpressionElement\nfrom .cfg import CFG, Edge\nfrom .module import Module\nfrom .node import Node, _NodeMessage\nfrom .proto import CFG_pb2, IR_pb2\nfrom .section import Section\nfrom .symbol import Symbol\nfrom .util import (\n    DictLike,\n    ListWrapper,\n    nodes_at,\n    nodes_on,\n    symbolic_expressions_at,\n)\nfrom .version import PROTOBUF_VERSION\n\nGTIRB_MAGIC_CHARS = b\"GTIRB\"\n\n\nclass IR(AuxDataContainer):\n    \"\"\"A complete internal representation consisting of multiple Modules.\n\n    :ivar ~.modules: A list of :class:`Module`\\\\s contained in the IR.\n    :ivar ~.cfg: The IR's control flow graph.\n    :ivar ~.version: The Protobuf version of this IR.\n    \"\"\"\n\n    class _ModuleList(ListWrapper[Module]):\n        def __init__(self, node: \"IR\", *args: typing.Iterable[Module]):\n            self._node = node\n            super().__init__(*args)\n\n        def _remove(self, v: Module) -> None:\n            v._ir = None\n            v._remove_from_uuid_cache(self._node._local_uuid_cache)\n\n        def _add(self, v: Module) -> None:\n            if v._ir is not None:\n                v._ir.modules.remove(v)\n            v._ir = self._node\n            v._add_to_uuid_cache(self._node._local_uuid_cache)\n\n    def __init__(\n        self,\n        *,\n        modules: typing.Iterable[Module] = [],\n        aux_data: DictLike[str, AuxData] = {},\n        cfg: typing.Iterable[Edge] = set(),\n        version: int = PROTOBUF_VERSION,\n        uuid: typing.Optional[UUID] = None,\n    ):\n        \"\"\"\n        :param modules: A list of Modules contained in the IR.\n        :param cfg: A set of :class:`Edge`\\\\s representing the IR's control\n            flow graph. Defaults to being empty.\n        :param aux_data: The initial auxiliary data to be associated\n            with the object, as a mapping from names to\n            :class:`gtirb.AuxData`. Defaults to being empty.\n        :param version: The Protobuf version of this IR.\n        :param uuid: The UUID of this ``IR``,\n            or None if a new UUID needs generated via :func:`uuid.uuid4`.\n            Defaults to None.\n        \"\"\"\n\n        self._local_uuid_cache: typing.Dict[UUID, Node] = {}\n        # Modules are decoded before the aux data, since the UUID decoder\n        # checks Node's cache.\n        self.modules = IR._ModuleList(self, modules)\n        self.cfg = CFG(cfg)\n        self.version = version\n        super().__init__(aux_data, uuid)\n        self._local_uuid_cache[self.uuid] = self\n\n    @classmethod\n    def _decode_protobuf(\n        cls, proto_ir: _NodeMessage, uuid: UUID, _: typing.Optional[\"IR\"]\n    ) -> \"IR\":\n        assert isinstance(proto_ir, IR_pb2.IR)\n        if proto_ir.version != PROTOBUF_VERSION:\n            raise ValueError(\n                \"Attempt to decode IR of version %s (expected version %s)\"\n                % (proto_ir.version, PROTOBUF_VERSION)\n            )\n\n        ir = cls(version=proto_ir.version, uuid=uuid)\n        ir.modules.extend(\n            Module._from_protobuf(m, ir) for m in proto_ir.modules\n        )\n        ir.cfg = CFG._from_protobuf(proto_ir.cfg.edges, ir)\n        ir.aux_data.update(\n            AuxDataContainer._read_protobuf_aux_data(proto_ir.aux_data, ir)\n        )\n        return ir\n\n    def _to_protobuf(self) -> IR_pb2.IR:\n        proto_ir = IR_pb2.IR()\n        proto_ir.uuid = self.uuid.bytes\n        proto_ir.version = self.version\n        proto_ir.modules.extend(m._to_protobuf() for m in self.modules)\n        proto_cfg = CFG_pb2.CFG()\n        proto_cfg.vertices.extend(v.uuid.bytes for v in self.cfg_nodes)\n        proto_cfg.edges.extend(self.cfg._to_protobuf())\n        proto_ir.cfg.CopyFrom(proto_cfg)\n        self._write_protobuf_aux_data(proto_ir.aux_data)\n        return proto_ir\n\n    def deep_eq(self, other: object) -> bool:\n        # Do not move __eq__. See docstring for Node.deep_eq for more info.\n        if not isinstance(other, IR) or not super().deep_eq(other):\n            return False\n        self_modules = sorted(self.modules, key=lambda m: m.uuid)\n        other_modules = sorted(other.modules, key=lambda m: m.uuid)\n        if not len(self_modules) == len(other_modules):\n            return False\n        for self_module, other_module in zip(self_modules, other_modules):\n            if not self_module.deep_eq(other_module):\n                return False\n        return self.version == other.version and self.cfg.deep_eq(other.cfg)\n\n    @staticmethod\n    def load_protobuf_file(protobuf_file: typing.BinaryIO) -> \"IR\":\n        \"\"\"Load IR from a Protobuf object.\n\n        Use this function when you have a Protobuf object already loaded,\n        and you want to parse it as a GTIRB IR.\n        If the Protobuf object is stored in a file,\n        use :func:`gtirb.IR.load_protobuf` instead.\n\n        :param protobuf_file: A byte stream encoding a GTIRB Protobuf message.\n        :returns: An IR object representing the same\n            information that is contained in ``protobuf_file``.\n        \"\"\"\n\n        # Magic signature\n        # Bytes 0-4 contain the ASCII characters: GTIRB.\n        # Bytes 5-6 are considered reserved for future use and should be 0.\n        # Byte 7 contains the GTIRB protobuf spec version in use.\n        magic = protobuf_file.read(len(GTIRB_MAGIC_CHARS))\n        if magic != GTIRB_MAGIC_CHARS:\n            raise ValueError(\"File missing GTIRB magic - not a GTIRB file?\")\n\n        protobuf_file.read(1)\n        protobuf_file.read(1)\n\n        version = int.from_bytes(protobuf_file.read(1), byteorder=\"little\")\n        if version != PROTOBUF_VERSION:\n            raise ValueError(\n                \"Attempt to decode IR of version %s (expected version %s)\"\n                % (version, PROTOBUF_VERSION)\n            )\n\n        ir = IR_pb2.IR()\n        ir.ParseFromString(protobuf_file.read())\n        return IR._from_protobuf(ir, None)\n\n    @staticmethod\n    def load_protobuf(\n        file_name: typing.Union[str, \"os.PathLike[str]\"]\n    ) -> \"IR\":\n        \"\"\"Load IR from a Protobuf file at the specified path.\n\n        :param file_name: The path to the Protobuf file.\n        :returns: A Python GTIRB IR object.\n        \"\"\"\n        with open(file_name, \"rb\") as f:\n            return IR.load_protobuf_file(f)\n\n    def save_protobuf_file(self, protobuf_file: typing.BinaryIO) -> None:\n        \"\"\"Save ``self`` to a Protobuf object.\n\n        :param protobuf_file: The byte stream to write the GTIRB Protobuf\n            message to.\n        \"\"\"\n\n        protobuf_file.write(GTIRB_MAGIC_CHARS)\n        protobuf_file.write(b\"\\0\")\n        protobuf_file.write(b\"\\0\")\n        protobuf_file.write(PROTOBUF_VERSION.to_bytes(1, byteorder=\"little\"))\n        protobuf_file.write(self._to_protobuf().SerializeToString())\n\n    def save_protobuf(\n        self, file_name: typing.Union[str, \"os.PathLike[str]\"]\n    ) -> None:\n        \"\"\"Save ``self`` to a Protobuf file at the specified path.\n\n        :param file_name: The file path at which to\n            save the Protobuf representation of ``self``.\n        \"\"\"\n        with open(file_name, \"wb\") as f:\n            self.save_protobuf_file(f)\n\n    def __repr__(self) -> str:\n        return (\n            \"IR(\"\n            \"uuid={uuid!r}, \"\n            \"modules={modules!r}, \"\n            \"cfg={cfg!r}, \"\n            \"version={version}, \"\n            \")\".format(**self.__dict__)\n        )\n\n    @property\n    def proxy_blocks(self) -> typing.Iterator[ProxyBlock]:\n        \"\"\"The :class:`ProxyBlock`\\\\s in this IR.\"\"\"\n\n        return itertools.chain.from_iterable(m.proxies for m in self.modules)\n\n    @property\n    def sections(self) -> typing.Iterator[Section]:\n        \"\"\"The :class:`Section`\\\\s in this IR.\"\"\"\n\n        return itertools.chain.from_iterable(m.sections for m in self.modules)\n\n    @property\n    def symbols(self) -> typing.Iterator[Symbol]:\n        \"\"\"The :class:`Symbol`\\\\s in this IR.\"\"\"\n\n        return itertools.chain.from_iterable(m.symbols for m in self.modules)\n\n    @property\n    def byte_intervals(self) -> typing.Iterator[ByteInterval]:\n        \"\"\"The :class:`ByteInterval`\\\\s in this IR.\"\"\"\n\n        return itertools.chain.from_iterable(\n            m.byte_intervals for m in self.modules\n        )\n\n    @property\n    def byte_blocks(self) -> typing.Iterator[ByteBlock]:\n        \"\"\"The :class:`ByteBlock`\\\\s in this IR.\"\"\"\n\n        return itertools.chain.from_iterable(\n            m.byte_blocks for m in self.modules\n        )\n\n    @property\n    def code_blocks(self) -> typing.Iterator[CodeBlock]:\n        \"\"\"The :class:`CodeBlock`\\\\s in this IR.\"\"\"\n\n        return itertools.chain.from_iterable(\n            m.code_blocks for m in self.modules\n        )\n\n    @property\n    def data_blocks(self) -> typing.Iterator[DataBlock]:\n        \"\"\"The :class:`DataBlock`\\\\s in this IR.\"\"\"\n\n        return itertools.chain.from_iterable(\n            m.data_blocks for m in self.modules\n        )\n\n    @property\n    def cfg_nodes(self) -> typing.Iterator[CfgNode]:\n        \"\"\"The :class:`CfgNode`\\\\s in this IR.\"\"\"\n\n        return itertools.chain.from_iterable(m.cfg_nodes for m in self.modules)\n\n    def modules_named(self, name: str) -> typing.Iterator[Module]:\n        \"\"\"Find all modules with a given name\"\"\"\n        return (m for m in self.modules if m.name == name)\n\n    def sections_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[Section]:\n        \"\"\"Finds all the sections that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return nodes_on(self.sections, addrs)\n\n    def sections_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[Section]:\n        \"\"\"Finds all the sections that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return nodes_at(self.sections, addrs)\n\n    def byte_intervals_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[ByteInterval]:\n        \"\"\"Finds all the byte intervals that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            m.byte_intervals_on(addrs) for m in self.modules\n        )\n\n    def byte_intervals_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[ByteInterval]:\n        \"\"\"Finds all the byte intervals that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            m.byte_intervals_at(addrs) for m in self.modules\n        )\n\n    def byte_blocks_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[ByteBlock]:\n        \"\"\"Finds all the byte blocks that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            m.byte_blocks_on(addrs) for m in self.modules\n        )\n\n    def byte_blocks_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[ByteBlock]:\n        \"\"\"Finds all the byte blocks that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            m.byte_blocks_at(addrs) for m in self.modules\n        )\n\n    def code_blocks_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[CodeBlock]:\n        \"\"\"Finds all the code blocks that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            m.code_blocks_on(addrs) for m in self.modules\n        )\n\n    def code_blocks_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[CodeBlock]:\n        \"\"\"Finds all the code blocks that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            m.code_blocks_at(addrs) for m in self.modules\n        )\n\n    def data_blocks_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[DataBlock]:\n        \"\"\"Finds all the data blocks that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            m.data_blocks_on(addrs) for m in self.modules\n        )\n\n    def data_blocks_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[DataBlock]:\n        \"\"\"Finds all the data blocks that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            m.data_blocks_at(addrs) for m in self.modules\n        )\n\n    def symbolic_expressions_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[SymbolicExpressionElement]:\n        \"\"\"Finds all the symbolic expressions that begin at an address or\n        range of addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        :returns: Yields ``(interval, offset, symexpr)`` tuples for every\n            symbolic expression in the range.\n        \"\"\"\n\n        return symbolic_expressions_at(self.modules, addrs)\n\n    def get_by_uuid(self, uuid: UUID) -> typing.Optional[Node]:\n        \"\"\"Look up a node by its UUID.\n\n        This method will find any node currently attached to this IR.\n        It will not find any nodes attached to other IRs, or not attached to\n        any IR.\n\n        :param uuid: The UUID to look up.\n        :returns: The Node this UUID corresponds to, or None if no node exists\n            with that UUID.\n        \"\"\"\n\n        return self._local_uuid_cache.get(uuid)\n"
  },
  {
    "path": "python/gtirb/lazyintervaltree.py",
    "content": "\"\"\"\nImplements a simple wrapper that lazily initializes and updates an\nIntervalTree.\n\nGTIRB uses IntervalTrees to accelerate certain operations. However, these\noperations are not always needed for a given GTIRB object or by a given GTIRB\nanalysis. To prevent scripts that do not need the IntervalTrees from wasting\ntime updating the data structures, the LazyIntervalTree in this module delays\ninstantiating or updating the tree. Instead, it queues the updates so they can\nbe rapidly applied when the script invokes an operation that requires an\nup-to-date tree.\n\"\"\"\n\nimport enum\nfrom typing import (\n    Collection,\n    Generic,\n    Iterator,\n    List,\n    Optional,\n    Tuple,\n    TypeVar,\n)\n\nfrom intervaltree import Interval, IntervalTree\nfrom typing_extensions import Protocol\n\n_K = TypeVar(\"_K\")\n_Kco = TypeVar(\"_Kco\", covariant=True)\n_V = TypeVar(\"_V\")\n\n\nclass _EventType(enum.Enum):\n    \"\"\"Whether an interval is to be added or discarded.\"\"\"\n\n    ADDED = enum.auto()\n    DISCARDED = enum.auto()\n\n\nclass IntervalBuilder(Protocol[_Kco, _V]):\n    \"\"\"Gets an interval for certain values.\n\n    If no interval is available for a particular value, returns None instead.\n    \"\"\"\n\n    def __call__(self, node: _V) -> Optional[\"Interval[_Kco, _V]\"]:\n        ...\n\n\nclass LazyIntervalTree(Generic[_K, _V]):\n    \"\"\"Simple wrapper to lazily initialize and update an IntervalTree.\n\n    The underlying IntervalTree can be retrieved by calling get(). This will\n    ensure that the tree is up-to-date with all intermediate modifications\n    before returning it.\n\n    In many algorithms, the tree may receive large numbers of modifications,\n    adding and removing the same intervals several times before querying. In\n    these cases, it may be faster to rebuild the tree from scratch rather than\n    perform all of the intermediate modifications. For this reason, get() is\n    not guaranteed to always return the same tree object. That is, the tree\n    returned by get() should not be cached; calling get() may return a new tree\n    rather than updating the tree it returned previously.\n    \"\"\"\n\n    def __init__(\n        self,\n        values: Collection[_V],\n        make_interval: IntervalBuilder[_K, _V],\n    ):\n        \"\"\"Create a new lazy tree.\n\n        :param values: collection of values from which the tree can be rebuilt\n        :param make_interval: callable to get an interval for a value\n        \"\"\"\n        self._interval_index: Optional[\"IntervalTree[_K, _V]\"] = None\n        self._interval_events: List[Tuple[_EventType, \"Interval[_K, _V]\"]] = []\n        self._value_collection = values\n        self._make_interval = make_interval\n\n    def add(self, value: _V) -> None:\n        \"\"\"Add a value to the tree.\"\"\"\n        interval = self._make_interval(value)\n        if interval is not None:\n            self._interval_events.append((_EventType.ADDED, interval))\n\n    def discard(self, value: _V) -> None:\n        \"\"\"Remove a value from the tree.\n\n        Does nothing if the interval with that value is not present.\n        \"\"\"\n        interval = self._make_interval(value)\n        if interval is not None:\n            self._interval_events.append((_EventType.DISCARDED, interval))\n\n    def get(self) -> \"IntervalTree[_K, _V]\":\n        \"\"\"Get the most up-to-date tree reflecting all pending updates.\"\"\"\n\n        def intervals() -> Iterator[\"Interval[_K, _V]\"]:\n            for value in self._value_collection:\n                interval = self._make_interval(value)\n                if interval:\n                    yield interval\n\n        if self._interval_index is None:\n            self._interval_index = IntervalTree(intervals())\n        elif len(self._value_collection) <= len(self._interval_events):\n            # Constructing a new tree involves one update for each value.\n            self._interval_index = IntervalTree(intervals())\n        else:\n            # There are fewer updates than constructing a new tree would use.\n            for event, interval in self._interval_events:\n                if event == _EventType.ADDED:\n                    self._interval_index.add(interval)\n                else:\n                    self._interval_index.discard(interval)\n        self._interval_events.clear()\n        return self._interval_index\n"
  },
  {
    "path": "python/gtirb/module.py",
    "content": "import collections\nimport itertools\nimport typing\nfrom enum import Enum\nfrom uuid import UUID\n\nfrom .auxdata import AuxData, AuxDataContainer\nfrom .block import ByteBlock, CfgNode, CodeBlock, DataBlock, ProxyBlock\nfrom .byteinterval import ByteInterval, SymbolicExpressionElement\nfrom .node import Node, _NodeMessage\nfrom .proto import Module_pb2\nfrom .section import Section\nfrom .symbol import Symbol\nfrom .util import (\n    DeserializationError,\n    DictLike,\n    SetWrapper,\n    nodes_at,\n    nodes_on,\n    symbolic_expressions_at,\n)\n\nif typing.TYPE_CHECKING:  # pragma: no cover\n    # Ignore flake8 \"imported but unused\" errors.\n    from .block import Block  # noqa: F401\n    from .ir import IR  # noqa: F401\n\n\n_T = typing.TypeVar(\"_T\", bound=typing.Union[ProxyBlock, Section, Symbol])\n\n\nclass Module(AuxDataContainer):\n    \"\"\"Represents a loadable object, such as an executable or library.\n\n    :ivar ~.binary_path: The path to the loadable binary object\n        represented by this module. An empty string if not specified.\n        The file represented by this path is indicitave of what file\n        this ``Module`` was initially created from; it is not guaranteed to\n        currently exist or have the same contents.\n    :ivar ~.isa: The ISA of the binary.\n    :ivar ~.file_format: The file format of the binary.\n    :ivar ~.byte_order: The endianness of the binary.\n    :ivar ~.name: The name given to the binary. Some file formats use this\n        for linking and/or symbol resolution purposes. The file name (without\n        directory components) if not specified by the format.\n    :ivar ~.preferred_addr: The preferred loading address of the binary.\n    :ivar ~.proxies: A set containing all the :class:`gtirb.ProxyBlock`\\\\s\n        in the binary.\n    :ivar ~.rebase_delta: The rebase delta of the binary.\n    :ivar ~.sections: A set containing all the :class:`gtirb.Section`\\\\s\n        in the binary.\n    :ivar ~.symbols: A set containing all the :class:`gtirb.Symbol`\\\\s\n        in the binary.\n    :ivar ~.entry_point: A :class:`CodeBlock` representing where\n        control flow of this module begins at, or None if not present.\n    \"\"\"\n\n    class FileFormat(Enum):\n        \"\"\"Identifies the executable file format of the binary represented\n        by a :class:`gtirb.Module`.\n        \"\"\"\n\n        Undefined = Module_pb2.FileFormat.Value(\"Format_Undefined\")\n        \"\"\"A file format that has not yet been specified.\n        This is for unitialized modules; do not use to refer to\n        file formats without ``FileFormat`` values.\n        \"\"\"\n\n        COFF = Module_pb2.FileFormat.Value(\"COFF\")\n        \"\"\"The Common Object File Format.\"\"\"\n\n        ELF = Module_pb2.FileFormat.Value(\"ELF\")\n        \"\"\"The Executable and Linkable Format,\n        formerly the Extensible Linking Format.\n        \"\"\"\n\n        IdaProDb32 = Module_pb2.FileFormat.Value(\"IdaProDb32\")\n        \"\"\"A 32-bit IDA Pro database file.\"\"\"\n\n        IdaProDb64 = Module_pb2.FileFormat.Value(\"IdaProDb64\")\n        \"\"\"A 64-bit IDA Pro database file.\"\"\"\n\n        MACHO = Module_pb2.FileFormat.Value(\"MACHO\")\n        \"\"\"A Mach object file.\"\"\"\n\n        PE = Module_pb2.FileFormat.Value(\"PE\")\n        \"\"\"Microsoft's Portable Executable format.\"\"\"\n\n        RAW = Module_pb2.FileFormat.Value(\"RAW\")\n        \"\"\"A raw binary file, with no file format.\"\"\"\n\n        XCOFF = Module_pb2.FileFormat.Value(\"XCOFF\")\n        \"\"\"The Extended Common Object File Format.\"\"\"\n\n    class ISA(Enum):\n        \"\"\"Identifies the instruction set architecture (ISA)\n        targeted by a :class:`gtirb.Module`.\n        \"\"\"\n\n        Undefined = Module_pb2.ISA.Value(\"ISA_Undefined\")\n        \"\"\"An ISA that has not yet been specified.\n        This is for unitialized modules;\n        use :class:`gtirb.Module.ISA.ValidButUnsupported`\n        instead for specifying undefined ISAs.\n        \"\"\"\n\n        ARM = Module_pb2.ISA.Value(\"ARM\")\n        \"\"\"The Acorn RISC Machine, 32-bit.\"\"\"\n\n        ARM64 = Module_pb2.ISA.Value(\"ARM64\")\n        \"\"\"The Acorn RISC Machine, 64-bit.\"\"\"\n\n        IA32 = Module_pb2.ISA.Value(\"IA32\")\n        \"\"\"The 32-bit Intel Architecture. Also known as i386, x86, or x32.\"\"\"\n\n        PPC32 = Module_pb2.ISA.Value(\"PPC32\")\n        \"\"\"IBM's 32-bit PowerPC (Performance Optimization with Enhanced RISC /\n        Performance Computing) architecture.\"\"\"\n\n        PPC64 = Module_pb2.ISA.Value(\"PPC64\")\n        \"\"\"IBM's 64-bit PowerPC (Performance Optimization with Enhanced RISC /\n        Performance Computing) architecture.\"\"\"\n\n        MIPS32 = Module_pb2.ISA.Value(\"MIPS32\")\n        \"\"\"Microprocessor without Interlocked Pipelined Stages, 32-bit.\"\"\"\n\n        MIPS64 = Module_pb2.ISA.Value(\"MIPS64\")\n        \"\"\"Microprocessor without Interlocked Pipelined Stages, 64-bit.\"\"\"\n\n        X64 = Module_pb2.ISA.Value(\"X64\")\n        \"\"\"The 64-bit Intel Architecture. Also known as x86_64.\"\"\"\n\n        ValidButUnsupported = Module_pb2.ISA.Value(\"ValidButUnsupported\")\n        \"\"\"An unknown or undefined ISA.\"\"\"\n\n    class ByteOrder(Enum):\n        \"\"\"Identifies the endianness of a :class:`gtirb.Module`.\"\"\"\n\n        Undefined = Module_pb2.ByteOrder.Value(\"ByteOrder_Undefined\")\n        \"\"\"An unknown or uninitialized endianness.\"\"\"\n\n        Big = Module_pb2.ByteOrder.Value(\"BigEndian\")\n        \"\"\"Big endian.\"\"\"\n\n        Little = Module_pb2.ByteOrder.Value(\"LittleEndian\")\n        \"\"\"Little endian.\"\"\"\n\n    class _NodeSet(SetWrapper[_T]):\n        def __init__(\n            self, node: \"Module\", field: str, *args: typing.Iterable[_T]\n        ):\n            self._node: Module = node\n            self._field: str = field\n            super().__init__(*args)\n\n        def add(self, v: _T) -> None:\n            if v._module is not None:\n                getattr(v._module, self._field).discard(v)\n            v._module = self._node\n            self._node._index_add(v)\n            if self._node.ir is not None:\n                v._add_to_uuid_cache(self._node.ir._local_uuid_cache)\n            return super().add(v)\n\n        def discard(self, v: _T) -> None:\n            if v not in self:\n                return\n            v._module = None\n            self._node._index_discard(v)\n            if self._node.ir is not None:\n                v._remove_from_uuid_cache(self._node.ir._local_uuid_cache)\n            return super().discard(v)\n\n    def __init__(\n        self,\n        *,\n        name: str,\n        aux_data: DictLike[str, AuxData] = {},\n        binary_path: str = \"\",\n        file_format: FileFormat = FileFormat.Undefined,\n        isa: ISA = ISA.Undefined,\n        byte_order: ByteOrder = ByteOrder.Undefined,\n        preferred_addr: int = 0,\n        proxies: typing.Iterable[ProxyBlock] = set(),\n        rebase_delta: int = 0,\n        sections: typing.Iterable[Section] = set(),\n        symbols: typing.Iterable[Symbol] = set(),\n        entry_point: typing.Optional[CodeBlock] = None,\n        uuid: typing.Optional[UUID] = None,\n        ir: typing.Optional[\"IR\"] = None,\n    ):\n        \"\"\"\n        :param aux_data: The initial auxiliary data to be associated\n            with the object, as a mapping from names to\n            :class:`gtirb.AuxData`, defaults to an empty :class:`dict`.\n        :param binary_path: The path to the loadable binary object\n            represented by this module.\n        :param isa: The ISA of the binary.\n        :param byte_order: The endianness of the binary.\n        :param file_format: The file format of the binary.\n        :param name: The name given to the binary.\n        :param preferred_addr: The preferred loading address of the binary.\n        :param proxies: A set containing all the :class:`gtirb.ProxyBlock`\\\\s\n            in the binary.\n        :param rebase_delta: The rebase delta of the binary.\n        :param sections: A set containing all the :class:`gtirb.Section`\\\\s\n            in the binary.\n        :param symbols: A set containing all the :class:`gtirb.Symbol`\\\\s\n            in the binary.\n        :param entry_point: A :class:`CodeBlock` representing where\n            control flow of this module begins at, or None if not present.\n        :param uuid: The UUID of this ``Module``,\n            or None if a new UUID needs generated via :func:`uuid.uuid4`.\n            Defaults to None.\n        :param ir: The :class:`IR` this module belongs to.\n        \"\"\"\n\n        self._symbol_name_index: typing.MutableMapping[\n            str, typing.Set[Symbol]\n        ] = collections.defaultdict(set)\n        self._symbol_referent_index: typing.MutableMapping[\n            \"Block\", typing.Set[Symbol]\n        ] = collections.defaultdict(set)\n        self._ir: typing.Optional[\"IR\"] = None\n        self.binary_path = binary_path\n        self.isa = isa\n        self.byte_order = byte_order\n        self.file_format = file_format\n        self.name = name\n        self.preferred_addr = preferred_addr\n        self.proxies = Module._NodeSet(self, \"proxies\", proxies)\n        self.rebase_delta = rebase_delta\n        self.sections = Module._NodeSet(self, \"sections\", sections)\n        self.symbols = Module._NodeSet(self, \"symbols\", symbols)\n        self.entry_point = entry_point\n        # Initialize the aux data last so that the cache is populated\n        super().__init__(aux_data, uuid)\n\n        # Use the property setter to ensure correct invariants.\n        self.ir = ir\n\n    @classmethod\n    def _decode_protobuf(\n        cls,\n        proto_module: _NodeMessage,\n        uuid: UUID,\n        ir: typing.Optional[\"IR\"],\n    ) -> \"Module\":\n        assert ir\n        assert isinstance(proto_module, Module_pb2.Module)\n        m = cls(\n            binary_path=proto_module.binary_path,\n            isa=Module.ISA(proto_module.isa),\n            file_format=Module.FileFormat(proto_module.file_format),\n            name=proto_module.name,\n            preferred_addr=proto_module.preferred_addr,\n            rebase_delta=proto_module.rebase_delta,\n            byte_order=Module.ByteOrder(proto_module.byte_order),\n            uuid=uuid,\n        )\n        m._add_to_uuid_cache(ir._local_uuid_cache)\n\n        # proxies depend on nothing\n        m.proxies.update(\n            ProxyBlock._from_protobuf(p, ir) for p in proto_module.proxies\n        )\n        # sections depend on symbolic expressions, so that step is split out\n        # from _decode_protobuf into _decode_symbolic_expressions\n        m.sections.update(\n            Section._from_protobuf(s, ir) for s in proto_module.sections\n        )\n        # entry point is a code block, which depends on sections\n        m.entry_point = None\n        if proto_module.entry_point:\n            entry_point_uuid = UUID(bytes=proto_module.entry_point)\n            entry_point = ir.get_by_uuid(entry_point_uuid)\n            if not isinstance(entry_point, CodeBlock):\n                raise DeserializationError(\n                    \"Module: entry block UUID %s is not a CodeBlock\"\n                    % entry_point_uuid\n                )\n            m.entry_point = entry_point\n        # symbols depend on blocks\n        m.symbols.update(\n            Symbol._from_protobuf(s, ir) for s in proto_module.symbols\n        )\n        # symbolic expressions depend on symbols\n        for section in m.sections:\n            for interval in section.byte_intervals:\n                interval._decode_symbolic_expressions(ir)\n        # aux data may depend on any node\n        m.aux_data.update(\n            AuxDataContainer._read_protobuf_aux_data(proto_module.aux_data, ir)\n        )\n\n        return m\n\n    def _to_protobuf(self) -> Module_pb2.Module:\n        proto_module = Module_pb2.Module()\n        self._write_protobuf_aux_data(proto_module.aux_data)\n        proto_module.binary_path = self.binary_path\n        proto_module.isa = self.isa.value\n        proto_module.file_format = self.file_format.value\n        proto_module.name = self.name\n        proto_module.preferred_addr = self.preferred_addr\n        proto_module.proxies.extend(p._to_protobuf() for p in self.proxies)\n        proto_module.rebase_delta = self.rebase_delta\n        proto_module.sections.extend(s._to_protobuf() for s in self.sections)\n        proto_module.symbols.extend(s._to_protobuf() for s in self.symbols)\n        if self.entry_point is not None:\n            proto_module.entry_point = self.entry_point.uuid.bytes\n        proto_module.byte_order = self.byte_order.value\n        proto_module.uuid = self.uuid.bytes\n        return proto_module\n\n    def deep_eq(self, other: object) -> bool:\n        # Do not move __eq__. See docstring for Node.deep_eq for more info.\n        if not super().deep_eq(other):\n            return False\n        if not isinstance(other, Module):\n            return False\n        for attr in (\n            \"binary_path\",\n            \"isa\",\n            \"byte_order\",\n            \"file_format\",\n            \"name\",\n            \"preferred_addr\",\n            \"rebase_delta\",\n        ):\n            if getattr(self, attr) != getattr(other, attr):\n                return False\n\n        for attr in (\"proxies\", \"sections\", \"symbols\"):\n            self_nodes = sorted(getattr(self, attr), key=lambda n: n.uuid)\n            other_nodes = sorted(getattr(other, attr), key=lambda n: n.uuid)\n            if not len(self_nodes) == len(other_nodes):\n                return False\n            for self_node, other_node in zip(self_nodes, other_nodes):\n                if not self_node.deep_eq(other_node):\n                    return False\n\n        if self.entry_point is None:\n            if other.entry_point is not None:\n                return False\n        else:\n            if not self.entry_point.deep_eq(other.entry_point):\n                return False\n\n        return True\n\n    def __repr__(self) -> str:\n        return (\n            \"Module(\"\n            \"uuid={uuid!r}, \"\n            \"name={name!r}, \"\n            \"binary_path={binary_path!r}, \"\n            \"isa=Module.{isa!s}, \"\n            \"byte_order=Module.{byte_order!s}, \"\n            \"file_format=Module.{file_format!s}, \"\n            \"preferred_addr={preferred_addr:#x}, \"\n            \"rebase_delta={rebase_delta:#x}, \"\n            \"proxies={proxies!r}, \"\n            \"sections={sections!r}, \"\n            \"symbols={symbols!r}, \"\n            \"entry_point={entry_point!r}, \"\n            \")\".format(**self.__dict__)\n        )\n\n    def _index_add(\n        self, node: typing.Union[ProxyBlock, Section, Symbol]\n    ) -> None:\n        if isinstance(node, Symbol):\n            self._symbol_name_index[node.name].add(node)\n            if node.referent:\n                self._symbol_referent_index[node.referent].add(node)\n\n    def _index_discard(\n        self, node: typing.Union[ProxyBlock, Section, Symbol]\n    ) -> None:\n        if isinstance(node, Symbol):\n            symbol_set = self._symbol_name_index[node.name]\n            symbol_set.discard(node)\n            if not symbol_set:\n                del self._symbol_name_index[node.name]\n\n            if node.referent:\n                symbol_set = self._symbol_referent_index[node.referent]\n                symbol_set.discard(node)\n                if not symbol_set:\n                    del self._symbol_referent_index[node.referent]\n\n    def symbols_named(self, name: str) -> typing.Iterator[Symbol]:\n        \"Finds all symbols with a given name.\"\n        symbols = self._symbol_name_index.get(name, None)\n        if symbols:\n            yield from symbols\n\n    @property\n    def ir(self) -> typing.Optional[\"IR\"]:\n        \"\"\"The :class:`IR` this module belongs to.\"\"\"\n\n        return self._ir\n\n    @ir.setter\n    def ir(self, value: typing.Optional[\"IR\"]) -> None:\n        if self._ir is not None:\n            self._ir.modules.remove(self)\n        if value is not None:\n            value.modules.append(self)\n\n    @property\n    def byte_intervals(self) -> typing.Iterator[ByteInterval]:\n        \"\"\"The :class:`ByteInterval`\\\\s in this module.\"\"\"\n\n        return itertools.chain.from_iterable(\n            s.byte_intervals for s in self.sections\n        )\n\n    @property\n    def byte_blocks(self) -> typing.Iterator[ByteBlock]:\n        \"\"\"The :class:`ByteBlock`\\\\s in this module.\"\"\"\n\n        return itertools.chain.from_iterable(\n            s.byte_blocks for s in self.sections\n        )\n\n    @property\n    def code_blocks(self) -> typing.Iterator[CodeBlock]:\n        \"\"\"The :class:`CodeBlock`\\\\s in this module.\"\"\"\n\n        return itertools.chain.from_iterable(\n            s.code_blocks for s in self.sections\n        )\n\n    @property\n    def data_blocks(self) -> typing.Iterator[DataBlock]:\n        \"\"\"The :class:`DataBlock`\\\\s in this module.\"\"\"\n\n        return itertools.chain.from_iterable(\n            s.data_blocks for s in self.sections\n        )\n\n    @property\n    def cfg_nodes(self) -> typing.Iterator[CfgNode]:\n        \"\"\"The :class:`CfgNode`\\\\s in this module.\"\"\"\n\n        return itertools.chain(self.code_blocks, self.proxies)\n\n    def sections_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[Section]:\n        \"\"\"Finds all the sections that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return nodes_on(self.sections, addrs)\n\n    def sections_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[Section]:\n        \"\"\"Finds all the sections that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return nodes_at(self.sections, addrs)\n\n    def byte_intervals_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[ByteInterval]:\n        \"\"\"Finds all the byte intervals that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            s.byte_intervals_on(addrs) for s in self.sections\n        )\n\n    def byte_intervals_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[ByteInterval]:\n        \"\"\"Finds all the byte intervals that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            s.byte_intervals_at(addrs) for s in self.sections\n        )\n\n    def byte_blocks_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[ByteBlock]:\n        \"\"\"Finds all the byte blocks that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            s.byte_blocks_on(addrs) for s in self.sections\n        )\n\n    def byte_blocks_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[ByteBlock]:\n        \"\"\"Finds all the byte blocks that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            s.byte_blocks_at(addrs) for s in self.sections\n        )\n\n    def code_blocks_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[CodeBlock]:\n        \"\"\"Finds all the code blocks that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            s.code_blocks_on(addrs) for s in self.sections\n        )\n\n    def code_blocks_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[CodeBlock]:\n        \"\"\"Finds all the code blocks that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            s.code_blocks_at(addrs) for s in self.sections\n        )\n\n    def data_blocks_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[DataBlock]:\n        \"\"\"Finds all the data blocks that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            s.data_blocks_on(addrs) for s in self.sections\n        )\n\n    def data_blocks_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[DataBlock]:\n        \"\"\"Finds all the data blocks that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return itertools.chain.from_iterable(\n            s.data_blocks_at(addrs) for s in self.sections\n        )\n\n    def symbolic_expressions_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[SymbolicExpressionElement]:\n        \"\"\"Finds all the symbolic expressions that begin at an address or\n        range of addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        :returns: Yields ``(interval, offset, symexpr)`` tuples for every\n            symbolic expression in the range.\n        \"\"\"\n\n        return symbolic_expressions_at(self.sections, addrs)\n\n    def _add_to_uuid_cache(self, cache: typing.Dict[UUID, Node]) -> None:\n        \"\"\"Update the UUID cache when this node is added.\"\"\"\n\n        cache[self.uuid] = self\n        for proxy in self.proxies:\n            proxy._add_to_uuid_cache(cache)\n        for section in self.sections:\n            section._add_to_uuid_cache(cache)\n        for symbol in self.symbols:\n            symbol._add_to_uuid_cache(cache)\n\n    def _remove_from_uuid_cache(self, cache: typing.Dict[UUID, Node]) -> None:\n        \"\"\"Update the UUID cache when this node is removed.\"\"\"\n\n        del cache[self.uuid]\n        for proxy in self.proxies:\n            proxy._remove_from_uuid_cache(cache)\n        for section in self.sections:\n            section._remove_from_uuid_cache(cache)\n        for symbol in self.symbols:\n            symbol._remove_from_uuid_cache(cache)\n"
  },
  {
    "path": "python/gtirb/node.py",
    "content": "import typing\nfrom uuid import UUID, uuid4\n\nimport typing_extensions\nfrom google.protobuf.message import Message\n\nfrom .util import DeserializationError\n\nif typing.TYPE_CHECKING:  # pragma: no cover\n    # Ignore flake8 \"imported but unused\" errors.\n    from .ir import IR  # noqa: F401\n\n\n_T = typing.TypeVar(\"_T\", bound=\"Node\")\n\n\nclass _NodeMessage(typing_extensions.Protocol):\n    uuid: bytes\n\n\nclass Node:\n    \"\"\"A Node is any GTIRB object which can be referenced by UUID.\n\n    :ivar ~.uuid: The UUID of this Node.\n    \"\"\"\n\n    def __init__(self, uuid: typing.Optional[UUID] = None) -> None:\n        \"\"\"\n        :param uuid: The UUID of this ``Node``,\n            or None if a new UUID needs generated via :func:`uuid.uuid4`.\n            Defaults to None.\n        \"\"\"\n\n        if uuid is None:\n            uuid = uuid4()\n        self.uuid = uuid\n\n    @classmethod\n    def _decode_protobuf(\n        cls: typing.Type[_T],\n        proto_object: _NodeMessage,\n        uuid: UUID,\n        ir: typing.Optional[\"IR\"],\n    ) -> _T:\n        \"\"\"Decode a Protobuf object to a Python GTIRB object.\n        Must be overridden by subclasses.\n\n        :param proto_object: The Protobuf object.\n        :param uuid: The UUID of the object.\n        \"\"\"\n\n        raise NotImplementedError  # pragma: no cover\n\n    @classmethod\n    def _from_protobuf(\n        cls: typing.Type[_T],\n        proto_object: _NodeMessage,\n        ir: typing.Optional[\"IR\"],\n    ) -> _T:\n        \"\"\"Deserialize a Node from Protobuf.\n\n        Performs a cache lookup for the object's UUID in the cache, calling the\n        class' _decode_protobuf constructor if cannot find it.\n        \"\"\"\n\n        uuid = UUID(bytes=proto_object.uuid)\n        node = None\n        if ir is not None:\n            cached_node = ir.get_by_uuid(uuid)\n            if isinstance(cached_node, cls):\n                node = cached_node\n            elif cached_node is not None:\n                raise DeserializationError(\n                    \"got %s for UUID %s but expected %s\"\n                    % (type(cached_node).__name__, uuid, cls.__name__)\n                )\n        if node is None:\n            node = cls._decode_protobuf(proto_object, uuid, ir)\n        return node\n\n    def _to_protobuf(self) -> Message:\n        \"\"\"Get a Protobuf representation of ``self``.\n        Must be overridden by subclasses.\n        \"\"\"\n\n        raise NotImplementedError  # pragma: no cover\n\n    def deep_eq(self, other: object) -> bool:\n        \"\"\"Check: is ``self`` structurally equal to ``other``?\n\n        This method should be used only when deep structural equality checks\n        are actually needed, and not for all equality checks. Typically the\n        default implmentation of __eq__, which checks pointer equality, is\n        sufficient; Nodes are cached such that references to two Nodes with\n        the same UUID refer to the same exact object. Use this method when\n        you have manually constructed Nodes that may share the same UUID\n        despite being different objects, and you need to check for structural\n        equality.\n        \"\"\"\n\n        raise NotImplementedError  # pragma: no cover\n"
  },
  {
    "path": "python/gtirb/offset.py",
    "content": "from typing import TYPE_CHECKING, NamedTuple, Optional, Union\nfrom uuid import UUID\n\nfrom .node import Node\nfrom .proto import Offset_pb2\nfrom .util import DeserializationError\n\nif TYPE_CHECKING:  # pragma: no cover\n    # Ignore flake8 \"imported but unused\" errors.\n    from .ir import IR  # noqa: F401\n\n\nclass Offset(\n    NamedTuple(\n        \"NamedTuple\",\n        ((\"element_id\", Union[UUID, Node]), (\"displacement\", int)),\n    )\n):\n    \"\"\"\n    An Offset describes a location inside a :class:`gtirb.Node`, such as a\n    :class:`gtirb.DataBlock` or :class:`gtirb.ByteInterval`.\n\n    :ivar ~.element_id: The :class:`gtirb.Node` containing the location of\n            interest.\n    :ivar ~.displacement: The offset inside the Node to point to.\n    \"\"\"\n\n    @classmethod\n    def _from_protobuf(\n        cls, offset: Offset_pb2.Offset, ir: Optional[\"IR\"]\n    ) -> \"Offset\":\n        \"\"\"Decode a Protobuf object to an offset.\n\n        :param offset: The Protobuf object.\n        \"\"\"\n\n        assert ir\n        element_id = UUID(bytes=offset.element_id)\n        element = ir.get_by_uuid(element_id)\n        if not element:\n            raise DeserializationError(\n                \"Offset: UUID %s does not refer to a Node\" % element_id\n            )\n        return cls(element, offset.displacement)\n\n    def _to_protobuf(self) -> Offset_pb2.Offset:\n        \"\"\"Encode this offset into a Protobuf object.\"\"\"\n\n        proto_offset = Offset_pb2.Offset()\n        if isinstance(self.element_id, UUID):\n            proto_offset.element_id = self.element_id.bytes\n        else:\n            proto_offset.element_id = self.element_id.uuid.bytes\n        proto_offset.displacement = self.displacement\n        return proto_offset\n"
  },
  {
    "path": "python/gtirb/proto/__init__.py",
    "content": ""
  },
  {
    "path": "python/gtirb/section.py",
    "content": "import itertools\nimport typing\nfrom enum import Enum\nfrom uuid import UUID\n\nfrom .block import ByteBlock, CodeBlock, DataBlock\nfrom .byteinterval import ByteInterval, SymbolicExpressionElement\nfrom .lazyintervaltree import LazyIntervalTree\nfrom .node import Node, _NodeMessage\nfrom .proto import Section_pb2\nfrom .util import (\n    SetWrapper,\n    _address_interval,\n    _nodes_at_interval_tree,\n    _nodes_on_interval_tree,\n)\n\nif typing.TYPE_CHECKING:  # pragma: no cover\n    # Ignore flake8 \"imported but unused\" errors.\n    from .ir import IR  # noqa: F401\n    from .module import Module  # noqa: F401\n\n\nclass Section(Node):\n    \"\"\"Represents a named section of the binary.\n\n    Does not directly store the contents of the section, which are\n    kept in a :class:`gtirb.ImageByteMap`.\n\n    :ivar ~.name: The section name (E.g. \".text\", \".bss\", etc).\n    :ivar ~.byte_intervals: The :class:`ByteInterval`\\\\s in this section.\n    :ivar ~.flags: The :class:`Section.Flag`\\\\s this section has.\n    \"\"\"\n\n    class Flag(Enum):\n        \"\"\"A flag representing a known property of a section.\"\"\"\n\n        Undefined = Section_pb2.SectionFlag.Value(\"Section_Undefined\")\n        \"\"\"This value is defined for Protobuf compatibility. Do not use.\"\"\"\n\n        Readable = Section_pb2.SectionFlag.Value(\"Readable\")\n        \"\"\"This section can be read from at runtime.\"\"\"\n\n        Writable = Section_pb2.SectionFlag.Value(\"Writable\")\n        \"\"\"This section can be written to at runtime.\"\"\"\n\n        Executable = Section_pb2.SectionFlag.Value(\"Executable\")\n        \"\"\"This section contains executable code.\"\"\"\n\n        Loaded = Section_pb2.SectionFlag.Value(\"Loaded\")\n        \"\"\"This section is present in memory at runtime.\"\"\"\n\n        Initialized = Section_pb2.SectionFlag.Value(\"Initialized\")\n        \"\"\"This section has bytes allocated to it in the binary file.\"\"\"\n\n        ThreadLocal = Section_pb2.SectionFlag.Value(\"ThreadLocal\")\n        \"\"\"This section is created in memory once per thread.\"\"\"\n\n    class _ByteIntervalSet(SetWrapper[ByteInterval]):\n        def __init__(\n            self, node: \"Section\", *args: typing.Iterable[ByteInterval]\n        ):\n            self._node = node\n            super().__init__(*args)\n\n        def add(self, v: ByteInterval) -> None:\n            if v._section is not None:\n                v._section.byte_intervals.discard(v)\n            self._node._index_add(v)\n            v._section = self._node\n            if self._node.ir is not None:\n                v._add_to_uuid_cache(self._node.ir._local_uuid_cache)\n            return super().add(v)\n\n        def discard(self, v: ByteInterval) -> None:\n            if v not in self:\n                return\n            self._node._index_discard(v)\n            v._section = None\n            if self._node.ir is not None:\n                v._remove_from_uuid_cache(self._node.ir._local_uuid_cache)\n            return super().discard(v)\n\n    def __init__(\n        self,\n        *,\n        name: str = \"\",\n        byte_intervals: typing.Iterable[ByteInterval] = (),\n        flags: typing.Iterable[\"Section.Flag\"] = set(),\n        uuid: typing.Optional[UUID] = None,\n        module: typing.Optional[\"Module\"] = None,\n    ):\n        \"\"\"\n        :param name: The name of this section.\n        :param byte_intervals: The :class:`ByteInterval`\\\\s in this section.\n        :param flags: The :class:`Section.Flag`\\\\s this section has.\n        :param uuid: The UUID of this ``Section``,\n            or None if a new UUID needs generated via :func:`uuid.uuid4`.\n            Defaults to None.\n        :param module: The :class:`Module` this section belongs to.\n        \"\"\"\n\n        super().__init__(uuid)\n        self._module: typing.Optional[\"Module\"] = None\n        self.name = name\n\n        # Both byte_intervals and _interval_index must exist before adding any\n        # intervals.\n        self.byte_intervals = Section._ByteIntervalSet(self)\n        self._interval_index = LazyIntervalTree[int, ByteInterval](\n            self.byte_intervals, _address_interval\n        )\n        self.byte_intervals.update(byte_intervals)\n\n        self.flags = set(flags)\n\n        # Use the property setter to ensure correct invariants.\n        self.module = module\n\n    def _index_add(self, byte_interval: ByteInterval) -> None:\n        self._interval_index.add(byte_interval)\n\n    def _index_discard(self, byte_interval: ByteInterval) -> None:\n        self._interval_index.discard(byte_interval)\n\n    @classmethod\n    def _decode_protobuf(\n        cls,\n        proto_section: _NodeMessage,\n        uuid: UUID,\n        ir: typing.Optional[\"IR\"],\n    ) -> \"Section\":\n        assert ir\n        assert isinstance(proto_section, Section_pb2.Section)\n        s = cls(\n            name=proto_section.name,\n            flags=(Section.Flag(f) for f in proto_section.section_flags),\n            uuid=uuid,\n        )\n        s._add_to_uuid_cache(ir._local_uuid_cache)\n        s.byte_intervals.update(\n            ByteInterval._from_protobuf(bi, ir)\n            for bi in proto_section.byte_intervals\n        )\n        return s\n\n    def _to_protobuf(self) -> Section_pb2.Section:\n        \"\"\"Get a Protobuf representation of ``self``.\"\"\"\n\n        proto_section = Section_pb2.Section()\n        proto_section.uuid = self.uuid.bytes\n        proto_section.name = self.name\n        proto_section.byte_intervals.extend(\n            bi._to_protobuf() for bi in self.byte_intervals\n        )\n        proto_section.section_flags.extend(f.value for f in self.flags)\n        return proto_section\n\n    def deep_eq(self, other: object) -> bool:\n        # Do not move __eq__. See docstring for Node.deep_eq for more info.\n        if not isinstance(other, Section):\n            return False\n        return (\n            self.uuid == other.uuid\n            and self.name == other.name\n            and len(self.byte_intervals) == len(other.byte_intervals)\n            and all(\n                self_node.deep_eq(other_node)\n                for self_node, other_node in zip(\n                    sorted(self.byte_intervals, key=lambda bi: bi.uuid),\n                    sorted(other.byte_intervals, key=lambda bi: bi.uuid),\n                )\n            )\n            and self.flags == other.flags\n        )\n\n    def __repr__(self) -> str:\n        return (\n            \"Section(\"\n            \"uuid={uuid!r}, \"\n            \"name={name!r}, \"\n            \"byte_intervals={byte_intervals!r}, \"\n            \"flags=({pretty_flags}), \"\n            \")\".format(\n                pretty_flags=\", \".join(\n                    \"Section.\" + str(f) for f in self.flags\n                ),\n                **self.__dict__,\n            )\n        )\n\n    @property\n    def module(self) -> typing.Optional[\"Module\"]:\n        \"\"\"The :class:`Module` this section belongs to.\"\"\"\n\n        return self._module\n\n    @module.setter\n    def module(self, value: typing.Optional[\"Module\"]) -> None:\n        if self._module is not None:\n            self._module.sections.discard(self)\n        if value is not None:\n            value.sections.add(self)\n\n    @property\n    def byte_blocks(self) -> typing.Iterator[ByteBlock]:\n        \"\"\"The :class:`ByteBlock`\\\\s in this section.\"\"\"\n\n        return itertools.chain.from_iterable(\n            bi.blocks for bi in self.byte_intervals\n        )\n\n    @property\n    def code_blocks(self) -> typing.Iterator[CodeBlock]:\n        \"\"\"The :class:`CodeBlock`\\\\s in this section.\"\"\"\n\n        return (b for b in self.byte_blocks if isinstance(b, CodeBlock))\n\n    @property\n    def data_blocks(self) -> typing.Iterator[DataBlock]:\n        \"\"\"The :class:`DataBlock`\\\\s in this section.\"\"\"\n\n        return (b for b in self.byte_blocks if isinstance(b, DataBlock))\n\n    @property\n    def address(self) -> typing.Optional[int]:\n        \"\"\"Get the address of this section, if known.\n\n        The address is calculated from the :class:`ByteInterval` objects in\n        this section. More specifically, if the address of all byte intervals\n        in this section are fixed, then it will return the address of the\n        interval lowest in memory. If any one interval does not have an address\n        then this will be ``None``, as the address is not calculable in that\n        case. Note that a section with no intervals in it has no address or\n        size, so it will be ``None`` in that case.\n        \"\"\"\n\n        index = self._interval_index.get()\n        if 0 < len(index) == len(self.byte_intervals):\n            return index.begin()\n\n        return None\n\n    @property\n    def size(self) -> typing.Optional[int]:\n        \"\"\"Get the size of this section, if known.\n\n        The address is calculated from the :class:`ByteInterval` objects in\n        this section. More specifically, if the address of all byte intervals\n        in this section are fixed, then it will return the difference between\n        the lowest and highest address among the intervals. If any one interval\n        does not have an address, then this will be ``None``, as the size is\n        not calculable in that case. Note that a section with no intervals in\n        it has no address or size, so it will be ``None`` in that case.\n        \"\"\"\n\n        index = self._interval_index.get()\n        if 0 < len(index) == len(self.byte_intervals):\n            return index.span() - 1\n\n        return None\n\n    def byte_intervals_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[ByteInterval]:\n        \"\"\"Finds all the byte intervals that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return _nodes_on_interval_tree(self._interval_index.get(), addrs)\n\n    def byte_intervals_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[ByteInterval]:\n        \"\"\"Finds all the byte intervals that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return _nodes_at_interval_tree(self._interval_index.get(), addrs)\n\n    def byte_blocks_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[ByteBlock]:\n        \"\"\"Finds all the byte blocks that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        for interval in self.byte_intervals_on(addrs):\n            yield from interval.byte_blocks_on(addrs)\n\n    def byte_blocks_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[ByteBlock]:\n        \"\"\"Finds all the byte blocks that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        for interval in self.byte_intervals_on(addrs):\n            yield from interval.byte_blocks_at(addrs)\n\n    def code_blocks_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[CodeBlock]:\n        \"\"\"Finds all the code blocks that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return (\n            block\n            for block in self.byte_blocks_on(addrs)\n            if isinstance(block, CodeBlock)\n        )\n\n    def code_blocks_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[CodeBlock]:\n        \"\"\"Finds all the code blocks that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return (\n            block\n            for block in self.byte_blocks_at(addrs)\n            if isinstance(block, CodeBlock)\n        )\n\n    def data_blocks_on(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[DataBlock]:\n        \"\"\"Finds all the data blocks that overlap an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return (\n            block\n            for block in self.byte_blocks_on(addrs)\n            if isinstance(block, DataBlock)\n        )\n\n    def data_blocks_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[DataBlock]:\n        \"\"\"Finds all the data blocks that begin at an address or range of\n        addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        \"\"\"\n\n        return (\n            block\n            for block in self.byte_blocks_at(addrs)\n            if isinstance(block, DataBlock)\n        )\n\n    def symbolic_expressions_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[SymbolicExpressionElement]:\n        \"\"\"Finds all the symbolic expressions that begin at an address or\n        range of addresses.\n\n        :param addrs: Either a ``range`` object or a single address.\n        :returns: Yields ``(interval, offset, symexpr)`` tuples for every\n            symbolic expression in the range.\n        \"\"\"\n\n        for interval in self.byte_intervals_on(addrs):\n            yield from interval.symbolic_expressions_at(addrs)\n\n    def _add_to_uuid_cache(self, cache: typing.Dict[UUID, Node]) -> None:\n        \"\"\"Update the UUID cache when this node is added.\"\"\"\n\n        cache[self.uuid] = self\n        for bi in self.byte_intervals:\n            bi._add_to_uuid_cache(cache)\n\n    def _remove_from_uuid_cache(self, cache: typing.Dict[UUID, Node]) -> None:\n        \"\"\"Update the UUID cache when this node is removed.\"\"\"\n\n        del cache[self.uuid]\n        for bi in self.byte_intervals:\n            bi._remove_from_uuid_cache(cache)\n\n    @property\n    def ir(self) -> typing.Optional[\"IR\"]:\n        \"\"\"Get the IR this node ultimately belongs to.\"\"\"\n        if self.module is None:\n            return None\n        return self.module.ir\n"
  },
  {
    "path": "python/gtirb/serialization.py",
    "content": "import io\nimport struct\nfrom re import findall\nfrom typing import (\n    Any,\n    BinaryIO,\n    Callable,\n    Collection,\n    Dict,\n    Iterable,\n    Mapping,\n    Optional,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    Union,\n)\nfrom uuid import UUID\n\nfrom .node import Node\nfrom .offset import Offset\n\nCacheLookupFn = Optional[Callable[[UUID], Optional[Node]]]\n\n\nclass CodecError(Exception):\n    \"\"\"Base class for codec exceptions.\"\"\"\n\n\nclass DecodeError(CodecError):\n    \"\"\"An exception during decoding.\"\"\"\n\n\nclass EncodeError(CodecError):\n    \"\"\"An exception during encoding.\"\"\"\n\n\nclass TypeNameError(EncodeError):\n    \"\"\"A type name is malformed.\"\"\"\n\n    def __init__(self, hint: str) -> None:\n        super().__init__(\"malformed type name: '%s'\" % (hint))\n\n\nclass UnknownCodecError(CodecError):\n    \"\"\"An unknown codec name is encountered.\n    Caught and handled by the top-level codec methods.\n\n    :param name: the name of the unknown codec\n    \"\"\"\n\n    def __init__(self, name: str) -> None:\n        self.name = name\n\n\nclass SubtypeTree:\n    \"\"\"A type hint representing a parsed serialization type name.\n    A ``SubtypeTree`` is has two items: A ``str`` giving\n    the name of the type and a Sequence of type parameters\n    (which are also ``SubtypeTree``\\\\s). For example, the following are all\n    valid ``SubtypeTree``\\\\s:\n\n    >>> SubtypeTree('string', ())\n    >>> SubtypeTree('sequence', (SubtypeTree('UUID',()),))\n    >>> SubtypeTree(\n        'mapping', (\n            SubtypeTree('string', ()),\n            SubtypeTree('set', (SubtypeTree('UUID', ()),))\n        )\n    )\n    \"\"\"\n\n    def __init__(self, name: str, subtypes: Sequence[\"SubtypeTree\"]) -> None:\n        self.name = name\n        self.subtypes = subtypes\n\n    def __eq__(self, other: object) -> bool:\n        if isinstance(other, SubtypeTree):\n            return self.name == other.name and self.subtypes == other.subtypes\n        if isinstance(other, tuple):\n            return (self.name, self.subtypes) == other\n        return False\n\n\nclass Variant:\n    # Because the Variant can contain arbitrary data, depending on the context\n    # in which it is used, it has type Any. This requires an exception to the\n    # project-wide mypy configuration that disallows Any.\n    def __init__(self, index: int, val: Any):  # type: ignore[misc]\n        self.index = index\n        self.val = val\n\n    def __eq__(self, other: object) -> bool:\n        if isinstance(other, Variant):\n            return self.index == other.index and self.val == other.val\n        return False\n\n\nclass Codec:\n    \"\"\"The base class for codecs.\"\"\"\n\n    @staticmethod\n    def decode(\n        raw_bytes: BinaryIO,\n        *,\n        serialization: \"Serialization\",\n        subtypes: Sequence[SubtypeTree],\n        get_by_uuid: CacheLookupFn = None,\n    ) -> object:\n        \"\"\"Decode the specified raw data into a Python object.\n\n        :param raw_bytes: The BytesIO object to be decoded.\n        :param serialization: A Serialization instance used to invoke\n            other codecs if needed.\n        :param subtypes: The parsed type of this object.\n        :param get_by_uuid: A function to look up nodes by UUID.\n        :returns: A new Python object, as decoded from ``raw_bytes``.\n        \"\"\"\n\n        raise NotImplementedError  # pragma: no cover\n\n    @staticmethod\n    def encode(\n        out: BinaryIO,\n        item: object,\n        *,\n        serialization: \"Serialization\",\n        subtypes: Sequence[SubtypeTree],\n    ) -> None:\n        \"\"\"Encode an item, writing the serialized object to ``out``.\n\n        :param out: A binary stream to serialize to.\n        :param item: The arbitrary Python object to encode.\n        :param serialization: A Serialization instance, used to invoke\n            other codecs if needed.\n        :param subtypes: The parsed type of this object.\n        \"\"\"\n\n        raise NotImplementedError  # pragma: no cover\n\n\nclass MappingCodec(Codec):\n    \"\"\"A Codec for mapping<K,V> entries. Implemented via ``dict``.\"\"\"\n\n    @staticmethod\n    def decode(\n        raw_bytes: BinaryIO,\n        *,\n        serialization: \"Serialization\",\n        subtypes: Sequence[SubtypeTree],\n        get_by_uuid: Optional[CacheLookupFn] = None,\n    ) -> Mapping[object, object]:\n        try:\n            key_type, val_type = subtypes\n        except (TypeError, ValueError):\n            raise DecodeError(\n                \"could not unpack mapping types: %s\" % str(subtypes)\n            )\n        mapping = dict()\n        mapping_len = Uint64Codec.decode(raw_bytes)\n        for _ in range(mapping_len):\n            key = serialization._decode_tree(raw_bytes, key_type, get_by_uuid)\n            val = serialization._decode_tree(raw_bytes, val_type, get_by_uuid)\n            mapping[key] = val\n        return mapping\n\n    @staticmethod\n    def encode(\n        out: BinaryIO,\n        mapping: object,\n        *,\n        serialization: \"Serialization\",\n        subtypes: Sequence[SubtypeTree],\n    ) -> None:\n        if not isinstance(mapping, Mapping):\n            raise EncodeError(\"Mapping codec only supports Mappings\")\n        try:\n            key_type, val_type = subtypes\n        except (TypeError, ValueError):\n            raise EncodeError(\n                \"could not unpack mapping types: %s\" % str(subtypes)\n            )\n        Uint64Codec.encode(out, len(mapping))\n        for key, val in mapping.items():\n            serialization._encode_tree(out, key, key_type)\n            serialization._encode_tree(out, val, val_type)\n\n\nclass OffsetCodec(Codec):\n    \"\"\"A Codec for :class:`gtirb.Offset` objects,\n    containing a UUID and a displacement.\n    \"\"\"\n\n    @staticmethod\n    def decode(\n        raw_bytes: BinaryIO,\n        *,\n        serialization: \"Serialization\" = None,\n        subtypes: Sequence[SubtypeTree] = (),\n        get_by_uuid: Optional[CacheLookupFn] = None,\n    ) -> Offset:\n        if subtypes != ():\n            raise DecodeError(\"Offset should have no subtypes\")\n        element_uuid = UUIDCodec.decode(raw_bytes, get_by_uuid=get_by_uuid)\n        displacement = Uint64Codec.decode(raw_bytes)\n\n        return Offset(element_uuid, displacement)\n\n    @staticmethod\n    def encode(\n        out: BinaryIO,\n        val: object,\n        *,\n        serialization: \"Serialization\" = None,\n        subtypes: Sequence[SubtypeTree] = (),\n    ) -> None:\n        if not isinstance(val, Offset):\n            raise EncodeError(\"Offset codec only supports Offsets\")\n        if subtypes != ():\n            raise EncodeError(\"Offset should have no subtypes\")\n        UUIDCodec.encode(out, val.element_id)\n        Uint64Codec.encode(out, val.displacement)\n\n\nclass SequenceCodec(Codec):\n    \"\"\"A Codec for sequence<T> entries. Implemented via ``list``.\"\"\"\n\n    @staticmethod\n    def decode(\n        raw_bytes: BinaryIO,\n        *,\n        serialization: \"Serialization\",\n        subtypes: Sequence[SubtypeTree],\n        get_by_uuid: Optional[CacheLookupFn] = None,\n    ) -> Sequence[object]:\n        try:\n            (subtype,) = subtypes\n        except (TypeError, ValueError) as e:\n            raise DecodeError(\"could not unpack sequence type: %s\" % str(e))\n        sequence = list()\n        sequence_len = Uint64Codec.decode(raw_bytes)\n        for _ in range(sequence_len):\n            sequence.append(\n                serialization._decode_tree(raw_bytes, subtype, get_by_uuid)\n            )\n        return sequence\n\n    @staticmethod\n    def encode(\n        out: BinaryIO,\n        sequence: object,\n        *,\n        serialization: \"Serialization\",\n        subtypes: Sequence[SubtypeTree],\n    ) -> None:\n        if not isinstance(sequence, Sequence):\n            raise EncodeError(\"Sequence codec only supports Collections\")\n        try:\n            (subtype,) = subtypes\n        except (TypeError, ValueError) as e:\n            raise EncodeError(\"could not unpack sequence type: %s\" % str(e))\n        Uint64Codec.encode(out, len(sequence))\n        for item in sequence:\n            serialization._encode_tree(out, item, subtype)\n\n\nclass SetCodec(Codec):\n    \"\"\"A Codec for set<T> entries. Implemented via ``set``.\"\"\"\n\n    @staticmethod\n    def decode(\n        raw_bytes: BinaryIO,\n        *,\n        serialization: \"Serialization\",\n        subtypes: Sequence[SubtypeTree],\n        get_by_uuid: Optional[CacheLookupFn] = None,\n    ) -> Set[object]:\n        try:\n            (subtype,) = subtypes\n        except (TypeError, ValueError) as e:\n            raise DecodeError(\"could not unpack set type: %s\" % str(e))\n        decoded_set = set()\n        set_len = Uint64Codec.decode(raw_bytes)\n        for _ in range(set_len):\n            decoded_set.add(\n                serialization._decode_tree(raw_bytes, subtype, get_by_uuid)\n            )\n        return decoded_set\n\n    @staticmethod\n    def encode(\n        out: BinaryIO,\n        items: object,\n        *,\n        serialization: \"Serialization\",\n        subtypes: Sequence[SubtypeTree],\n    ) -> None:\n        if not isinstance(items, Collection):\n            raise EncodeError(\"Set codec only supports Collections\")\n        try:\n            (subtype,) = subtypes\n        except (TypeError, ValueError) as e:\n            raise EncodeError(\"could not unpack set type: %s\" % str(e))\n        Uint64Codec.encode(out, len(items))\n        for item in items:\n            serialization._encode_tree(out, item, subtype)\n\n\nclass TupleCodec(Codec):\n    \"\"\"A Codec for tuple<...> entries. Implemented via ``tuple``.\"\"\"\n\n    @staticmethod\n    def decode(\n        raw_bytes: BinaryIO,\n        *,\n        serialization: \"Serialization\",\n        subtypes: Sequence[SubtypeTree],\n        get_by_uuid: Optional[CacheLookupFn] = None,\n    ) -> Tuple[object, ...]:\n        # The length of a tuple is not contained in the Protobuf\n        # representation, so error checking cannot be done here.\n        decoded_list = list()\n        for subtype in subtypes:\n            decoded_list.append(\n                serialization._decode_tree(raw_bytes, subtype, get_by_uuid)\n            )\n        return tuple(decoded_list)\n\n    @staticmethod\n    def encode(\n        out: BinaryIO,\n        items: object,\n        *,\n        serialization: \"Serialization\",\n        subtypes: Sequence[SubtypeTree],\n    ) -> None:\n        if not isinstance(items, Collection):\n            raise EncodeError(\"Tuple codec only supports Collections\")\n        if len(items) != len(subtypes):\n            raise EncodeError(\"length of tuple does not match subtype count\")\n        for item, subtype in zip(items, subtypes):\n            serialization._encode_tree(out, item, subtype)\n\n\nclass StringCodec(Codec):\n    \"\"\"A Codec for strings.\"\"\"\n\n    @staticmethod\n    def decode(\n        raw_bytes: BinaryIO,\n        *,\n        serialization: \"Serialization\" = None,\n        subtypes: Sequence[SubtypeTree] = (),\n        get_by_uuid: Optional[CacheLookupFn] = None,\n    ) -> str:\n        if subtypes != tuple():\n            raise DecodeError(\"string should have no subtypes\")\n        size = Uint64Codec.decode(raw_bytes)\n        return raw_bytes.read(size).decode(\"utf-8\")\n\n    @staticmethod\n    def encode(\n        out: BinaryIO,\n        val: object,\n        *,\n        serialization: \"Serialization\" = None,\n        subtypes: Sequence[SubtypeTree] = (),\n    ) -> None:\n        if not isinstance(val, str):\n            raise EncodeError(\"String codec only supports strings\")\n        if subtypes != ():\n            raise EncodeError(\"string should have no subtypes\")\n        Uint64Codec.encode(out, len(val))\n        out.write(val.encode())\n\n\nclass BoolCodec(Codec):\n    \"\"\"A Codec for bool.\"\"\"\n\n    @staticmethod\n    def decode(\n        raw_bytes: BinaryIO,\n        *,\n        serialization: \"Serialization\" = None,\n        subtypes: Sequence[SubtypeTree] = (),\n        get_by_uuid: Optional[CacheLookupFn] = None,\n    ) -> bool:\n        if subtypes != tuple():\n            raise DecodeError(\"bool should have no subtypes\")\n        return bool(raw_bytes.read(1) != b\"\\x00\")\n\n    @staticmethod\n    def encode(\n        out: BinaryIO,\n        val: object,\n        *,\n        serialization: \"Serialization\" = None,\n        subtypes: Sequence[SubtypeTree] = (),\n    ) -> None:\n        if not isinstance(val, bool):\n            raise EncodeError(\"Bool codec only supports bool\")\n        if subtypes != ():\n            raise EncodeError(\"bool should have no subtypes\")\n        out.write(bytes([val]))\n\n\nclass IntegerCodec(Codec):\n    \"\"\"Generic base class for integer-based Codecs\"\"\"\n\n    typname: str\n    bytesize: int\n    signed: bool\n\n    @classmethod\n    def decode(\n        cls,\n        raw_bytes: BinaryIO,\n        *,\n        serialization: \"Serialization\" = None,\n        subtypes: Sequence[SubtypeTree] = (),\n        get_by_uuid: Optional[CacheLookupFn] = None,\n    ) -> int:\n        if subtypes != ():\n            raise DecodeError(f\"{cls.typname} should have no subtypes\")\n        return int.from_bytes(\n            raw_bytes.read(cls.bytesize), byteorder=\"little\", signed=cls.signed\n        )\n\n    @classmethod\n    def encode(\n        cls,\n        out: BinaryIO,\n        val: object,\n        *,\n        serialization: \"Serialization\" = None,\n        subtypes: Sequence[SubtypeTree] = (),\n    ) -> None:\n        if not isinstance(val, int):\n            raise EncodeError(\"Integer codec only supports integers\")\n        if subtypes != ():\n            raise EncodeError(f\"{cls.typname} should have no subtypes\")\n        out.write(\n            val.to_bytes(cls.bytesize, byteorder=\"little\", signed=cls.signed)\n        )\n\n\nclass Uint64Codec(IntegerCodec):\n    \"\"\"A Codec for 64-bit unsigned integers.\"\"\"\n\n    typname = \"uint64_t\"\n    bytesize = 8\n    signed = False\n\n\nclass Uint32Codec(IntegerCodec):\n    \"\"\"A Codec for 32-bit unsigned integers.\"\"\"\n\n    typname = \"uint32_t\"\n    bytesize = 4\n    signed = False\n\n\nclass Uint16Codec(IntegerCodec):\n    \"\"\"A Codec for 16-bit unsigned integers.\"\"\"\n\n    typname = \"uint16_t\"\n    bytesize = 2\n    signed = False\n\n\nclass Uint8Codec(IntegerCodec):\n    \"\"\"A Codec for 8-bit unsigned integers.\"\"\"\n\n    typname = \"uint8_t\"\n    bytesize = 1\n    signed = False\n\n\nclass Int64Codec(IntegerCodec):\n    \"\"\"A Codec for 64-bit signed integers.\"\"\"\n\n    typname = \"int64_t\"\n    bytesize = 8\n    signed = True\n\n\nclass Int32Codec(IntegerCodec):\n    \"\"\"A Codec for 32-bit signed integers.\"\"\"\n\n    typname = \"int32_t\"\n    bytesize = 4\n    signed = True\n\n\nclass Int16Codec(IntegerCodec):\n    \"\"\"A Codec for 16-bit signed integers.\"\"\"\n\n    typname = \"int16_t\"\n    bytesize = 2\n    signed = True\n\n\nclass Int8Codec(IntegerCodec):\n    \"\"\"A Codec for 8-bit signed integers.\"\"\"\n\n    typname = \"int8_t\"\n    bytesize = 1\n    signed = True\n\n\nclass FloatCodec(Codec):\n    \"\"\"Generic base class for float-based Codecs\"\"\"\n\n    typname: str\n    bytesize: int\n    struct_format: str\n\n    @classmethod\n    def decode(\n        cls,\n        raw_bytes: BinaryIO,\n        *,\n        serialization: \"Serialization\" = None,\n        subtypes: Sequence[SubtypeTree] = (),\n        get_by_uuid: Optional[CacheLookupFn] = None,\n    ) -> float:\n        if subtypes != ():\n            raise DecodeError(f\"{cls.typname} should have no subtypes\")\n\n        return struct.unpack(cls.struct_format, raw_bytes.read(cls.bytesize))[\n            0\n        ]\n\n    @classmethod\n    def encode(\n        cls,\n        out: BinaryIO,\n        val: object,\n        *,\n        serialization: \"Serialization\" = None,\n        subtypes: Sequence[SubtypeTree] = (),\n    ) -> None:\n        if not isinstance(val, float):\n            raise EncodeError(\"Float codec only supports floats\")\n        if subtypes != ():\n            raise EncodeError(f\"{cls.typname} should have no subtypes\")\n\n        out.write(struct.pack(cls.struct_format, val))\n\n\nclass Float32Codec(FloatCodec):\n    typname = \"float\"\n    bytesize = 4\n    struct_format = \"<f\"\n\n\nclass Float64Codec(FloatCodec):\n    typname = \"double\"\n    bytesize = 8\n    struct_format = \"<d\"\n\n\nclass UUIDCodec(Codec):\n    \"\"\"A Codec for raw UUIDs or Nodes.\n\n    Decoding a UUID first checks the Node cache for an object with the\n    corresponding UUID, and either returns the object it hits or a new\n    raw UUID.\n    \"\"\"\n\n    @staticmethod\n    def decode(\n        raw_bytes: BinaryIO,\n        *,\n        serialization: \"Serialization\" = None,\n        subtypes: Sequence[SubtypeTree] = (),\n        get_by_uuid: Optional[CacheLookupFn] = None,\n    ) -> Union[UUID, Node]:\n        if subtypes != ():\n            raise DecodeError(\"UUID should have no subtypes\")\n        uuid = UUID(bytes=raw_bytes.read(16))\n        existing_node = None if get_by_uuid is None else get_by_uuid(uuid)\n        return uuid if existing_node is None else existing_node\n\n    @staticmethod\n    def encode(\n        out: BinaryIO,\n        val: object,\n        *,\n        serialization: \"Serialization\" = None,\n        subtypes: Sequence[SubtypeTree] = (),\n    ) -> None:\n        if subtypes != ():\n            raise EncodeError(\"UUID should have no subtypes\")\n        if isinstance(val, Node):\n            out.write(val.uuid.bytes)\n        elif isinstance(val, UUID):\n            out.write(val.bytes)\n        else:\n            raise EncodeError(\"UUID codec only supports UUIDs or Nodes\")\n\n\nclass VariantCodec(Codec):\n    \"\"\"A Codec for variant<Ts...> entries.\n\n    An encoded record containg two part:\n    index - position of member of variant's list\n    value - encoded values of selected member\n    \"\"\"\n\n    @staticmethod\n    def decode(\n        raw_bytes: BinaryIO,\n        *,\n        serialization: \"Serialization\",\n        subtypes: Sequence[SubtypeTree] = (),\n        get_by_uuid: Optional[CacheLookupFn] = None,\n    ) -> Variant:\n        index = int.from_bytes(\n            raw_bytes.read(8), byteorder=\"little\", signed=False\n        )\n        val = serialization._decode_tree(\n            raw_bytes, subtypes[index], get_by_uuid\n        )\n        return Variant(index, val)\n\n    @staticmethod\n    def encode(\n        out: BinaryIO,\n        variant: object,\n        *,\n        serialization: \"Serialization\",\n        subtypes: Sequence[SubtypeTree] = (),\n    ) -> None:\n        if not isinstance(variant, Variant):\n            raise EncodeError(\"Variant codec only supports variants\")\n        # variant is a named tuple containg index and value\n        # writing the index\n        out.write(variant.index.to_bytes(8, byteorder=\"little\"))\n        # writing the value\n        serialization._encode_tree(out, variant.val, subtypes[variant.index])\n\n\nclass UnknownData(bytes):\n    \"\"\"This class is a blob of bytes representing data with an unknown type.\n    Generated by :func:`gtirb.Serialization.decode` when it encounters\n    the name of an unknown codec. Use only at the top level of an auxdata.\n    \"\"\"\n\n\nclass Serialization:\n    \"\"\"Manages codecs used to serialize and deserialize GTIRB objects.\n\n    The :meth:`gtirb.Serialization.decode` method of\n    :attr:`gtirb.AuxData.serializer` is called when GTIRB AuxData is loaded via\n    :meth:`gtirb.IR.load_protobuf`, and the :meth:`gtirb.Serialization.encode`\n    method of :attr:`gtirb.AuxData.serializer` is called when GTIRB AuxData is\n    saved to file via :meth:`gtirb.IR.save_protobuf`. You can alter the\n    encoding and decoding of AuxData values via\n    :attr:`gtirb.Serialization.codecs`. To do this, create a new subclass of\n    :class:`gtirb.serialization.Codec` and add it to\n    :attr:`gtirb.Serialization.codecs`:\n\n    >>> gtirb.AuxData.serializer.codecs['my_custom_type'] = MyCustomCodec\n\n    This example registers a new type name, ``my_custom_type``, and associate\n    it with a new codec, ``MyCustomCodec``.\n\n    :ivar ~.codecs: A mapping of type names to codecs. Codecs can be added\n        or overridden using this dictionary.\n    \"\"\"\n\n    def __init__(self) -> None:\n        \"\"\"Initialize with the built-in `gtirb.serialization.Codec`\n        subclasses.\n        \"\"\"\n\n        self.codecs: Dict[str, Type[Codec]] = {\n            \"Addr\": Uint64Codec,\n            \"bool\": BoolCodec,\n            \"Offset\": OffsetCodec,\n            \"int64_t\": Int64Codec,\n            \"int32_t\": Int32Codec,\n            \"int16_t\": Int16Codec,\n            \"int8_t\": Int8Codec,\n            \"float\": Float32Codec,\n            \"double\": Float64Codec,\n            \"mapping\": MappingCodec,\n            \"sequence\": SequenceCodec,\n            \"set\": SetCodec,\n            \"string\": StringCodec,\n            \"tuple\": TupleCodec,\n            \"uint64_t\": Uint64Codec,\n            \"uint32_t\": Uint32Codec,\n            \"uint16_t\": Uint16Codec,\n            \"uint8_t\": Uint8Codec,\n            \"UUID\": UUIDCodec,\n            \"variant\": VariantCodec,\n        }\n\n    def _decode_tree(\n        self,\n        raw_bytes: BinaryIO,\n        type_tree: SubtypeTree,\n        get_by_uuid: CacheLookupFn,\n    ) -> object:\n        \"\"\"Decode the data in ``raw_bytes`` given a parsed type tree.\n\n        :param raw_bytes: The binary stream to read bytes from.\n        :param type_tree: The parsed type of the object encoded by\n            ``raw_bytes``.\n        \"\"\"\n\n        if type_tree.name not in self.codecs:\n            raise UnknownCodecError(type_tree.name)\n        codec = self.codecs[type_tree.name]\n        return codec.decode(\n            raw_bytes,\n            serialization=self,\n            subtypes=type_tree.subtypes,\n            get_by_uuid=get_by_uuid,\n        )\n\n    def _encode_tree(\n        self, out: BinaryIO, val: object, type_tree: SubtypeTree\n    ) -> None:\n        \"\"\"Encode the data in ``val`` given a parsed type tree.\n\n        :param out: A binary stream to write bytes to.\n        :param val: The :class:`gtirb.AuxData` to encode.\n        :param type_tree: The parsed type to encode ``val`` as.\n        \"\"\"\n\n        if type_tree.name not in self.codecs:\n            raise UnknownCodecError(type_tree.name)\n        codec = self.codecs[type_tree.name]\n        return codec.encode(\n            out, val, serialization=self, subtypes=type_tree.subtypes\n        )\n\n    @staticmethod\n    def _parse_type(type_name: str) -> SubtypeTree:\n        \"\"\"Given an encoded aux_data type_name, generate its parse tree.\n\n        >>> _parse_type('foo')\n        ('foo', ())\n\n        >>> _parse_type('foo<bar>')\n        ('foo', (('bar',()),))\n\n        >>> _parse_type('foo<bar<baz>>')\n        ('foo', (('bar', (('baz', ()),)),))\n\n        :param type_name: The type name to parse into a ``SubtypeTree``.\n        \"\"\"\n        tokens = findall(\"[^<>,]+|<|>|,\", type_name)\n\n        def parse(\n            tokens: Sequence[str],\n            tree: Iterable[SubtypeTree],\n        ) -> Tuple[Tuple[SubtypeTree, ...], Sequence[None]]:\n            tree = list(tree)\n            # It is an error to parse nothing\n            if len(tokens) == 0:\n                raise TypeNameError(type_name)\n            first_token, *tail = tokens\n\n            # The first token should be a name\n            if first_token in {\"<\", \">\", \",\"}:\n                raise TypeNameError(type_name)\n\n            # Base case\n            if len(tail) == 0:\n                tree.append(SubtypeTree(first_token, ()))\n                return tuple(tree), []\n            next_token, *tail = tail\n\n            # No subtypes\n            if next_token == \",\":\n                tree.append(SubtypeTree(first_token, ()))\n\n            # Parse subtypes\n            if next_token == \"<\":\n                # Extract just the subtype tokens and parse them\n                stack = [\"<\"]\n                subtype_tokens = list()\n                remaining_tokens = list()\n                for t in tail:\n                    if len(stack) == 0:\n                        remaining_tokens.append(t)\n                        continue\n                    if t == \"<\":\n                        stack.append(t)\n                    elif t == \">\":\n                        stack.pop()\n                    subtype_tokens.append(t)\n                if len(stack) > 0 or subtype_tokens[-1] != \">\":\n                    raise TypeNameError(type_name)\n                subtypes, remaining = parse(subtype_tokens[:-1], [])\n                # Parsing should consume all subtype tokens\n                if len(remaining) != 0:\n                    raise TypeNameError(type_name)\n                tree.append(SubtypeTree(first_token, subtypes))\n                # Finish if all tokens are consumed\n                if len(remaining_tokens) == 0:\n                    return tuple(tree), []\n                next_token, *tail = remaining_tokens\n\n            # If the next token is a comma, parse next\n            if next_token == \",\":\n                return parse(tail, tree)\n\n            # None of the rules match, error\n            raise TypeNameError(type_name)\n\n        # There should only be one item at the root of the tree\n        try:\n            (parse_tree,) = parse(tokens, [])[0]\n        except ValueError:\n            raise TypeNameError(type_name)\n        return parse_tree\n\n    def decode(\n        self,\n        raw_bytes: Union[bytes, bytearray, memoryview, BinaryIO],\n        type_name: str,\n        get_by_uuid: CacheLookupFn = None,\n    ) -> object:\n        \"\"\"Decode a :class:`gtirb.AuxData` of the specified type\n        from the specified byte stream.\n\n        :param raw_bytes: The byte stream from which to read the encoded value.\n        :param type_name: The type name of the object encoded by ``raw_bytes``.\n        :param get_by_uuid: A function to look up nodes by UUID.\n        :returns: The object encoded by ``raw_bytes``.\n        \"\"\"\n\n        parse_tree = Serialization._parse_type(type_name)\n        all_bytes = None\n        if isinstance(raw_bytes, (bytes, bytearray, memoryview)):\n            all_bytes = raw_bytes\n        else:\n            all_bytes = raw_bytes.read()\n        try:\n            return self._decode_tree(\n                io.BytesIO(all_bytes), parse_tree, get_by_uuid\n            )\n        except UnknownCodecError:\n            # we found an unknwon codec; the entire data structure can't be\n            # parsed; return a blob of bytes\n            return UnknownData(all_bytes)\n\n    def encode(self, out: BinaryIO, val: object, type_name: str) -> None:\n        \"\"\"Encodes the value of an AuxData value to bytes.\n\n        :param out: A binary stream to write bytes to.\n        :param val: The :class:`gtirb.AuxData` to encode.\n        :param type_name: The type name of the value encapsulated\n            by the :class:`gtirb.AuxData`.\n        \"\"\"\n\n        if isinstance(val, UnknownData):\n            # it was a blob of bytes because of a decoding problem;\n            # just write the whole thing out\n            out.write(val)\n            return\n        parse_tree = Serialization._parse_type(type_name)\n        try:\n            self._encode_tree(out, val, parse_tree)\n        except UnknownCodecError as e:\n            # rethrow UnknownCodecError, because we were supposed to catch it\n            # via UnknownData. This means the user manually wrote a bad type.\n            raise EncodeError(\"unknown codec: %s\" % e.name)\n"
  },
  {
    "path": "python/gtirb/symbol.py",
    "content": "import typing\nfrom uuid import UUID\n\nfrom .block import Block\nfrom .node import Node, _NodeMessage\nfrom .proto import Symbol_pb2\nfrom .util import DeserializationError, _IndexedAttribute\n\nif typing.TYPE_CHECKING:  # pragma: no cover\n    # Ignore flake8 \"imported but unused\" errors.\n    from .ir import IR  # noqa: F401\n    from .module import Module  # noqa: F401\n\n\nPayload = typing.Union[Block, int]\n\"\"\"A type hint representing the possible Symbol payloads.\"\"\"\n\n\nclass Symbol(Node):\n    \"\"\"Represents a symbol, which maps a name to an object in the IR.\n\n    :ivar ~.name: The name of this symbol.\n    :ivar ~.at_end: True if this symbol is at the end of its referent, rather\n        than at the beginning. Has no meaning for integral symbols.\n    \"\"\"\n\n    name = _IndexedAttribute[str]()(lambda self: self.module)\n    _payload = _IndexedAttribute[typing.Optional[Payload]]()(\n        lambda self: self.module\n    )\n\n    def __init__(\n        self,\n        name: str,\n        uuid: typing.Optional[UUID] = None,\n        payload: typing.Optional[Payload] = None,\n        at_end: bool = False,\n        module: typing.Optional[\"Module\"] = None,\n    ):\n        \"\"\"\n        :param name: The name of this symbol.\n        :param uuid: The UUID of this ``Symbol``,\n            or None if a new UUID needs generated via :func:`uuid.uuid4`.\n            Defaults to None.\n        :param payload: The value this symbol points to.\n            May be an address, a Node, or None.\n        :param at_end: True if this symbol is at the end of its referent,\n            rather than at the beginning.\n        :param module: The :class:`Module` this symbol belongs to.\n        \"\"\"\n\n        super().__init__(uuid)\n        self._module: typing.Optional[\"Module\"] = None\n        self.name = name\n        self.at_end = at_end\n        self._payload = payload\n        # Use the property setter to ensure correct invariants.\n        self.module = module\n\n    @property\n    def value(self) -> typing.Optional[int]:\n        \"\"\"The value of a Symbol, which is an integer or None.\n        ``value`` and ``referent`` are mutually exclusive.\n        \"\"\"\n\n        if not isinstance(self._payload, Block):\n            return self._payload\n        return None\n\n    @value.setter\n    def value(self, value: typing.Optional[int]) -> None:\n        self._payload = value\n\n    @property\n    def referent(self) -> typing.Optional[Block]:\n        \"\"\"The object referred to by a Symbol, which is :class:`Block`\n        or None. ``value`` and ``referent`` are mutually exclusive.\n        \"\"\"\n\n        if isinstance(self._payload, Block):\n            return self._payload\n        return None\n\n    @referent.setter\n    def referent(self, referent: typing.Optional[Block]) -> None:\n        self._payload = referent\n\n    @classmethod\n    def _decode_protobuf(\n        cls,\n        proto_symbol: _NodeMessage,\n        uuid: UUID,\n        ir: typing.Optional[\"IR\"],\n    ) -> \"Symbol\":\n        assert ir\n        assert isinstance(proto_symbol, Symbol_pb2.Symbol)\n        symbol = cls(\n            name=proto_symbol.name, at_end=proto_symbol.at_end, uuid=uuid\n        )\n        if proto_symbol.HasField(\"value\"):\n            symbol.value = proto_symbol.value\n        if proto_symbol.HasField(\"referent_uuid\"):\n            referent_uuid = UUID(bytes=proto_symbol.referent_uuid)\n            referent = ir.get_by_uuid(referent_uuid)\n            if not isinstance(referent, Block):\n                raise DeserializationError(\n                    \"Symbol: UUID %s is not a block\" % referent_uuid\n                )\n            symbol.referent = referent\n        symbol._add_to_uuid_cache(ir._local_uuid_cache)\n        return symbol\n\n    def _to_protobuf(self) -> Symbol_pb2.Symbol:\n        proto_symbol = Symbol_pb2.Symbol()\n        proto_symbol.uuid = self.uuid.bytes\n        if self.value is not None:\n            proto_symbol.value = self.value\n        elif self.referent is not None:\n            proto_symbol.referent_uuid = self.referent.uuid.bytes\n        proto_symbol.name = self.name\n        proto_symbol.at_end = self.at_end\n        return proto_symbol\n\n    def deep_eq(self, other: object) -> bool:\n        # Do not move __eq__. See docstring for Node.deep_eq for more info.\n        if not isinstance(other, Symbol):\n            return False\n        if self.value != other.value:\n            return False\n        if self.referent is None:\n            if other.referent is not None:\n                return False\n        else:\n            if not self.referent.deep_eq(other.referent):\n                return False\n        return (\n            self.name == other.name\n            and self.at_end == other.at_end\n            and self.uuid == other.uuid\n        )\n\n    def __repr__(self) -> str:\n        return (\n            \"Symbol(\"\n            \"uuid={uuid!r}, \"\n            \"name={name!r}, \"\n            \"payload={payload!r}, \"\n            \"at_end={at_end!r}, \"\n            \")\".format(name=self.name, payload=self._payload, **self.__dict__)\n        )\n\n    @property\n    def module(self) -> typing.Optional[\"Module\"]:\n        return self._module\n\n    @module.setter\n    def module(self, value: typing.Optional[\"Module\"]) -> None:\n        if self._module is not None:\n            self._module.symbols.discard(self)\n        if value is not None:\n            value.symbols.add(self)\n\n    def _add_to_uuid_cache(self, cache: typing.Dict[UUID, Node]) -> None:\n        \"\"\"Update the UUID cache when this node is added.\"\"\"\n\n        cache[self.uuid] = self\n\n    def _remove_from_uuid_cache(self, cache: typing.Dict[UUID, Node]) -> None:\n        \"\"\"Update the UUID cache when this node is removed.\"\"\"\n\n        del cache[self.uuid]\n\n    @property\n    def ir(self) -> typing.Optional[\"IR\"]:\n        \"\"\"Get the IR this node ultimately belongs to.\"\"\"\n        if self.module is None:\n            return None\n        return self.module.ir\n"
  },
  {
    "path": "python/gtirb/symbolicexpression.py",
    "content": "import typing\nfrom enum import Enum\nfrom uuid import UUID\n\nfrom .node import Node\nfrom .proto import SymbolicExpression_pb2\nfrom .symbol import Symbol\nfrom .util import DeserializationError\n\nAttributesCtorType = typing.Iterable[\n    typing.Union[\n        \"SymbolicExpression_pb2.SymAttribute.ValueType\",\n        \"SymbolicExpression.Attribute\",\n    ]\n]\n\n\nclass SymbolicExpression:\n    \"\"\"Base class of symbolic expression types.\"\"\"\n\n    class Attribute(Enum):\n        \"\"\"Attributes representing a known property of a symbolic expression.\n        See https://grammatech.github.io/gtirb/md__symbolic_expression.html\n        \"\"\"\n\n        GOT = SymbolicExpression_pb2.SymAttribute.Value(\"GOT\")\n        GOTPC = SymbolicExpression_pb2.SymAttribute.Value(\"GOTPC\")\n        GOTOFF = SymbolicExpression_pb2.SymAttribute.Value(\"GOTOFF\")\n        GOTREL = SymbolicExpression_pb2.SymAttribute.Value(\"GOTREL\")\n        PLT = SymbolicExpression_pb2.SymAttribute.Value(\"PLT\")\n        PLTOFF = SymbolicExpression_pb2.SymAttribute.Value(\"PLTOFF\")\n        PCREL = SymbolicExpression_pb2.SymAttribute.Value(\"PCREL\")\n        SECREL = SymbolicExpression_pb2.SymAttribute.Value(\"SECREL\")\n        TLS = SymbolicExpression_pb2.SymAttribute.Value(\"TLS\")\n        TLSGD = SymbolicExpression_pb2.SymAttribute.Value(\"TLSGD\")\n        TLSLD = SymbolicExpression_pb2.SymAttribute.Value(\"TLSLD\")\n        TLSLDM = SymbolicExpression_pb2.SymAttribute.Value(\"TLSLDM\")\n        TLSCALL = SymbolicExpression_pb2.SymAttribute.Value(\"TLSCALL\")\n        TLSDESC = SymbolicExpression_pb2.SymAttribute.Value(\"TLSDESC\")\n        TPREL = SymbolicExpression_pb2.SymAttribute.Value(\"TPREL\")\n        TPOFF = SymbolicExpression_pb2.SymAttribute.Value(\"TPOFF\")\n        DTPREL = SymbolicExpression_pb2.SymAttribute.Value(\"DTPREL\")\n        DTPOFF = SymbolicExpression_pb2.SymAttribute.Value(\"DTPOFF\")\n        DTPMOD = SymbolicExpression_pb2.SymAttribute.Value(\"DTPMOD\")\n        NTPOFF = SymbolicExpression_pb2.SymAttribute.Value(\"NTPOFF\")\n        PAGE = SymbolicExpression_pb2.SymAttribute.Value(\"PAGE\")\n        PAGEOFF = SymbolicExpression_pb2.SymAttribute.Value(\"PAGEOFF\")\n        CALL = SymbolicExpression_pb2.SymAttribute.Value(\"CALL\")\n        LO = SymbolicExpression_pb2.SymAttribute.Value(\"LO\")\n        HI = SymbolicExpression_pb2.SymAttribute.Value(\"HI\")\n        HIGHER = SymbolicExpression_pb2.SymAttribute.Value(\"HIGHER\")\n        HIGHEST = SymbolicExpression_pb2.SymAttribute.Value(\"HIGHEST\")\n        GOTNTPOFF = SymbolicExpression_pb2.SymAttribute.Value(\"GOTNTPOFF\")\n        INDNTPOFF = SymbolicExpression_pb2.SymAttribute.Value(\"INDNTPOFF\")\n        G0 = SymbolicExpression_pb2.SymAttribute.Value(\"G0\")\n        G1 = SymbolicExpression_pb2.SymAttribute.Value(\"G1\")\n        G2 = SymbolicExpression_pb2.SymAttribute.Value(\"G2\")\n        G3 = SymbolicExpression_pb2.SymAttribute.Value(\"G3\")\n        UPPER16 = SymbolicExpression_pb2.SymAttribute.Value(\"UPPER16\")\n        LOWER16 = SymbolicExpression_pb2.SymAttribute.Value(\"LOWER16\")\n        LO12 = SymbolicExpression_pb2.SymAttribute.Value(\"LO12\")\n        LO15 = SymbolicExpression_pb2.SymAttribute.Value(\"LO15\")\n        LO14 = SymbolicExpression_pb2.SymAttribute.Value(\"LO14\")\n        HI12 = SymbolicExpression_pb2.SymAttribute.Value(\"HI12\")\n        HI21 = SymbolicExpression_pb2.SymAttribute.Value(\"HI21\")\n        S = SymbolicExpression_pb2.SymAttribute.Value(\"S\")\n        PG = SymbolicExpression_pb2.SymAttribute.Value(\"PG\")\n        NC = SymbolicExpression_pb2.SymAttribute.Value(\"NC\")\n        ABS = SymbolicExpression_pb2.SymAttribute.Value(\"ABS\")\n        PREL = SymbolicExpression_pb2.SymAttribute.Value(\"PREL\")\n        PREL31 = SymbolicExpression_pb2.SymAttribute.Value(\"PREL31\")\n        TARGET1 = SymbolicExpression_pb2.SymAttribute.Value(\"TARGET1\")\n        TARGET2 = SymbolicExpression_pb2.SymAttribute.Value(\"TARGET2\")\n        SBREL = SymbolicExpression_pb2.SymAttribute.Value(\"SBREL\")\n        TLSLDO = SymbolicExpression_pb2.SymAttribute.Value(\"TLSLDO\")\n        HI16 = SymbolicExpression_pb2.SymAttribute.Value(\"HI16\")\n        LO16 = SymbolicExpression_pb2.SymAttribute.Value(\"LO16\")\n        GPREL = SymbolicExpression_pb2.SymAttribute.Value(\"GPREL\")\n        DISP = SymbolicExpression_pb2.SymAttribute.Value(\"DISP\")\n        OFST = SymbolicExpression_pb2.SymAttribute.Value(\"OFST\")\n        H = SymbolicExpression_pb2.SymAttribute.Value(\"H\")\n        L = SymbolicExpression_pb2.SymAttribute.Value(\"L\")\n        HA = SymbolicExpression_pb2.SymAttribute.Value(\"HA\")\n        HIGH = SymbolicExpression_pb2.SymAttribute.Value(\"HIGH\")\n        HIGHA = SymbolicExpression_pb2.SymAttribute.Value(\"HIGHA\")\n        HIGHERA = SymbolicExpression_pb2.SymAttribute.Value(\"HIGHERA\")\n        HIGHESTA = SymbolicExpression_pb2.SymAttribute.Value(\"HIGHESTA\")\n        TOCBASE = SymbolicExpression_pb2.SymAttribute.Value(\"TOCBASE\")\n        TOC = SymbolicExpression_pb2.SymAttribute.Value(\"TOC\")\n        NOTOC = SymbolicExpression_pb2.SymAttribute.Value(\"NOTOC\")\n\n        def __repr__(self) -> str:\n            return \"SymbolicExpression.Attribute.%s\" % self.name\n\n        def __int__(self) -> int:\n            return self.value\n\n    def __init__(\n        self,\n        attributes: AttributesCtorType = set(),\n    ):\n        self.attributes = set(attributes)\n\n    @property\n    def symbols(self) -> typing.Iterable[Symbol]:\n        \"\"\"Get all the symbols involved with this symbolic expression,\n        regardless of role.\n        \"\"\"\n\n        raise NotImplementedError  # pragma: no cover\n\n    def deep_eq(self, other: object) -> bool:\n        raise NotImplementedError  # pragma: no cover\n\n    def _attributes_repr(self) -> str:\n        if not self.attributes:\n            return \"set()\"\n        else:\n            return \"{%s}\" % \",\".join(repr(a) for a in self.attributes)\n\n\nclass SymAddrAddr(SymbolicExpression):\n    \"\"\"Represents a symbolic expression of the form\n    \"(Sym1 - Sym2) / Scale + Offset\".\n\n    :ivar ~.scale: Constant scale factor.\n    :ivar ~.offset: Constant offset.\n    :ivar ~.symbol1: Symbol representing the base address.\n    :ivar ~.symbol2: Symbol to subtract from ``symbol1``.\n    \"\"\"\n\n    def __init__(\n        self,\n        scale: int,\n        offset: int,\n        symbol1: Symbol,\n        symbol2: Symbol,\n        attributes: AttributesCtorType = set(),\n    ):\n        \"\"\"\n        :param scale: Constant scale factor.\n        :param offset: Constant offset.\n        :param symbol1: Symbol representing the base address.\n        :param symbol2: Symbol to subtract from ``symbol1``.\n        :param attributes: :class:`SymobolicExpression.Attribute`\\\\s of this\n            expression.\n        \"\"\"\n        super().__init__(attributes)\n        self.scale = scale\n        self.offset = offset\n        self.symbol1 = symbol1\n        self.symbol2 = symbol2\n\n    @classmethod\n    def _from_protobuf(\n        cls,\n        proto_symaddraddr: SymbolicExpression_pb2.SymAddrAddr,\n        get_by_uuid: typing.Callable[[UUID], typing.Optional[Node]],\n    ) -> \"SymAddrAddr\":\n        symbol1_uuid = UUID(bytes=proto_symaddraddr.symbol1_uuid)\n        symbol1 = get_by_uuid(symbol1_uuid)\n        if not isinstance(symbol1, Symbol):\n            raise DeserializationError(\n                \"SymAddrAddr: UUID %s is not a Symbol\" % symbol1_uuid\n            )\n        symbol2_uuid = UUID(bytes=proto_symaddraddr.symbol2_uuid)\n        symbol2 = get_by_uuid(symbol2_uuid)\n        if not isinstance(symbol2, Symbol):\n            raise DeserializationError(\n                \"SymAddrAddr: UUID %s is not a Symbol\" % symbol2_uuid\n            )\n        return cls(\n            proto_symaddraddr.scale, proto_symaddraddr.offset, symbol1, symbol2\n        )\n\n    def _to_protobuf(self) -> SymbolicExpression_pb2.SymAddrAddr:\n        proto_symaddraddr = SymbolicExpression_pb2.SymAddrAddr()\n        proto_symaddraddr.scale = self.scale\n        proto_symaddraddr.offset = self.offset\n        proto_symaddraddr.symbol1_uuid = self.symbol1.uuid.bytes\n        proto_symaddraddr.symbol2_uuid = self.symbol2.uuid.bytes\n        return proto_symaddraddr\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, SymAddrAddr):\n            return False\n        return (\n            self.scale == other.scale\n            and self.offset == other.offset\n            and self.symbol1.uuid == other.symbol1.uuid\n            and self.symbol2.uuid == other.symbol2.uuid\n            and self.attributes == other.attributes\n        )\n\n    def __hash__(self) -> int:\n        return hash(\n            (self.offset, self.scale, self.symbol1.uuid, self.symbol2.uuid)\n        )\n\n    def __repr__(self) -> str:\n        return (\n            \"SymAddrAddr(\"\n            \"scale={scale!r}, \"\n            \"offset={offset!r}, \"\n            \"symbol1={symbol1!r}, \"\n            \"symbol2={symbol2!r}, \"\n            \"attributes={attributes_repr!s}, \"\n            \")\"\n        ).format(\n            scale=self.scale,\n            offset=self.offset,\n            symbol1=self.symbol1,\n            symbol2=self.symbol2,\n            attributes_repr=self._attributes_repr(),\n        )\n\n    def deep_eq(self, other: object) -> bool:\n        # Do not move __eq__. See docstring for Node.deep_eq for more info.\n        if not isinstance(other, SymAddrAddr):\n            return False\n        return (\n            self.scale == other.scale\n            and self.offset == other.offset\n            and self.symbol1.deep_eq(other.symbol1)\n            and self.symbol2.deep_eq(other.symbol2)\n            and self.attributes == other.attributes\n        )\n\n    @property\n    def symbols(self) -> typing.Iterable[Symbol]:\n        yield self.symbol1\n        yield self.symbol2\n\n\nclass SymAddrConst(SymbolicExpression):\n    \"\"\"Represents a symbolic expression of the form \"Sym + Offset\".\n\n    :ivar ~.offset: Constant offset.\n    :ivar ~.symbol: Symbol representing an address.\n    \"\"\"\n\n    def __init__(\n        self,\n        offset: int,\n        symbol: Symbol,\n        attributes: AttributesCtorType = set(),\n    ):\n        \"\"\"\n        :param offset: Constant offset.\n        :param symbol: Symbol representing an address.\n        :param attributes: :class:`SymbolicExpression.Attribute`\\\\s of this\n            expression.\n        \"\"\"\n        super().__init__(attributes)\n        self.offset = offset\n        self.symbol = symbol\n\n    @classmethod\n    def _from_protobuf(\n        cls,\n        proto_symaddrconst: SymbolicExpression_pb2.SymAddrConst,\n        get_by_uuid: typing.Callable[[UUID], typing.Optional[Node]],\n    ) -> \"SymAddrConst\":\n        symbol_uuid = UUID(bytes=proto_symaddrconst.symbol_uuid)\n        symbol = get_by_uuid(symbol_uuid)\n        if not isinstance(symbol, Symbol):\n            raise DeserializationError(\n                \"SymAddrConst: UUID %s is not a Symbol\" % symbol_uuid\n            )\n        return cls(proto_symaddrconst.offset, symbol)\n\n    def _to_protobuf(self) -> SymbolicExpression_pb2.SymAddrConst:\n        proto_symaddrconst = SymbolicExpression_pb2.SymAddrConst()\n        proto_symaddrconst.offset = self.offset\n        if self.symbol is not None:\n            proto_symaddrconst.symbol_uuid = self.symbol.uuid.bytes\n        return proto_symaddrconst\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, SymAddrConst):\n            return False\n        return (\n            self.offset == other.offset\n            and self.symbol.uuid == other.symbol.uuid\n            and self.attributes == other.attributes\n        )\n\n    def __hash__(self) -> int:\n        return hash((self.offset, self.symbol.uuid))\n\n    def __repr__(self) -> str:\n        return (\n            \"SymAddrConst(\"\n            \"offset={offset!r}, \"\n            \"symbol={symbol!r}, \"\n            \"attributes={attributes_repr!s}, \"\n            \")\"\n        ).format(\n            offset=self.offset,\n            symbol=self.symbol,\n            attributes_repr=self._attributes_repr(),\n        )\n\n    def deep_eq(self, other: object) -> bool:\n        # Do not move __eq__. See docstring for Node.deep_eq for more info.\n        if not isinstance(other, SymAddrConst):\n            return False\n        return (\n            self.offset == other.offset\n            and self.symbol.deep_eq(other.symbol)\n            and self.attributes == other.attributes\n        )\n\n    @property\n    def symbols(self) -> typing.Iterable[Symbol]:\n        yield self.symbol\n"
  },
  {
    "path": "python/gtirb/util.py",
    "content": "\"\"\"General utilities usable by any other GTIRB submoudle.\"\"\"\n\nimport itertools\nimport typing\n\nimport intervaltree\nimport typing_extensions\n\nK = typing.TypeVar(\"K\")\nV = typing.TypeVar(\"V\")\nT = typing.TypeVar(\"T\")\nT_cov = typing.TypeVar(\"T_cov\", covariant=True)\nT_contra = typing.TypeVar(\"T_contra\", contravariant=True)\nS = typing.TypeVar(\"S\")\n\n\nDictLike = typing.Union[\n    typing.Mapping[K, V],\n    typing.Iterable[typing.Tuple[K, V]],\n]\n\"\"\"Any value that can be passed to the constructor of ``dict``;\nthat is, a mapping or iterable yielding key-value tuples.\n\"\"\"\n\n\nclass GtirbError(Exception):\n    pass\n\n\nclass DeserializationError(GtirbError):\n    pass\n\n\nclass _SymbolicExpressionContainer(typing_extensions.Protocol[T_cov]):\n    \"\"\"A container of symbolic expressions at addresses.\"\"\"\n\n    def symbolic_expressions_at(\n        self, addrs: typing.Union[int, range]\n    ) -> typing.Iterable[T_cov]:\n        ...  # pragma: no cover\n\n\nclass ListWrapper(typing.MutableSequence[T]):\n    def __init__(self, *args: typing.Iterable[T]):\n        self._data: typing.List[T] = []\n        for values in args:\n            for value in values:\n                self.append(value)\n\n    def _add(self, value: T) -> None:\n        pass  # pragma: no cover\n\n    def _remove(self, value: T) -> None:\n        pass  # pragma: no cover\n\n    # begin functions for ABC\n    @typing.overload\n    def __getitem__(self, i: int) -> T:\n        ...  # pragma: no cover\n\n    @typing.overload\n    def __getitem__(self, i: slice) -> typing.MutableSequence[T]:\n        ...  # pragma: no cover\n\n    def __getitem__(\n        self, i: typing.Union[int, slice]\n    ) -> typing.Union[T, typing.MutableSequence[T]]:\n        return self._data[i]\n\n    @typing.overload\n    def __setitem__(self, i: typing_extensions.SupportsIndex, v: T) -> None:\n        ...  # pragma: no cover\n\n    @typing.overload\n    def __setitem__(self, i: slice, v: typing.Iterable[T]) -> None:\n        ...  # pragma: no cover\n\n    def __setitem__(\n        self,\n        i: typing.Union[typing_extensions.SupportsIndex, slice],\n        v: typing.Union[T, typing.Iterable[T]],\n    ) -> None:\n        if isinstance(i, slice):\n            assert isinstance(v, typing.Iterable)\n            indices = range(*i.indices(len(self)))\n            values = list(v)\n        elif -len(self._data) <= i.__index__() < len(self._data):\n            indices = range(i.__index__(), i.__index__() + 1)\n            values = [typing.cast(T, v)]\n        else:\n            raise IndexError(\"list assignment index out of range\")\n        for index in indices:\n            self._remove(self._data[index])\n        for value in values:\n            self._add(value)\n        if isinstance(i, slice):\n            self._data[i] = values\n        else:\n            self._data[i] = values[0]\n\n    @typing.overload\n    def __delitem__(self, i: int) -> None:\n        ...  # pragma: no cover\n\n    @typing.overload\n    def __delitem__(self, i: slice) -> None:\n        ...  # pragma: no cover\n\n    def __delitem__(self, i: typing.Union[int, slice]) -> None:\n        if isinstance(i, slice):\n            indices = range(*i.indices(len(self)))\n        else:\n            indices = range(i, i + 1)\n        for index in indices:\n            self._remove(self._data[index])\n\n        del self._data[i]\n\n    def __len__(self) -> int:\n        return len(self._data)\n\n    def insert(self, i: int, v: T) -> None:\n        self._add(v)\n        return self._data.insert(i, v)\n\n    # The version of typing.py which comes with python 3.5.2 doesn't provide\n    # definitions for append or remove on MutableList, so we have to do it\n    # ourselves.\n    def append(self, v: T) -> None:\n        self.insert(len(self), v)\n\n    def remove(self, v: T) -> None:\n        del self[self._data.index(v)]\n\n    # extend is not in every version of Python 3, so list wrapper adds it here\n    # itself.\n    def extend(self, other: typing.Iterable[T]) -> None:\n        for v in other:\n            self.append(v)\n\n    # end functions for ABC\n    def __str__(self) -> str:\n        return str(self._data)\n\n    def __repr__(self) -> str:\n        return repr(self._data)\n\n\n# A type variable for the SetWrapper's \"self\" type. Since type variables cannot\n# have a generic bound (see https://github.com/python/mypy/issues/2756), we\n# need to use Any instead. Which we then have to tell mypy to ignore.\n#\n# Used in __ior__.\n_SetWrapperSelf = typing.TypeVar(  # type: ignore[misc]\n    \"_SetWrapperSelf\", bound=\"SetWrapper[typing.Any]\"\n)\n\n\nclass SetWrapper(typing.MutableSet[T]):\n    def __init__(self, *args: typing.Iterable[T]):\n        self._data: typing.Set[T] = set()\n        for arg in args:\n            for v in arg:\n                self.add(v)\n\n    # begin functions for ABC\n    def __contains__(self, v: object) -> bool:\n        return v in self._data\n\n    def __iter__(self) -> typing.Iterator[T]:\n        return iter(self._data)\n\n    def __len__(self) -> int:\n        return len(self._data)\n\n    def add(self, v: T) -> None:\n        return self._data.add(v)\n\n    def discard(self, v: T) -> None:\n        return self._data.discard(v)\n\n    # end functions for ABC\n\n    # The version of typing.py which comes with python 3.5.2 doesn't provide\n    # definitions for __or__ or clear on MutableSet, so we have to do it\n    # ourselves.\n    def __or__(\n        self, other: typing.AbstractSet[S]\n    ) -> typing.Set[typing.Union[T, S]]:\n        return self._data | other\n\n    # The type declaration for __ior__ in typeshed's MutableSet is problematic.\n    # MutableSet requires __ior__ to accept an AbstractSet[S], and return a\n    # Mutable[T|S]. This results in a type error when the result is assigned\n    # back to the original variable unless S is T. Since this can't actually be\n    # used if S is not T and is much easier to implement if S is T anyway, we\n    # declare it to only accept AbstractSet[T]. This causes mypy to report an\n    # error for incompatible override types and different return types for\n    # __ior__ and __or__, which we ignore.\n    def __ior__(  # type: ignore\n        self: _SetWrapperSelf, other: typing.AbstractSet[T]\n    ) -> _SetWrapperSelf:\n        for value in other:\n            self.add(value)\n        return self\n\n    def pop(self) -> T:\n        it = iter(self)\n        # pop is documented as raising a KeyError if it's empty, not\n        # StopIteration\n        try:\n            result = next(it)\n        except StopIteration:\n            raise KeyError\n        self.discard(result)\n        return result\n\n    def clear(self) -> None:\n        while self:\n            self.pop()\n\n    # For whatever reason, update isn't included as part of abc.MutableSet.\n    def update(self, *others: typing.Iterable[T]) -> None:\n        for other in others:\n            for v in other:\n                self.add(v)\n\n    def __str__(self) -> str:\n        return str(self._data)\n\n    def __repr__(self) -> str:\n        return repr(self._data)\n\n\nclass DictWrapper(typing.MutableMapping[K, V]):\n    def __init__(self, *args: DictLike[K, V]):\n        self._data: typing.MutableMapping[K, V] = {}\n        # Create a temporary dictionary so we can uniformly access the items\n        # and add them to _data.\n        temp: typing.Dict[K, V] = dict(*args)\n        for i, v in temp.items():\n            self[i] = v\n\n    # begin functions for ABC\n    def __getitem__(self, i: K) -> V:\n        return self._data[i]\n\n    def __setitem__(self, i: K, v: V) -> None:\n        self._data[i] = v\n\n    def __delitem__(self, i: K) -> None:\n        del self._data[i]\n\n    def __iter__(self) -> typing.Iterator[K]:\n        return iter(self._data)\n\n    def __len__(self) -> int:\n        return len(self._data)\n\n    # end functions for ABC\n    def __str__(self) -> str:\n        return str(self._data)\n\n    def __repr__(self) -> str:\n        return repr(self._data)\n\n\nInstanceT = typing.TypeVar(\"InstanceT\")\nAttributeT = typing.TypeVar(\"AttributeT\")\n\n\nclass IndexedContainer(typing_extensions.Protocol[T_contra]):\n    \"\"\"Container wth an index that can be updated.\"\"\"\n\n    def _index_discard(self, instance: T_contra) -> None:\n        ...  # pragma: no cover\n\n    def _index_add(self, instance: T_contra) -> None:\n        ...  # pragma: no cover\n\n\nclass ParentGetter(typing_extensions.Protocol[T_contra]):\n    \"\"\"Interface for getting an _IndexedContainer for an instance.\"\"\"\n\n    def __call__(\n        self, instance: T_contra\n    ) -> typing.Optional[IndexedContainer[T_contra]]:\n        ...  # pragma: no cover\n\n\nclass _IndexedAttribute(typing.Generic[AttributeT]):\n    \"\"\"\n    The _IndexedAttribute descriptor notifies a parent when the attribute is\n    modified. The outer class is generic in the attribute type and provides a\n    __call__ method to deduce the remaining type parameters and construct the\n    descriptor itself.\n\n    Example usage:\n\n    class Foo:\n        my_int = _IndexedAttribute[int]()(lambda foo: foo.parent)\n    \"\"\"\n\n    class Descriptor(typing.Generic[InstanceT]):\n        \"\"\"\n        A descriptor that will notify a parent when the value is set and can be\n        otherwise used like a normal attribute.\n        \"\"\"\n\n        def __init__(self, parent_getter: ParentGetter[InstanceT]):\n            self.parent_getter = parent_getter\n\n        def __get__(\n            self,\n            instance: InstanceT,\n            owner: typing.Type[InstanceT] = None,\n        ) -> AttributeT:\n            return getattr(instance, self.attribute_name)\n\n        def __set__(self, instance: InstanceT, value: AttributeT) -> None:\n            parent = self.parent_getter(instance)\n            if parent:\n                parent._index_discard(instance)\n            setattr(instance, self.attribute_name, value)\n            parent = self.parent_getter(instance)\n            if parent:\n                parent._index_add(instance)\n\n        def __delete__(self, instance: InstanceT) -> None:\n            raise AttributeError(\"can't delete attribute %s\" % (self.name))\n\n        def __set_name__(self, owner: InstanceT, name: str) -> None:\n            self.name = name\n            self.attribute_name = \"_\" + name\n\n    def __call__(self, parent_getter: ParentGetter[InstanceT]) -> AttributeT:\n        \"\"\"\n        Create the descriptor, but tell mypy it is the attribute type.\n\n        The cast helps mypy recognize when the instance type satisfies a\n        protocol. Mypy checks to see if the class matches the protocol instead\n        of the instance. However, descriptors are treated as the descriptor\n        type in the class and the attribute type in the instance. This causes\n        mypy to reject the protocol, even though it works correctly at runtime.\n        \"\"\"\n        return typing.cast(\n            AttributeT, self.Descriptor[InstanceT](parent_getter)\n        )\n\n\ndef get_desired_range(addrs: typing.Union[int, range]) -> range:\n    if isinstance(addrs, int):\n        return range(addrs, addrs + 1)\n    else:\n        return addrs\n\n\nclass AddrRange(typing_extensions.Protocol):\n    \"\"\"An object spanning a range of addresses.\"\"\"\n\n    # Protocol field types must match exactly, but properties are allowed to\n    # return subtypes. This means that a class whose address or size is an int\n    # will match Optional[int] properties, but not Optional[int] fields.\n\n    @property\n    def address(self) -> typing.Optional[int]:\n        ...  # pragma: no cover\n\n    @property\n    def size(self) -> typing.Optional[int]:\n        ...  # pragma: no cover\n\n\n# Need a TypeVar bounded by the protocol so that nodes_on callers will get\n# back the actual node type, not an AddrRange.\nAddrRangeT = typing.TypeVar(\"AddrRangeT\", bound=AddrRange)\n\n\ndef nodes_on(\n    nodes: typing.Iterable[AddrRangeT],\n    addrs: typing.Union[int, range],\n) -> typing.Iterable[AddrRangeT]:\n    desired_range = get_desired_range(addrs)\n    for node in nodes:\n        node_addr = node.address\n        if node_addr is not None:\n            node_size = node.size\n            assert node_size is not None\n            node_range = range(node_addr, node_addr + node_size)\n            if range(\n                max(desired_range.start, node_range.start),\n                min(desired_range.stop, node_range.stop),\n            ):\n                yield node\n\n\ndef nodes_at(\n    nodes: typing.Iterable[AddrRangeT],\n    addrs: typing.Union[int, range],\n) -> typing.Iterable[AddrRangeT]:\n    desired_range = get_desired_range(addrs)\n    for node in nodes:\n        node_addr = node.address\n        if node_addr is not None and node_addr in desired_range:\n            yield node\n\n\ndef _address_interval(\n    node: AddrRangeT,\n) -> \"typing.Optional[intervaltree.Interval[int, AddrRangeT]]\":\n    \"\"\"\n    Creates an interval tree interval based on a GTIRB node's address and\n    size or returns None, if the node has no address.\n    \"\"\"\n    node_address = node.address\n    if node_address is not None:\n        node_size = node.size\n        assert node_size is not None\n        return intervaltree.Interval(\n            node_address, node_address + node_size + 1, node\n        )\n    else:\n        return None\n\n\nclass OffsetRange(typing_extensions.Protocol):\n    \"\"\"An object spanning a range of offsets.\"\"\"\n\n    @property\n    def offset(self) -> int:\n        ...  # pragma: no cover\n\n    @property\n    def size(self) -> int:\n        ...  # pragma: no cover\n\n\nOffsetRangeT = typing.TypeVar(\"OffsetRangeT\", bound=OffsetRange)\n\n\ndef _offset_interval(\n    node: OffsetRangeT,\n) -> \"intervaltree.Interval[int, OffsetRangeT]\":\n    \"\"\"\n    Creates an interval tree interval based on a GTIRB node's offset and size.\n    \"\"\"\n    return intervaltree.Interval(\n        node.offset, node.offset + node.size + 1, node\n    )\n\n\ndef _nodes_on_interval_tree_impl(\n    tree: \"intervaltree.IntervalTree[int, T]\",\n    addrs: typing.Union[int, range],\n    *,\n    interval_getter: typing.Callable[\n        [T], typing.Optional[\"intervaltree.Interval[int, T]\"]\n    ],\n    adjustment: int = 0,\n) -> typing.Iterable[T]:\n    \"\"\"\n    Implements nodes_on for an IntervalTree.\n    :param tree: The IntervalTree to search.\n    :param addrs: The address or addresses to locate nodes on.\n    :param interval_getter: Get the node's interval.\n    :param adjustment: An adjustment to be applied to the search range before\n           consulting the interval tree.\n    \"\"\"\n\n    desired_range = get_desired_range(addrs)\n    for interval in tree.overlap(\n        desired_range.start + adjustment, desired_range.stop + adjustment\n    ):\n        node = interval.data\n        node_interval = interval_getter(node)\n        if node_interval is None:\n            continue\n\n        # We explicitly exclude zero-sized blocks to match the existing\n        # nodes_on function and prior behavior of callers before they switched\n        # to using an interval tree.\n        if not node_interval.length() - 1:\n            continue\n\n        # Our interval tree ranges are closed, so we need to make sure not to\n        # return items the caller didn't request.\n        if node_interval.end - 1 <= desired_range.start:\n            continue\n\n        yield node\n\n\ndef _nodes_on_interval_tree(\n    tree: \"intervaltree.IntervalTree[int, AddrRangeT]\",\n    addrs: typing.Union[int, range],\n    adjustment: int = 0,\n) -> typing.Iterable[AddrRangeT]:\n    \"\"\"\n    Implements nodes_on for an IntervalTree by address.\n    :param tree: The IntervalTree to search.\n    :param addrs: The address or addresses to locate nodes on.\n    :param adjustment: An adjustment to be applied to the search range before\n           consulting the interval tree.\n    \"\"\"\n\n    return _nodes_on_interval_tree_impl(\n        tree, addrs, interval_getter=_address_interval, adjustment=adjustment\n    )\n\n\ndef _nodes_on_interval_tree_offset(\n    tree: \"intervaltree.IntervalTree[int, OffsetRangeT]\",\n    addrs: typing.Union[int, range],\n) -> typing.Iterable[OffsetRangeT]:\n    \"\"\"\n    Implements nodes_on for an IntervalTree by offset.\n    :param tree: The IntervalTree to search.\n    :param addrs: The address or addresses to locate nodes on.\n    \"\"\"\n\n    return _nodes_on_interval_tree_impl(\n        tree, addrs, interval_getter=_offset_interval\n    )\n\n\ndef _nodes_at_interval_tree_impl(\n    tree: \"intervaltree.IntervalTree[int, T]\",\n    addrs: typing.Union[int, range],\n    *,\n    bounds_getter: typing.Callable[\n        [T], typing.Optional[\"intervaltree.Interval[int, T]\"]\n    ],\n    adjustment: int = 0,\n) -> typing.Iterable[T]:\n    \"\"\"\n    Implements nodes_at for an IntervalTree.\n    :param tree: The IntervalTree to search.\n    :param addrs: The address or addresses to locate nodes at.\n    :param adjustment: An adjustment to be applied to the search range before\n           consulting the interval tree.\n    \"\"\"\n\n    desired_range = get_desired_range(addrs)\n    for interval in tree.overlap(\n        desired_range.start + adjustment, desired_range.stop + adjustment\n    ):\n        bounds = bounds_getter(interval.data)\n        if not bounds:\n            continue\n\n        # Check that it's actually in our desired range, which may have a\n        # step value that excludes it. This is a constant time operation.\n        if bounds.begin in desired_range:\n            yield interval.data\n\n\ndef _nodes_at_interval_tree(\n    tree: \"intervaltree.IntervalTree[int, AddrRangeT]\",\n    addrs: typing.Union[int, range],\n    adjustment: int = 0,\n) -> typing.Iterable[AddrRangeT]:\n    \"\"\"\n    Implements nodes_at for an IntervalTree.\n    :param tree: The IntervalTree to search.\n    :param addrs: The address or addresses to locate nodes at.\n    :param adjustment: An adjustment to be applied to the search range before\n           consulting the interval tree.\n    \"\"\"\n\n    return _nodes_at_interval_tree_impl(\n        tree, addrs, bounds_getter=_address_interval, adjustment=adjustment\n    )\n\n\ndef _nodes_at_interval_tree_offset(\n    tree: \"intervaltree.IntervalTree[int, OffsetRangeT]\",\n    offsets: typing.Union[int, range],\n) -> typing.Iterable[OffsetRangeT]:\n    \"\"\"\n    Implements nodes_at for an IntervalTree by offset.\n    :param tree: The IntervalTree to search.\n    :param offsets: The offset or offsets to locate nodes at.\n    \"\"\"\n\n    return _nodes_at_interval_tree_impl(\n        tree, offsets, bounds_getter=_offset_interval\n    )\n\n\ndef symbolic_expressions_at(\n    nodes: typing.Iterable[_SymbolicExpressionContainer[T_cov]],\n    addrs: typing.Union[int, range],\n) -> typing.Iterable[T_cov]:\n    return itertools.chain.from_iterable(\n        node.symbolic_expressions_at(addrs) for node in nodes\n    )\n"
  },
  {
    "path": "python/mypy.ini.in",
    "content": "[mypy]\npython_version = 3.8\nmypy_path = @CMAKE_CURRENT_SOURCE_DIR@/stubs\nshow_error_codes = True\nshow_column_numbers = True\n\ndisallow_incomplete_defs = True\ndisallow_untyped_calls = True\ndisallow_untyped_decorators = True\ndisallow_untyped_defs = True\n\ndisallow_any_decorated = True\ndisallow_any_explicit = True\ndisallow_any_generics = True\ndisallow_any_unimported = True\ndisallow_subclassing_any = True\n"
  },
  {
    "path": "python/pyproject.toml.in",
    "content": "[build-system]\nrequires = [\"setuptools >= 64\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"gtirb\"\ndynamic = [\"version\"]\ndescription = \"GrammaTech Intermediate Representation for Binaries\"\nreadme = \"README\"\nauthors = [\n    {name = \"GrammaTech\", email=\"gtirb@grammatech.com\"},\n]\nlicense = {text = \"MIT\"}\n\nrequires-python = \">= 3.8\"\n\nclassifiers = [\n    \"Development Status :: 5 - Production/Stable\",\n    \"License :: OSI Approved :: MIT License\",\n    \"Operating System :: OS Independent\",\n    \"Programming Language :: Python :: 3\",\n    \"Programming Language :: Python :: 3.8\",\n    \"Programming Language :: Python :: 3.9\",\n    \"Programming Language :: Python :: 3.10\",\n    \"Programming Language :: Python :: 3.11\",\n    \"Programming Language :: Python :: 3.12\",\n    \"Programming Language :: Python :: 3.13\",\n]\n\ndependencies = [\n    \"intervaltree >= 3.0\",\n    \"networkx >= 2.3\",\n    \"networkx >= 2.6; python_version >= '3.9'\",\n    \"@GTIRB_PROTOBUF_CONSTRAINT@\",\n    \"protobuf >= 3.8; python_version >= '3.10'\",\n    # TODO: uncomment after we drop support for protobuf < 3.19.\n    # \"protobuf >= 5.27; python_version >= '3.14'\",\n    \"sortedcontainers >= 2.0\",\n    \"sortedcontainers >= 2.0.5; python_version >= '3.10'\",\n    \"typing-extensions >= 3.7.4.3\",\n]\n\n[project.urls]\nHomepage = \"https://github.com/grammatech/gtirb\"\nDocumentation = \"https://grammatech.github.io/gtirb/python/index.html\"\nRepository = \"https://github.com/grammatech/gtirb.git\"\nIssues = \"https://github.com/GrammaTech/gtirb/issues\"\n\n[tool.setuptools]\npackages = [\"gtirb\", \"gtirb.proto\"]\n\n[tool.setuptools.dynamic]\nversion = {attr = \"gtirb.version.API_VERSION\"}\n\n[tool.coverage.run]\nsource_pkgs = [\"gtirb\"]\nomit = [\"*/gtirb/proto/*\"]\nbranch = true\n\n[tool.coverage.report]\nfail_under = 75\nshow_missing = true\n\n[tool.coverage.paths]\nsource = [\n    \".\",\n    \"*/site-packages\",\n]\n"
  },
  {
    "path": "python/requirements-dev.txt",
    "content": "pre-commit>=3.0\npytest>=7.4\npytest-cov>=4.0\nsphinx >= 7.0\nsphinx-autodoc-typehints >= 2.0\ntox>=4.0\ntox-uv>=1.0\n"
  },
  {
    "path": "python/requirements-mypy.txt",
    "content": "# Type stubs have a separate requirements file so they can be excluded from the\n# prerelease environments in tox.ini. In particular, mypy-protobuf depends on a\n# much newer version of protobuf than we actually require at runtime.\nmypy==0.961\nmypy-protobuf==3.3.0\ntypes-protobuf==3.20.4\n"
  },
  {
    "path": "python/stubs/README.md",
    "content": "Stubs for packages that do not include type annotations recognized by mypy.\n\nGeneric type stubs were handwritten to enable more precise type checking.\nThey are deliberately incomplete, only including the operations used in the\nGTIRB implementation.\n"
  },
  {
    "path": "python/stubs/intervaltree/__init__.pyi",
    "content": "from .interval import Interval as Interval\nfrom .intervaltree import IntervalTree as IntervalTree\n"
  },
  {
    "path": "python/stubs/intervaltree/interval.pyi",
    "content": "from typing import Generic, TypeVar\n\nPointT = TypeVar(\"PointT\", covariant=True)\nDataT = TypeVar(\"DataT\", covariant=True)\n\nclass Interval(Generic[PointT, DataT]):\n    begin: PointT\n    end: PointT\n    data: DataT\n    def __init__(self, begin: PointT, end: PointT, data: DataT): ...\n    def length(self) -> PointT: ...\n"
  },
  {
    "path": "python/stubs/intervaltree/intervaltree.pyi",
    "content": "from typing import Iterable, Iterator, MutableSet, Set, TypeVar, overload\n\nfrom .interval import Interval\n\nPointT = TypeVar(\"PointT\")\nDataT = TypeVar(\"DataT\")\n\nclass IntervalTree(MutableSet[Interval[PointT, DataT]]):\n    def __init__(\n        self, intervals: Iterable[Interval[PointT, DataT]] | None = ...\n    ): ...\n    def __contains__(self, item: object) -> bool: ...\n    def __iter__(self) -> Iterator[Interval[PointT, DataT]]: ...\n    def __len__(self) -> int: ...\n    def add(self, interval: Interval[PointT, DataT]) -> None: ...\n    def discard(self, interval: Interval[PointT, DataT]) -> None: ...\n    def begin(self) -> PointT: ...\n    def span(self) -> PointT: ...\n    @overload\n    def overlap(\n        self, begin: Interval[PointT, DataT]\n    ) -> Set[Interval[PointT, DataT]]: ...\n    @overload\n    def overlap(\n        self, begin: PointT, end: PointT\n    ) -> Set[Interval[PointT, DataT]]: ...\n"
  },
  {
    "path": "python/stubs/networkx/__init__.pyi",
    "content": "from networkx.classes import *\n"
  },
  {
    "path": "python/stubs/networkx/classes/__init__.pyi",
    "content": "from .multidigraph import MultiDiGraph as MultiDiGraph\n"
  },
  {
    "path": "python/stubs/networkx/classes/multidigraph.pyi",
    "content": "from typing import (\n    Collection,\n    Dict,\n    Generic,\n    Iterable,\n    Tuple,\n    TypeVar,\n    overload,\n)\nfrom typing_extensions import Literal\n\nNodeT = TypeVar(\"NodeT\")\nKeyT = TypeVar(\"KeyT\")\nDataT = TypeVar(\"DataT\")\n\nclass MultiDiGraph(Generic[NodeT, KeyT, DataT]):\n    def __contains__(self, n: object) -> bool: ...\n    def __getitem__(\n        self, n: NodeT\n    ) -> Dict[NodeT, Dict[KeyT, Dict[str, DataT]]]: ...\n    def add_edge(\n        self, u: NodeT, v: NodeT, key: KeyT | None = ..., **attr: DataT\n    ) -> KeyT: ...\n    def remove_edge(\n        self, u: NodeT, v: NodeT, key: KeyT | None = ...\n    ) -> None: ...\n    def number_of_edges(\n        self, u: NodeT | None = ..., v: NodeT | None = ...\n    ) -> int: ...\n    def clear(self) -> None: ...\n    # The actual types of edges(), out_edges(), and in_edges() are remarkably\n    # complicated. Depending on various combinations of arguments, they can\n    # retrieve a collection of tuples of two, three, or four elements. These\n    # overloads are specifically just the cases currently used by CFG, and do\n    # not remotely cover all valid combinations of arguments.\n    @overload\n    def edges(\n        self,\n        nbunch: Iterable[NodeT] | NodeT | None = ...,\n        data: Literal[False] = ...,\n    ) -> Collection[Tuple[NodeT, NodeT]]: ...\n    @overload\n    def edges(\n        self,\n        nbunch: Iterable[NodeT] | NodeT | None = ...,\n        *,\n        data: str,\n        default: DataT | None = ...,\n    ) -> Collection[Tuple[NodeT, NodeT, DataT | None]]: ...\n    def out_edges(\n        self,\n        nbunch: Iterable[NodeT] | NodeT | None = ...,\n        *,\n        data: str = ...,\n        default: DataT | None = ...,\n    ) -> Collection[Tuple[NodeT, NodeT, DataT | None]]: ...\n    def in_edges(\n        self,\n        nbunch: Iterable[NodeT] | NodeT | None = ...,\n        *,\n        data: str = ...,\n        default: DataT | None = ...,\n    ) -> Collection[Tuple[NodeT, NodeT, DataT | None]]: ...\n"
  },
  {
    "path": "python/stubs/sortedcontainers/__init__.pyi",
    "content": "from .sorteddict import SortedDict as SortedDict\n"
  },
  {
    "path": "python/stubs/sortedcontainers/sorteddict.pyi",
    "content": "from typing import MutableMapping, Iterator, Tuple, TypeVar\n\nK = TypeVar(\"K\")\nV = TypeVar(\"V\")\n\nclass SortedDict(MutableMapping[K, V]):\n    def __delitem__(self, key: K) -> None: ...\n    def __getitem__(self, key: K) -> V: ...\n    def __iter__(self) -> Iterator[K]: ...\n    def __len__(self) -> int: ...\n    def __setitem__(self, key: K, value: V) -> None: ...\n    def irange(\n        self,\n        minimum: K | None = ...,\n        maximum: K | None = ...,\n        inclusive: Tuple[bool, bool] = ...,\n        reverse: bool = ...,\n    ) -> Iterator[K]: ...\n"
  },
  {
    "path": "python/tests/helpers.py",
    "content": "import enum\nimport functools\n\nimport gtirb\n\n\nclass SearchScope(enum.Enum):\n    ir = 1\n    module = 2\n    section = 3\n    byte_interval = 4\n\n    def select(self, ir, m, s, bi):\n        \"\"\"\n        Given an IR, Module, Section, and ByteInterval, returns the object\n        that matches this scope.\n        \"\"\"\n        if self == SearchScope.ir:\n            return ir\n        if self == SearchScope.module:\n            return m\n        if self == SearchScope.section:\n            return s\n        if self == SearchScope.byte_interval:\n            return bi\n        assert False\n\n\ndef parameterize_one(name, values):\n    \"\"\"\n    A decorator that paramaterizes a test case.\n    :param name: The parameter name to parameterize.\n    :param values: The values to supply to the parameter.\n    \"\"\"\n\n    def decorator(f):\n        @functools.wraps(f)\n        def run_test(self, *args, **kwargs):\n            for value in values:\n                arg = {name: value}\n                with self.subTest(**arg):\n                    f(self, *args, **arg, **kwargs)\n\n        return run_test\n\n    return decorator\n\n\ndef create_interval_etc(address, size):\n    \"\"\"\n    Creates a byte interval and all of the containing structures.\n    \"\"\"\n    ir = gtirb.IR()\n    m = gtirb.Module(name=\"test\", ir=ir)\n    s = gtirb.Section(name=\".text\", module=m)\n    bi = gtirb.ByteInterval(address=address, size=size, section=s)\n    return ir, m, s, bi\n"
  },
  {
    "path": "python/tests/test_auxdata.py",
    "content": "import unittest\nfrom unittest import mock\n\nimport gtirb\n\n\nclass AuxDataTest(unittest.TestCase):\n    def setUp(self):\n        self.fake_ir = mock.MagicMock()\n        self.fake_ir.get_by_uuid = None\n\n    def test_lazy(self):\n        ad1 = gtirb.AuxData(\"test1\", \"string\")\n        self.assertEqual(ad1.data, \"test1\")\n\n        serialized = ad1._to_protobuf()\n        ad2 = gtirb.AuxData._from_protobuf(serialized, self.fake_ir)\n        # Peek inside: the data is not yet deserialized\n        self.assertTrue(ad2._data is None)\n\n        # Accessing the data should deserialize\n        self.assertEqual(ad1.data, ad2.data)\n        self.assertTrue(ad2._data is not None)\n\n        # Just exercise repr\n        self.assertEqual(\n            repr(ad2), \"AuxData(type_name='string', data='test1', )\"\n        )\n\n    def test_lazy_never_deserialized(self):\n        serialized = gtirb.AuxData(\"testing 123\", \"string\")._to_protobuf()\n\n        ad1 = gtirb.AuxData._from_protobuf(serialized, self.fake_ir)\n        # Peek inside: the data is not yet deserialized\n        self.assertTrue(ad1._data is None)\n\n        serialized2 = ad1._to_protobuf()\n        self.assertTrue(ad1._data is None)\n        self.assertEqual(serialized, serialized2)\n\n\nif __name__ == \"__main__\":\n    unittest.main()\n"
  },
  {
    "path": "python/tests/test_block.py",
    "content": "import unittest\n\nfrom helpers import create_interval_etc\n\nimport gtirb\n\n\nclass BlockTest(unittest.TestCase):\n    def test_contains_offset(self):\n        node = gtirb.CodeBlock(offset=123, size=456, decode_mode=789)\n        self.assertTrue(node.contains_offset(127))\n        self.assertFalse(node.contains_offset(121))\n\n    def test_contains_address(self):\n        block = gtirb.CodeBlock(offset=123, size=456, decode_mode=789)\n        byte_interval = gtirb.ByteInterval(  # noqa: F841\n            address=0x0, size=579, blocks=(block,)\n        )\n        self.assertTrue(block.contains_address(323))  # addr: 0x143\n        self.assertFalse(block.contains_address(107))  # addr: 0x6b\n\n    def test_block_references(self):\n        ir, m, s, bi = create_interval_etc(address=0x1000, size=4)\n        b1 = gtirb.CodeBlock(offset=0, size=2, byte_interval=bi)\n        b2 = gtirb.CodeBlock(offset=2, size=2, byte_interval=bi)\n\n        found = set(b1.references)\n        self.assertEqual(found, set())\n\n        s1 = gtirb.Symbol(name=\"hello\", module=m, payload=b1)\n        s2 = gtirb.Symbol(name=\"world\", module=m, payload=b2)\n\n        found = set(b1.references)\n        self.assertEqual(found, {s1})\n\n        found = set(b2.references)\n        self.assertEqual(found, {s2})\n\n        # Change the referent to verify we update the index\n        s1.referent = b2\n        found = set(b1.references)\n        self.assertEqual(found, set())\n\n        found = set(b2.references)\n        self.assertEqual(found, {s1, s2})\n\n        # Discard the symbol to verify we update the index\n        m.symbols.discard(s1)\n        found = set(b2.references)\n        self.assertEqual(found, {s2})\n\n        # Now add it back to verify we update the index\n        m.symbols.add(s1)\n        found = set(b2.references)\n        self.assertEqual(found, {s1, s2})\n\n        # Then set the payload to an integer to make sure we handle that right\n        s1.value = 1\n        s2.value = 1\n        found = set(b2.references)\n        self.assertEqual(found, set())\n"
  },
  {
    "path": "python/tests/test_blocks_at.py",
    "content": "# noqa: F841\n\nimport unittest\n\nfrom helpers import SearchScope, create_interval_etc, parameterize_one\n\nimport gtirb\n\n\nclass BlocksAtTests(unittest.TestCase):\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_blocks_at_simple(self, scope):\n        ir, m, s, bi = create_interval_etc(address=0x1000, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi)\n\n        found = set(search_in.byte_blocks_at(0x1000))\n        self.assertEqual(found, {code_block})\n\n        # Change the offset to verify we update the index\n        code_block.offset = 2\n        found = set(search_in.byte_blocks_at(0x1000))\n        self.assertEqual(found, set())\n\n        found = set(search_in.byte_blocks_at(0x1002))\n        self.assertEqual(found, {code_block})\n\n        # Discard the block to verify we update the index\n        bi.blocks.discard(code_block)\n        found = set(search_in.byte_blocks_at(0x1002))\n        self.assertEqual(found, set())\n\n        # Now add it back to verify we update the index\n        bi.blocks.add(code_block)\n        found = set(search_in.byte_blocks_at(0x1002))\n        self.assertEqual(found, {code_block})\n\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_blocks_at_zero(self, scope):\n        ir, m, s, bi = create_interval_etc(address=0, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=3, byte_interval=bi)\n\n        found = set(search_in.byte_blocks_at(0))\n        self.assertEqual(found, {code_block})\n\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_blocks_at_overlapping(self, scope):\n        \"Test that byte_blocks_at only looks at starting addresses\"\n        ir, m, s, bi = create_interval_etc(address=0x1000, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=0, size=2, byte_interval=bi)\n        code_block3 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi)\n\n        found = set(search_in.byte_blocks_at(0x1001))\n        self.assertEqual(found, {code_block3})\n\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_blocks_at_zero_sized(self, scope):\n        \"Test that byte_blocks_at can find zero-sized blocks\"\n        ir, m, s, bi = create_interval_etc(address=0x1000, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=1, size=0, byte_interval=bi)\n        code_block3 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi)\n        search_in = scope.select(ir, m, s, bi)\n\n        found = set(search_in.byte_blocks_at(0x1001))\n        self.assertEqual(found, {code_block2, code_block3})\n\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_blocks_at_range(self, scope):\n        \"Test that byte_blocks_at works with ranges\"\n        ir, m, s, bi = create_interval_etc(address=0x1000, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi)\n        code_block3 = gtirb.CodeBlock(offset=2, size=1, byte_interval=bi)\n\n        found = set(search_in.byte_blocks_at(range(0x1000, 0x1001)))\n        self.assertEqual(found, {code_block})\n\n        found = set(search_in.byte_blocks_at(range(0x1001, 0x1003)))\n        self.assertEqual(found, {code_block2, code_block3})\n\n        # Now try with a range with a step to make sure that we actually\n        # respect what the range tells us.\n        found = set(search_in.byte_blocks_at(range(0x1000, 0x1004, 2)))\n        self.assertEqual(found, {code_block, code_block3})\n\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_blocks_at_no_address(self, scope):\n        \"Test that byte_blocks_at does nothing if we don't have an address\"\n        ir, m, s, bi = create_interval_etc(address=None, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi)\n\n        found = set(search_in.byte_blocks_at(0x1000))\n        self.assertEqual(found, set())\n\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_code_blocks_at(self, scope):\n        \"Test that code_blocks_at only gives back CodeBlocks\"\n        ir, m, s, bi = create_interval_etc(address=0x1000, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        data_block = gtirb.DataBlock(offset=0, size=1, byte_interval=bi)\n\n        found = set(search_in.code_blocks_at(0x1000))\n        self.assertEqual(found, {code_block})\n\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_data_blocks_at(self, scope):\n        \"Test that data_blocks_at only gives back DataBlocks\"\n        ir, m, s, bi = create_interval_etc(address=0x1000, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        data_block = gtirb.DataBlock(offset=0, size=1, byte_interval=bi)\n\n        found = set(search_in.data_blocks_at(0x1000))\n        self.assertEqual(found, {data_block})\n\n\nclass SectionBlocksAtTests(unittest.TestCase):\n    def test_blocks_at_simple(self):\n        s = gtirb.Section()\n\n        bi1 = gtirb.ByteInterval(address=0x1000, size=4, section=s)\n        bi1_block1 = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi1)\n        bi1_block2 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi1)\n\n        bi2 = gtirb.ByteInterval(address=0x1004, size=4, section=s)\n        bi2_block1 = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi2)\n        bi2_block2 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi2)\n\n        found = set(s.byte_blocks_at(0x1000))\n        self.assertEqual(found, {bi1_block1})\n\n    def test_blocks_at_overlapping(self):\n        \"Test that we find the correct blocks if two byte intervals overlap\"\n        s = gtirb.Section()\n\n        bi1 = gtirb.ByteInterval(address=0x1000, size=4, section=s)\n        bi1_block1 = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi1)\n        bi1_block2 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi1)\n\n        bi2 = gtirb.ByteInterval(address=0x1000, size=4, section=s)\n        bi2_block1 = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi2)\n        bi2_block2 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi2)\n\n        found = set(s.byte_blocks_at(0x1000))\n        self.assertEqual(found, {bi1_block1, bi2_block1})\n\n    def test_blocks_on_with_blocks_outside_bi(self):\n        \"Tests that we can handle byte intervals with blocks outside\"\n        s = gtirb.Section()\n\n        bi1 = gtirb.ByteInterval(address=0x1000, size=1, section=s)\n        bi1_block1 = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi1)\n        bi1_block2 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi1)\n\n        found = set(s.byte_blocks_at(0x1000))\n        self.assertEqual(found, {bi1_block1})\n\n        # These blocks are outside of the byte interval's declared size, so\n        # either interpretation is fair game.\n        found = set(s.byte_blocks_at(0x1001))\n        self.assertTrue(found == set() or found == {bi1_block2})\n"
  },
  {
    "path": "python/tests/test_blocks_at_offset.py",
    "content": "# noqa: F841\n\nimport unittest\n\nfrom helpers import create_interval_etc\n\nimport gtirb\n\n\nclass BlocksAtOffsetTests(unittest.TestCase):\n    def test_blocks_at_offset_simple(self):\n        ir, m, s, bi = create_interval_etc(address=None, size=4)\n\n        # Ensure we always have a couple blocks in the index beyond what we\n        # are querying so that we don't just rebuild the tree from scratch\n        # every time.\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi)\n        code_block3 = gtirb.CodeBlock(offset=2, size=1, byte_interval=bi)\n\n        found = set(bi.byte_blocks_at_offset(0))\n        self.assertEqual(found, {code_block})\n\n        # Change the offset to verify we update the index\n        code_block.offset = 3\n        found = set(bi.byte_blocks_at_offset(0))\n        self.assertEqual(found, set())\n\n        found = set(bi.byte_blocks_at_offset(3))\n        self.assertEqual(found, {code_block})\n\n        # Discard the block to verify we update the index\n        bi.blocks.discard(code_block)\n        found = set(bi.byte_blocks_at_offset(3))\n        self.assertEqual(found, set())\n\n        # Now add it back to verify we update the index\n        bi.blocks.add(code_block)\n        found = set(bi.byte_blocks_at_offset(3))\n        self.assertEqual(found, {code_block})\n\n    def test_blocks_at_offset_overlapping(self):\n        \"Test that byte_blocks_at_offset only looks at starting offsets\"\n        ir, m, s, bi = create_interval_etc(address=None, size=4)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=0, size=2, byte_interval=bi)\n        code_block3 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi)\n\n        found = set(bi.byte_blocks_at_offset(1))\n        self.assertEqual(found, {code_block3})\n\n    def test_blocks_at_offset_zero_sized(self):\n        \"Test that byte_blocks_at_offset can find zero-sized blocks\"\n        ir, m, s, bi = create_interval_etc(address=None, size=4)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=1, size=0, byte_interval=bi)\n        code_block3 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi)\n\n        found = set(bi.byte_blocks_at_offset(1))\n        self.assertEqual(found, {code_block2, code_block3})\n\n    def test_blocks_at_offset_range(self):\n        \"Test that byte_blocks_at_offset works with ranges\"\n        ir, m, s, bi = create_interval_etc(address=None, size=4)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi)\n        code_block3 = gtirb.CodeBlock(offset=2, size=1, byte_interval=bi)\n\n        found = set(bi.byte_blocks_at_offset(range(0, 1)))\n        self.assertEqual(found, {code_block})\n\n        found = set(bi.byte_blocks_at_offset(range(1, 3)))\n        self.assertEqual(found, {code_block2, code_block3})\n\n        # Now try with a range with a step to make sure that we actually\n        # respect what the range tells us.\n        found = set(bi.byte_blocks_at_offset(range(0, 4, 2)))\n        self.assertEqual(found, {code_block, code_block3})\n\n    def test_code_blocks_at_offset(self):\n        \"Test that code_blocks_at_offset only gives back CodeBlocks\"\n        ir, m, s, bi = create_interval_etc(address=None, size=4)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        data_block = gtirb.DataBlock(offset=0, size=1, byte_interval=bi)\n\n        found = set(bi.code_blocks_at_offset(0))\n        self.assertEqual(found, {code_block})\n\n    def test_data_blocks_at_offset(self):\n        \"Test that data_blocks_at_offset only gives back DataBlocks\"\n        ir, m, s, bi = create_interval_etc(address=None, size=4)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        data_block = gtirb.DataBlock(offset=0, size=1, byte_interval=bi)\n\n        found = set(bi.data_blocks_at_offset(0))\n        self.assertEqual(found, {data_block})\n"
  },
  {
    "path": "python/tests/test_blocks_on.py",
    "content": "import unittest\n\nfrom helpers import SearchScope, create_interval_etc, parameterize_one\n\nimport gtirb\n\n\nclass BlocksOnTests(unittest.TestCase):\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_blocks_on_simple(self, scope):\n        ir, m, s, bi = create_interval_etc(address=0x1000, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=3, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=3, size=1, byte_interval=bi)\n\n        found = set(search_in.byte_blocks_on(0x1001))\n        self.assertEqual(found, {code_block})\n\n        found = set(search_in.byte_blocks_on(0x1003))\n        self.assertEqual(found, {code_block2})\n\n        # Change the offset to verify we update the index\n        code_block.offset = 2\n        found = set(search_in.byte_blocks_on(0x1000))\n        self.assertEqual(found, set())\n\n        found = set(search_in.byte_blocks_on(0x1002))\n        self.assertEqual(found, {code_block})\n\n        # Discard the block to verify we update the index\n        bi.blocks.discard(code_block)\n        found = set(search_in.byte_blocks_on(0x1002))\n        self.assertEqual(found, set())\n\n        # Now add it back to verify we update the index\n        bi.blocks.add(code_block)\n        found = set(search_in.byte_blocks_on(0x1002))\n        self.assertEqual(found, {code_block})\n\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_blocks_on_zero(self, scope):\n        ir, m, s, bi = create_interval_etc(address=0, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=3, byte_interval=bi)\n\n        found = set(search_in.byte_blocks_on(0))\n        self.assertEqual(found, {code_block})\n\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_blocks_on_with_overlapping_blocks(self, scope):\n        \"Test that byte_blocks_on returns all blocks that overlap an address\"\n        ir, m, s, bi = create_interval_etc(address=0x1000, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=0, size=2, byte_interval=bi)\n        code_block3 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi)\n\n        found = set(search_in.byte_blocks_on(0x1001))\n        self.assertEqual(found, {code_block2, code_block3})\n\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_blocks_on_with_zero_sized_blocks(self, scope):\n        \"Test that byte_blocks_on doesn't find zero-sized blocks\"\n        ir, m, s, bi = create_interval_etc(address=0x1000, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=3, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=1, size=0, byte_interval=bi)\n        code_block3 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi)\n\n        found = set(search_in.byte_blocks_on(0x1001))\n        self.assertEqual(found, {code_block, code_block3})\n\n        found = set(search_in.byte_blocks_on(range(0x1001, 0x1002)))\n        self.assertEqual(found, {code_block, code_block3})\n\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_blocks_on_with_range(self, scope):\n        \"Test that byte_blocks_on handles ranges\"\n        ir, m, s, bi = create_interval_etc(address=0x1000, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=2, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=2, size=1, byte_interval=bi)\n        code_block3 = gtirb.CodeBlock(offset=3, size=1, byte_interval=bi)\n\n        found = set(search_in.byte_blocks_on(range(0x1000, 0x1004)))\n        self.assertEqual(found, {code_block, code_block2, code_block3})\n\n        found = set(search_in.byte_blocks_on(range(0x1002, 0x1002)))\n        self.assertEqual(found, set())\n\n        # Passing a different step doesn't make a ton of sense, but it should\n        # work.\n        found = set(search_in.byte_blocks_on(range(0x1000, 0x1004, 2)))\n        self.assertEqual(found, {code_block, code_block2, code_block3})\n\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_blocks_on_with_no_address(self, scope):\n        \"Test that byte_blocks_on does nothing if we don't have an address\"\n        ir, m, s, bi = create_interval_etc(address=None, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=2, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=2, size=1, byte_interval=bi)\n        code_block3 = gtirb.CodeBlock(offset=3, size=1, byte_interval=bi)\n\n        found = set(search_in.byte_blocks_on(range(0x1000, 0x1004)))\n        self.assertEqual(found, set())\n\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_code_blocks_on(self, scope):\n        \"Test that code_blocks_on only gives back CodeBlocks\"\n        ir, m, s, bi = create_interval_etc(address=0x1000, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        data_block = gtirb.DataBlock(offset=1, size=1, byte_interval=bi)\n\n        found = set(search_in.code_blocks_on(range(0x1000, 0x1004)))\n        self.assertEqual(found, {code_block})\n\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_data_blocks_on(self, scope):\n        \"Test that data_blocks_on only gives back DataBlocks\"\n        ir, m, s, bi = create_interval_etc(address=0x1000, size=4)\n        search_in = scope.select(ir, m, s, bi)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        data_block = gtirb.DataBlock(offset=1, size=1, byte_interval=bi)\n\n        found = set(search_in.data_blocks_on(range(0x1000, 0x1004)))\n        self.assertEqual(found, {data_block})\n\n\nclass SectionBlocksOnTests(unittest.TestCase):\n    def test_blocks_on_simple(self):\n        s = gtirb.Section()\n\n        bi1 = gtirb.ByteInterval(address=0x1000, size=4, section=s)\n        bi1_block1 = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi1)\n        bi1_block2 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi1)\n\n        bi2 = gtirb.ByteInterval(address=0x1004, size=4, section=s)\n        bi2_block1 = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi2)\n        bi2_block2 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi2)\n\n        found = set(s.byte_blocks_on(0x1001))\n        self.assertEqual(found, {bi1_block2})\n\n    def test_blocks_on_overlapping(self):\n        \"Test that we find the correct blocks if two byte intervals overlap\"\n        s = gtirb.Section()\n\n        bi1 = gtirb.ByteInterval(address=0x1000, size=4, section=s)\n        bi1_block1 = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi1)\n        bi1_block2 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi1)\n\n        bi2 = gtirb.ByteInterval(address=0x1000, size=4, section=s)\n        bi2_block1 = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi2)\n        bi2_block2 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi2)\n\n        found = set(s.byte_blocks_on(0x1001))\n        self.assertEqual(found, {bi1_block2, bi2_block2})\n\n    def test_blocks_on_with_blocks_outside_bi(self):\n        \"Tests that we can handle byte intervals with blocks outside\"\n        s = gtirb.Section()\n\n        bi1 = gtirb.ByteInterval(address=0x1000, size=1, section=s)\n        bi1_block1 = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi1)\n        bi1_block2 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi1)\n\n        found = set(s.byte_blocks_on(0x1000))\n        self.assertEqual(found, {bi1_block1})\n\n        # These blocks are outside of the byte interval's declared size, so\n        # either interpretation is fair game.\n        found = set(s.byte_blocks_on(0x1001))\n        self.assertTrue(found == set() or found == {bi1_block2})\n"
  },
  {
    "path": "python/tests/test_blocks_on_offset.py",
    "content": "import unittest\n\nfrom helpers import create_interval_etc\n\nimport gtirb\n\n\nclass BlocksOnOffsetTests(unittest.TestCase):\n    def test_blocks_on_offset_simple(self):\n        ir, m, s, bi = create_interval_etc(address=None, size=4)\n\n        code_block = gtirb.CodeBlock(offset=0, size=3, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=3, size=1, byte_interval=bi)\n\n        found = set(bi.byte_blocks_on_offset(1))\n        self.assertEqual(found, {code_block})\n\n        found = set(bi.byte_blocks_on_offset(3))\n        self.assertEqual(found, {code_block2})\n\n        # Change the offset to verify we update the index\n        code_block.offset = 2\n        found = set(bi.byte_blocks_on_offset(0))\n        self.assertEqual(found, set())\n\n        found = set(bi.byte_blocks_on_offset(2))\n        self.assertEqual(found, {code_block})\n\n        # Discard the block to verify we update the index\n        bi.blocks.discard(code_block)\n        found = set(bi.byte_blocks_on_offset(2))\n        self.assertEqual(found, set())\n\n        # Now add it back to verify we update the index\n        bi.blocks.add(code_block)\n        found = set(bi.byte_blocks_on_offset(2))\n        self.assertEqual(found, {code_block})\n\n    def test_blocks_on_offset_zero(self):\n        ir, m, s, bi = create_interval_etc(address=None, size=4)\n\n        code_block = gtirb.CodeBlock(offset=0, size=3, byte_interval=bi)\n\n        found = set(bi.byte_blocks_on_offset(0))\n        self.assertEqual(found, {code_block})\n\n    def test_blocks_on_offset_with_overlapping_blocks(self):\n        \"\"\"\n        Test that byte_blocks_on_offset returns all blocks that overlap an\n        offset.\n        \"\"\"\n        ir, m, s, bi = create_interval_etc(address=None, size=4)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=0, size=2, byte_interval=bi)\n        code_block3 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi)\n\n        found = set(bi.byte_blocks_on_offset(1))\n        self.assertEqual(found, {code_block2, code_block3})\n\n    def test_blocks_on_offset_with_zero_sized_blocks(self):\n        \"Test that byte_blocks_on_offset doesn't find zero-sized blocks\"\n        ir, m, s, bi = create_interval_etc(address=None, size=4)\n\n        code_block = gtirb.CodeBlock(offset=0, size=3, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=1, size=0, byte_interval=bi)\n        code_block3 = gtirb.CodeBlock(offset=1, size=1, byte_interval=bi)\n\n        found = set(bi.byte_blocks_on_offset(1))\n        self.assertEqual(found, {code_block, code_block3})\n\n        found = set(bi.byte_blocks_on_offset(range(1, 2)))\n        self.assertEqual(found, {code_block, code_block3})\n\n    def test_blocks_on_offset_with_range(self):\n        \"Test that byte_blocks_on_offset handles ranges\"\n        ir, m, s, bi = create_interval_etc(address=None, size=4)\n\n        code_block = gtirb.CodeBlock(offset=0, size=2, byte_interval=bi)\n        code_block2 = gtirb.CodeBlock(offset=2, size=1, byte_interval=bi)\n        code_block3 = gtirb.CodeBlock(offset=3, size=1, byte_interval=bi)\n\n        found = set(bi.byte_blocks_on_offset(range(0, 4)))\n        self.assertEqual(found, {code_block, code_block2, code_block3})\n\n        found = set(bi.byte_blocks_on_offset(range(2, 2)))\n        self.assertEqual(found, set())\n\n        # Passing a different step doesn't make a ton of sense, but it should\n        # work.\n        found = set(bi.byte_blocks_on_offset(range(0, 4, 2)))\n        self.assertEqual(found, {code_block, code_block2, code_block3})\n\n    def test_code_blocks_on_offset(self):\n        \"Test that code_blocks_on_offset only gives back CodeBlocks\"\n        ir, m, s, bi = create_interval_etc(address=None, size=4)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        data_block = gtirb.DataBlock(offset=1, size=1, byte_interval=bi)\n\n        found = set(bi.code_blocks_on_offset(range(0, 4)))\n        self.assertEqual(found, {code_block})\n\n    def test_data_blocks_on_offset(self):\n        \"Test that data_blocks_on_offset only gives back DataBlocks\"\n        ir, m, s, bi = create_interval_etc(address=None, size=4)\n\n        code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi)\n        data_block = gtirb.DataBlock(offset=1, size=1, byte_interval=bi)\n\n        found = set(bi.data_blocks_on_offset(range(0, 4)))\n        self.assertEqual(found, {data_block})\n"
  },
  {
    "path": "python/tests/test_byte_intervals_at.py",
    "content": "import unittest\n\nfrom helpers import SearchScope, parameterize_one\n\nimport gtirb\n\n\nclass ByteIntervalsAtTests(unittest.TestCase):\n    @parameterize_one(\n        \"scope\", (SearchScope.ir, SearchScope.module, SearchScope.section)\n    )\n    def test_byte_intervals_at(self, scope):\n        ir = gtirb.IR()\n        m = gtirb.Module(name=\"test\", ir=ir)\n        s = gtirb.Section(module=m)\n        search_in = scope.select(ir, m, s, None)\n\n        bi1 = gtirb.ByteInterval(address=0x1000, size=4, section=s)\n        bi2 = gtirb.ByteInterval(address=0x1004, size=4, section=s)\n\n        found = set(search_in.byte_intervals_at(0x1000))\n        self.assertEqual(found, {bi1})\n\n        found = set(search_in.byte_intervals_at(0x1001))\n        self.assertEqual(found, set())\n\n        found = set(search_in.byte_intervals_at(range(0x1000, 0x1008)))\n        self.assertEqual(found, {bi1, bi2})\n\n        found = set(search_in.byte_intervals_at(range(0x1000, 0x1008, 16)))\n        self.assertEqual(found, {bi1})\n\n        # Change the address to verify we update the index\n        bi2.address = 0x2000\n\n        found = set(search_in.byte_intervals_at(0x1004))\n        self.assertEqual(found, set())\n\n        found = set(search_in.byte_intervals_at(0x2000))\n        self.assertEqual(found, {bi2})\n\n        # Discard the interval to verify we update the index\n        bi2.section = None\n\n        found = set(search_in.byte_intervals_at(0x2000))\n        self.assertEqual(found, set())\n\n        # Now add it back to verify we update the index\n        s.byte_intervals.add(bi2)\n        found = set(search_in.byte_intervals_at(0x2000))\n        self.assertEqual(found, {bi2})\n"
  },
  {
    "path": "python/tests/test_byte_intervals_on.py",
    "content": "import unittest\n\nfrom helpers import SearchScope, parameterize_one\n\nimport gtirb\n\n\nclass ByteIntervalsOnTests(unittest.TestCase):\n    @parameterize_one(\n        \"scope\", (SearchScope.ir, SearchScope.module, SearchScope.section)\n    )\n    def test_byte_intervals_on(self, scope):\n        ir = gtirb.IR()\n        m = gtirb.Module(name=\"test\", ir=ir)\n        s = gtirb.Section(module=m)\n        search_in = scope.select(ir, m, s, None)\n\n        bi1 = gtirb.ByteInterval(address=0x1000, size=4, section=s)\n        bi2 = gtirb.ByteInterval(address=0x1004, size=4, section=s)\n\n        found = set(search_in.byte_intervals_on(0x1000))\n        self.assertEqual(found, {bi1})\n\n        found = set(search_in.byte_intervals_on(0x1001))\n        self.assertEqual(found, {bi1})\n\n        found = set(search_in.byte_intervals_on(range(0x1000, 0x1008)))\n        self.assertEqual(found, {bi1, bi2})\n\n        found = set(search_in.byte_intervals_on(range(0x1000, 0x1008, 16)))\n        self.assertEqual(found, {bi1, bi2})\n\n        # Change the address to verify we update the index\n        bi2.address = 0x2000\n\n        found = set(search_in.byte_intervals_on(0x1005))\n        self.assertEqual(found, set())\n\n        found = set(search_in.byte_intervals_on(0x2001))\n        self.assertEqual(found, {bi2})\n\n        # Discard the interval to verify we update the index\n        bi2.section = None\n\n        found = set(search_in.byte_intervals_on(0x2001))\n        self.assertEqual(found, set())\n\n        # Now add it back to verify we update the index\n        s.byte_intervals.add(bi2)\n        found = set(search_in.byte_intervals_on(0x2001))\n        self.assertEqual(found, {bi2})\n\n    @parameterize_one(\n        \"scope\", [SearchScope.ir, SearchScope.module, SearchScope.section]\n    )\n    def test_byte_intervals_overlapping(self, scope):\n        ir = gtirb.IR()\n        m = gtirb.Module(name=\"test\", ir=ir)\n        s = gtirb.Section(module=m)\n        search_in = scope.select(ir, m, s, None)\n\n        bi1 = gtirb.ByteInterval(address=0x1000, size=8, section=s)\n        bi2 = gtirb.ByteInterval(address=0x1004, size=4, section=s)\n\n        found = set(search_in.byte_intervals_on(0x1005))\n        self.assertEqual(found, {bi1, bi2})\n"
  },
  {
    "path": "python/tests/test_cfg.py",
    "content": "import unittest\n\nimport gtirb\n\n\nclass CFGTest(unittest.TestCase):\n    def test_contains(self):\n        b1, b2 = gtirb.ProxyBlock(), gtirb.ProxyBlock()\n        cfg = gtirb.CFG(\n            [gtirb.Edge(b1, b2, gtirb.Edge.Label(gtirb.Edge.Type.Branch))]\n        )\n        self.assertFalse(\n            gtirb.Edge(gtirb.ProxyBlock(), gtirb.ProxyBlock()) in cfg\n        )\n        self.assertFalse(\n            gtirb.Edge(b1, b2, gtirb.Edge.Label(gtirb.Edge.Type.Fallthrough))\n            in cfg\n        )\n        self.assertTrue(\n            gtirb.Edge(b1, b2, gtirb.Edge.Label(gtirb.Edge.Type.Branch)) in cfg\n        )\n\n    def test_add(self):\n        b1, b2 = gtirb.ProxyBlock(), gtirb.ProxyBlock()\n        cfg = gtirb.CFG()\n        cfg.add(gtirb.Edge(b1, b2))\n        cfg.add(gtirb.Edge(b1, b2))\n        cfg.add(gtirb.Edge(b1, b2, gtirb.Edge.Label(gtirb.Edge.Type.Branch)))\n        self.assertEqual(len(cfg), 2)\n        self.assertTrue(gtirb.Edge(b1, b2) in cfg)\n        self.assertTrue(\n            gtirb.Edge(b1, b2, gtirb.Edge.Label(gtirb.Edge.Type.Branch)) in cfg\n        )\n\n    def test_clear(self):\n        cfg = gtirb.CFG(\n            [\n                gtirb.Edge(gtirb.ProxyBlock(), gtirb.ProxyBlock()),\n                gtirb.Edge(\n                    gtirb.CodeBlock(offset=0, size=1),\n                    gtirb.CodeBlock(offset=1, size=2),\n                ),\n            ]\n        )\n        self.assertEqual(len(cfg), 2)\n\n        cfg.clear()\n        self.assertEqual(len(cfg), 0)\n\n    def test_discard(self):\n        b1, b2 = gtirb.ProxyBlock(), gtirb.CodeBlock(offset=0, size=1)\n        cfg = gtirb.CFG(\n            [\n                gtirb.Edge(b1, b2),\n                gtirb.Edge(\n                    gtirb.ProxyBlock(), gtirb.CodeBlock(offset=1, size=2)\n                ),\n            ]\n        )\n        self.assertEqual(len(cfg), 2)\n\n        cfg.discard(gtirb.Edge(b1, b2))\n        self.assertEqual(len(cfg), 1)\n        self.assertFalse(gtirb.Edge(b1, b2) in cfg)\n\n        cfg.discard(gtirb.Edge(b1, b2))\n        self.assertEqual(len(cfg), 1)\n        self.assertFalse(gtirb.Edge(b1, b2) in cfg)\n\n    def test_out_edges(self):\n        b1, b2, b3 = gtirb.ProxyBlock(), gtirb.ProxyBlock(), gtirb.ProxyBlock()\n        b4 = gtirb.CodeBlock(offset=0, size=1)\n        cfg = gtirb.CFG(\n            [\n                gtirb.Edge(\n                    b1, b2, gtirb.Edge.Label(gtirb.Edge.Type.Fallthrough)\n                ),\n                gtirb.Edge(b1, b2, gtirb.Edge.Label(gtirb.Edge.Type.Branch)),\n                gtirb.Edge(b3, b2),\n            ]\n        )\n        self.assertEqual(sum(1 for _ in cfg.out_edges(b1)), 2)\n        self.assertEqual(sum(1 for _ in cfg.out_edges(b2)), 0)\n        self.assertEqual(sum(1 for _ in cfg.out_edges(b3)), 1)\n        self.assertEqual(sum(1 for _ in cfg.out_edges(b4)), 0)\n\n    def test_in_edges(self):\n        b1, b2, b3 = gtirb.ProxyBlock(), gtirb.ProxyBlock(), gtirb.ProxyBlock()\n        b4 = gtirb.CodeBlock(offset=0, size=1)\n        cfg = gtirb.CFG(\n            [\n                gtirb.Edge(\n                    b1, b2, gtirb.Edge.Label(gtirb.Edge.Type.Fallthrough)\n                ),\n                gtirb.Edge(b3, b2, gtirb.Edge.Label(gtirb.Edge.Type.Branch)),\n                gtirb.Edge(b1, b3),\n            ]\n        )\n        self.assertEqual(sum(1 for _ in cfg.in_edges(b1)), 0)\n        self.assertEqual(sum(1 for _ in cfg.in_edges(b2)), 2)\n        self.assertEqual(sum(1 for _ in cfg.in_edges(b3)), 1)\n        self.assertEqual(sum(1 for _ in cfg.in_edges(b4)), 0)\n\n    def test_nx(self):\n        b1, b2 = gtirb.ProxyBlock(), gtirb.ProxyBlock()\n        cfg = gtirb.CFG(\n            [gtirb.Edge(b1, b2, gtirb.Edge.Label(gtirb.Edge.Type.Call))]\n        )\n        for n1, n2, lab in cfg.nx().edges(data=\"label\"):\n            self.assertEqual(n1, b1)\n            self.assertEqual(n2, b2)\n            self.assertEqual(lab, gtirb.Edge.Label(gtirb.Edge.Type.Call))\n"
  },
  {
    "path": "python/tests/test_deep_eq.py",
    "content": "import unittest\nimport uuid\n\nimport gtirb\n\n\nclass DeepEqTest(unittest.TestCase):\n    def test_code_block(self):\n        id1 = uuid.uuid4()\n        id2 = uuid.uuid4()\n\n        b1 = gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id1)\n        b2 = gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id1)\n        self.assertTrue(b1.deep_eq(b2))\n\n        b2 = gtirb.CodeBlock(size=5, decode_mode=2, offset=3, uuid=id1)\n        self.assertFalse(b1.deep_eq(b2))\n\n        b2 = gtirb.CodeBlock(size=1, decode_mode=5, offset=3, uuid=id1)\n        self.assertFalse(b1.deep_eq(b2))\n\n        b2 = gtirb.CodeBlock(size=1, decode_mode=2, offset=5, uuid=id1)\n        self.assertFalse(b1.deep_eq(b2))\n\n        b2 = gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id2)\n        self.assertFalse(b1.deep_eq(b2))\n\n    def test_data_block(self):\n        id1 = uuid.uuid4()\n        id2 = uuid.uuid4()\n\n        b1 = gtirb.DataBlock(size=1, offset=3, uuid=id1)\n        b2 = gtirb.DataBlock(size=1, offset=3, uuid=id1)\n        self.assertTrue(b1.deep_eq(b2))\n\n        b2 = gtirb.DataBlock(size=5, offset=3, uuid=id1)\n        self.assertFalse(b1.deep_eq(b2))\n\n        b2 = gtirb.DataBlock(size=1, offset=5, uuid=id1)\n        self.assertFalse(b1.deep_eq(b2))\n\n        b2 = gtirb.DataBlock(size=1, offset=3, uuid=id2)\n        self.assertFalse(b1.deep_eq(b2))\n\n    def test_proxy_blocks(self):\n        id1 = uuid.uuid4()\n        id2 = uuid.uuid4()\n\n        b1 = gtirb.ProxyBlock(uuid=id1)\n        b2 = gtirb.ProxyBlock(uuid=id1)\n        self.assertTrue(b1.deep_eq(b2))\n\n        b2 = gtirb.ProxyBlock(uuid=id2)\n        self.assertFalse(b1.deep_eq(b2))\n\n    def test_symbol(self):\n        id1 = uuid.uuid4()\n        id2 = uuid.uuid4()\n\n        s1 = gtirb.Symbol(name=\"name\", payload=None, uuid=id1)\n        s2 = gtirb.Symbol(name=\"name\", payload=None, uuid=id1)\n        self.assertTrue(s1.deep_eq(s2))\n\n        s1 = gtirb.Symbol(name=\"name\", payload=5, uuid=id1)\n        s2 = gtirb.Symbol(name=\"name\", payload=5, uuid=id1)\n        self.assertTrue(s1.deep_eq(s2))\n\n        s1 = gtirb.Symbol(\n            name=\"name\",\n            payload=gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id1),\n            uuid=id1,\n        )\n        s2 = gtirb.Symbol(\n            name=\"name\",\n            payload=gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id1),\n            uuid=id1,\n        )\n        self.assertTrue(s1.deep_eq(s2))\n\n        s1 = gtirb.Symbol(name=\"name1\", payload=None, uuid=id1)\n        s2 = gtirb.Symbol(name=\"name2\", payload=None, uuid=id1)\n        self.assertFalse(s1.deep_eq(s2))\n\n        s1 = gtirb.Symbol(name=\"name\", payload=None, uuid=id1)\n        s2 = gtirb.Symbol(name=\"name\", payload=5, uuid=id1)\n        self.assertFalse(s1.deep_eq(s2))\n\n        s1 = gtirb.Symbol(\n            name=\"name\",\n            payload=gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id1),\n            uuid=id1,\n        )\n        s2 = gtirb.Symbol(\n            name=\"name\",\n            payload=gtirb.CodeBlock(size=2, decode_mode=2, offset=3, uuid=id1),\n            uuid=id1,\n        )\n        self.assertFalse(s1.deep_eq(s2))\n\n        s1 = gtirb.Symbol(name=\"name\", payload=None, uuid=id1)\n        s2 = gtirb.Symbol(name=\"name\", payload=None, uuid=id2)\n        self.assertFalse(s1.deep_eq(s2))\n\n    def test_sym_exprs(self):\n        id1 = uuid.uuid4()\n        id2 = uuid.uuid4()\n\n        # SymAddrConst\n        s1 = gtirb.SymAddrConst(\n            offset=1,\n            symbol=gtirb.Symbol(name=\"name\", payload=None, uuid=id1),\n            attributes={gtirb.SymbolicExpression.Attribute.G1},\n        )\n        s2 = gtirb.SymAddrConst(\n            offset=1,\n            symbol=gtirb.Symbol(name=\"name\", payload=None, uuid=id1),\n            attributes={gtirb.SymbolicExpression.Attribute.G1},\n        )\n        self.assertTrue(s1.deep_eq(s2))\n\n        s1 = gtirb.SymAddrConst(\n            offset=1, symbol=gtirb.Symbol(name=\"name\", payload=None, uuid=id1)\n        )\n        s2 = gtirb.SymAddrConst(\n            offset=2, symbol=gtirb.Symbol(name=\"name\", payload=None, uuid=id1)\n        )\n        self.assertFalse(s1.deep_eq(s2))\n\n        s1 = gtirb.SymAddrConst(\n            offset=1, symbol=gtirb.Symbol(name=\"name1\", payload=None, uuid=id1)\n        )\n        s2 = gtirb.SymAddrConst(\n            offset=1, symbol=gtirb.Symbol(name=\"name2\", payload=None, uuid=id1)\n        )\n        self.assertFalse(s1.deep_eq(s2))\n\n        s1 = gtirb.SymAddrConst(\n            offset=1,\n            symbol=gtirb.Symbol(name=\"name\", payload=None, uuid=id1),\n            attributes={gtirb.SymbolicExpression.Attribute.G1},\n        )\n        s2 = gtirb.SymAddrConst(\n            offset=1,\n            symbol=gtirb.Symbol(name=\"name\", payload=None, uuid=id1),\n        )\n        self.assertFalse(s1.deep_eq(s2))\n\n        # SymAddrAddr\n        s1 = gtirb.SymAddrAddr(\n            offset=1,\n            scale=2,\n            symbol1=gtirb.Symbol(name=\"name1\", payload=None, uuid=id1),\n            symbol2=gtirb.Symbol(name=\"name2\", payload=None, uuid=id2),\n            attributes={gtirb.SymbolicExpression.Attribute.G1},\n        )\n        s2 = gtirb.SymAddrAddr(\n            offset=1,\n            scale=2,\n            symbol1=gtirb.Symbol(name=\"name1\", payload=None, uuid=id1),\n            symbol2=gtirb.Symbol(name=\"name2\", payload=None, uuid=id2),\n            attributes={gtirb.SymbolicExpression.Attribute.G1},\n        )\n        self.assertTrue(s1.deep_eq(s2))\n\n        s1 = gtirb.SymAddrAddr(\n            offset=1,\n            scale=2,\n            symbol1=gtirb.Symbol(name=\"name1\", payload=None, uuid=id1),\n            symbol2=gtirb.Symbol(name=\"name2\", payload=None, uuid=id2),\n        )\n        s2 = gtirb.SymAddrAddr(\n            offset=2,\n            scale=2,\n            symbol1=gtirb.Symbol(name=\"name1\", payload=None, uuid=id1),\n            symbol2=gtirb.Symbol(name=\"name2\", payload=None, uuid=id2),\n        )\n        self.assertFalse(s1.deep_eq(s2))\n\n        s1 = gtirb.SymAddrAddr(\n            offset=1,\n            scale=2,\n            symbol1=gtirb.Symbol(name=\"name1\", payload=None, uuid=id1),\n            symbol2=gtirb.Symbol(name=\"name2\", payload=None, uuid=id2),\n        )\n        s2 = gtirb.SymAddrAddr(\n            offset=1,\n            scale=4,\n            symbol1=gtirb.Symbol(name=\"name1\", payload=None, uuid=id1),\n            symbol2=gtirb.Symbol(name=\"name2\", payload=None, uuid=id2),\n        )\n        self.assertFalse(s1.deep_eq(s2))\n\n        s1 = gtirb.SymAddrAddr(\n            offset=1,\n            scale=2,\n            symbol1=gtirb.Symbol(name=\"name1\", payload=None, uuid=id1),\n            symbol2=gtirb.Symbol(name=\"name2\", payload=None, uuid=id2),\n        )\n        s2 = gtirb.SymAddrAddr(\n            offset=1,\n            scale=2,\n            symbol1=gtirb.Symbol(name=\"name3\", payload=None, uuid=id1),\n            symbol2=gtirb.Symbol(name=\"name2\", payload=None, uuid=id2),\n        )\n        self.assertFalse(s1.deep_eq(s2))\n\n        s1 = gtirb.SymAddrAddr(\n            offset=1,\n            scale=2,\n            symbol1=gtirb.Symbol(name=\"name1\", payload=None, uuid=id1),\n            symbol2=gtirb.Symbol(name=\"name2\", payload=None, uuid=id2),\n        )\n        s2 = gtirb.SymAddrAddr(\n            offset=1,\n            scale=2,\n            symbol1=gtirb.Symbol(name=\"name1\", payload=None, uuid=id1),\n            symbol2=gtirb.Symbol(name=\"name3\", payload=None, uuid=id2),\n        )\n        self.assertFalse(s1.deep_eq(s2))\n\n        s1 = gtirb.SymAddrAddr(\n            offset=1,\n            scale=2,\n            symbol1=gtirb.Symbol(name=\"name1\", payload=None, uuid=id1),\n            symbol2=gtirb.Symbol(name=\"name2\", payload=None, uuid=id2),\n            attributes={gtirb.SymbolicExpression.Attribute.G1},\n        )\n        s2 = gtirb.SymAddrAddr(\n            offset=1,\n            scale=2,\n            symbol1=gtirb.Symbol(name=\"name1\", payload=None, uuid=id1),\n            symbol2=gtirb.Symbol(name=\"name2\", payload=None, uuid=id2),\n        )\n        self.assertFalse(s1.deep_eq(s2))\n\n    def test_byte_intervals(self):\n        id1 = uuid.uuid4()\n        id2 = uuid.uuid4()\n        id3 = uuid.uuid4()\n        id4 = uuid.uuid4()\n        id6 = uuid.uuid4()\n\n        b1 = gtirb.ByteInterval(\n            address=1,\n            contents=b\"abcd\",\n            size=4,\n            initialized_size=4,\n            blocks=(\n                gtirb.DataBlock(size=1, offset=3, uuid=id2),\n                gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id3),\n            ),\n            symbolic_expressions={\n                2: gtirb.SymAddrConst(\n                    3, gtirb.Symbol(name=\"name1\", payload=4, uuid=id4)\n                ),\n            },\n            uuid=id1,\n        )\n        b2 = gtirb.ByteInterval(\n            address=1,\n            contents=b\"abcd\",\n            size=4,\n            initialized_size=4,\n            blocks=(\n                gtirb.DataBlock(size=1, offset=3, uuid=id2),\n                gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id3),\n            ),\n            symbolic_expressions={\n                2: gtirb.SymAddrConst(\n                    3, gtirb.Symbol(name=\"name1\", payload=4, uuid=id4)\n                ),\n            },\n            uuid=id1,\n        )\n        self.assertTrue(b1.deep_eq(b2))\n\n        b2 = gtirb.ByteInterval(\n            address=None,\n            contents=b\"abcd\",\n            size=4,\n            initialized_size=4,\n            blocks=(\n                gtirb.DataBlock(size=1, offset=3, uuid=id2),\n                gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id3),\n            ),\n            symbolic_expressions={\n                2: gtirb.SymAddrConst(\n                    3, gtirb.Symbol(name=\"name1\", payload=4, uuid=id4)\n                ),\n            },\n            uuid=id1,\n        )\n        self.assertFalse(b1.deep_eq(b2))\n\n        b2 = gtirb.ByteInterval(\n            address=1,\n            contents=b\"1234\",\n            size=4,\n            initialized_size=4,\n            blocks=(\n                gtirb.DataBlock(size=1, offset=3, uuid=id2),\n                gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id3),\n            ),\n            symbolic_expressions={\n                2: gtirb.SymAddrConst(\n                    3, gtirb.Symbol(name=\"name1\", payload=4, uuid=id4)\n                ),\n            },\n            uuid=id1,\n        )\n        self.assertFalse(b1.deep_eq(b2))\n\n        b2 = gtirb.ByteInterval(\n            address=1,\n            contents=b\"abcd\",\n            size=8,\n            initialized_size=4,\n            blocks=(\n                gtirb.DataBlock(size=1, offset=3, uuid=id2),\n                gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id3),\n            ),\n            symbolic_expressions={\n                2: gtirb.SymAddrConst(\n                    3, gtirb.Symbol(name=\"name1\", payload=4, uuid=id4)\n                ),\n            },\n            uuid=id1,\n        )\n        self.assertFalse(b1.deep_eq(b2))\n\n        b2 = gtirb.ByteInterval(\n            address=1,\n            contents=b\"abcd\",\n            size=4,\n            initialized_size=0,\n            blocks=(\n                gtirb.DataBlock(size=1, offset=3, uuid=id2),\n                gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id3),\n            ),\n            symbolic_expressions={\n                2: gtirb.SymAddrConst(\n                    3, gtirb.Symbol(name=\"name1\", payload=4, uuid=id4)\n                ),\n            },\n            uuid=id1,\n        )\n        self.assertFalse(b1.deep_eq(b2))\n\n        b2 = gtirb.ByteInterval(\n            address=1,\n            contents=b\"abcd\",\n            size=4,\n            initialized_size=4,\n            blocks=(\n                gtirb.DataBlock(size=1, offset=3, uuid=id2),\n                gtirb.CodeBlock(size=1, decode_mode=5, offset=3, uuid=id3),\n            ),\n            symbolic_expressions={\n                2: gtirb.SymAddrConst(\n                    3, gtirb.Symbol(name=\"name1\", payload=4, uuid=id4)\n                ),\n            },\n            uuid=id1,\n        )\n        self.assertFalse(b1.deep_eq(b2))\n\n        b2 = gtirb.ByteInterval(\n            address=1,\n            contents=b\"abcd\",\n            size=4,\n            initialized_size=4,\n            blocks=(\n                gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id3),\n            ),\n            symbolic_expressions={\n                2: gtirb.SymAddrConst(\n                    3, gtirb.Symbol(name=\"name1\", payload=4, uuid=id4)\n                ),\n            },\n            uuid=id1,\n        )\n        self.assertFalse(b1.deep_eq(b2))\n\n        b2 = gtirb.ByteInterval(\n            address=1,\n            contents=b\"abcd\",\n            size=4,\n            initialized_size=4,\n            blocks=(\n                gtirb.DataBlock(size=1, offset=3, uuid=id2),\n                gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id3),\n            ),\n            symbolic_expressions={\n                2: gtirb.SymAddrConst(\n                    6, gtirb.Symbol(name=\"name1\", payload=4, uuid=id4)\n                ),\n            },\n            uuid=id1,\n        )\n        self.assertFalse(b1.deep_eq(b2))\n\n        b2 = gtirb.ByteInterval(\n            address=1,\n            contents=b\"abcd\",\n            size=4,\n            initialized_size=4,\n            blocks=(\n                gtirb.DataBlock(size=1, offset=3, uuid=id2),\n                gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id3),\n            ),\n            symbolic_expressions={\n                2: gtirb.SymAddrConst(\n                    3, gtirb.Symbol(name=\"name1\", payload=4, uuid=id4)\n                )\n            },\n            uuid=id1,\n        )\n        self.assertTrue(b1.deep_eq(b2))\n\n        b2 = gtirb.ByteInterval(\n            address=1,\n            contents=b\"abcd\",\n            size=4,\n            initialized_size=4,\n            blocks=(\n                gtirb.DataBlock(size=1, offset=3, uuid=id2),\n                gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id3),\n            ),\n            symbolic_expressions={\n                7: gtirb.SymAddrConst(\n                    3, gtirb.Symbol(name=\"name1\", payload=4, uuid=id4)\n                ),\n            },\n            uuid=id1,\n        )\n        self.assertFalse(b1.deep_eq(b2))\n\n        b2 = gtirb.ByteInterval(\n            address=1,\n            contents=b\"abcd\",\n            size=4,\n            initialized_size=4,\n            blocks=(\n                gtirb.DataBlock(size=1, offset=3, uuid=id2),\n                gtirb.CodeBlock(size=1, decode_mode=2, offset=3, uuid=id3),\n            ),\n            symbolic_expressions={\n                2: gtirb.SymAddrConst(\n                    3, gtirb.Symbol(name=\"name1\", payload=4, uuid=id4)\n                ),\n            },\n            uuid=id6,\n        )\n        self.assertFalse(b1.deep_eq(b2))\n\n    def test_sections(self):\n        id1 = uuid.uuid4()\n        id2 = uuid.uuid4()\n        id3 = uuid.uuid4()\n        id4 = uuid.uuid4()\n\n        s1 = gtirb.Section(\n            name=\"name\",\n            byte_intervals=(\n                gtirb.ByteInterval(contents=b\"abcd\", uuid=id2),\n                gtirb.ByteInterval(contents=b\"1234\", uuid=id3),\n            ),\n            flags=(gtirb.Section.Flag.Readable, gtirb.Section.Flag.Writable),\n            uuid=id1,\n        )\n        s2 = gtirb.Section(\n            name=\"name\",\n            byte_intervals=(\n                gtirb.ByteInterval(contents=b\"abcd\", uuid=id2),\n                gtirb.ByteInterval(contents=b\"1234\", uuid=id3),\n            ),\n            flags=(gtirb.Section.Flag.Readable, gtirb.Section.Flag.Writable),\n            uuid=id1,\n        )\n        self.assertTrue(s1.deep_eq(s2))\n\n        s2 = gtirb.Section(\n            name=\"name2\",\n            byte_intervals=(\n                gtirb.ByteInterval(contents=b\"abcd\", uuid=id2),\n                gtirb.ByteInterval(contents=b\"1234\", uuid=id3),\n            ),\n            flags=(gtirb.Section.Flag.Readable, gtirb.Section.Flag.Writable),\n            uuid=id1,\n        )\n        self.assertFalse(s1.deep_eq(s2))\n\n        s2 = gtirb.Section(\n            name=\"name\",\n            byte_intervals=(\n                gtirb.ByteInterval(contents=b\"abcd\", uuid=id2),\n                gtirb.ByteInterval(contents=b\"12345\", uuid=id3),\n            ),\n            flags=(gtirb.Section.Flag.Readable, gtirb.Section.Flag.Writable),\n            uuid=id1,\n        )\n        self.assertFalse(s1.deep_eq(s2))\n\n        s2 = gtirb.Section(\n            name=\"name\",\n            byte_intervals=(gtirb.ByteInterval(contents=b\"abcd\", uuid=id2),),\n            flags=(gtirb.Section.Flag.Readable, gtirb.Section.Flag.Writable),\n            uuid=id1,\n        )\n        self.assertFalse(s1.deep_eq(s2))\n\n        s2 = gtirb.Section(\n            name=\"name\",\n            byte_intervals=(\n                gtirb.ByteInterval(contents=b\"abcd\", uuid=id2),\n                gtirb.ByteInterval(contents=b\"1234\", uuid=id3),\n            ),\n            flags=(gtirb.Section.Flag.Writable,),\n            uuid=id1,\n        )\n        self.assertFalse(s1.deep_eq(s2))\n\n        s2 = gtirb.Section(\n            name=\"name\",\n            byte_intervals=(\n                gtirb.ByteInterval(contents=b\"abcd\", uuid=id2),\n                gtirb.ByteInterval(contents=b\"1234\", uuid=id3),\n            ),\n            flags=(\n                gtirb.Section.Flag.Readable,\n                gtirb.Section.Flag.Writable,\n                gtirb.Section.Flag.Loaded,\n            ),\n            uuid=id1,\n        )\n        self.assertFalse(s1.deep_eq(s2))\n\n        s2 = gtirb.Section(\n            name=\"name\",\n            byte_intervals=(\n                gtirb.ByteInterval(contents=b\"abcd\", uuid=id2),\n                gtirb.ByteInterval(contents=b\"1234\", uuid=id3),\n            ),\n            flags=(gtirb.Section.Flag.Readable, gtirb.Section.Flag.Writable),\n            uuid=id4,\n        )\n        self.assertFalse(s1.deep_eq(s2))\n\n    def test_cfg(self):\n        id1 = uuid.uuid4()\n        id2 = uuid.uuid4()\n\n        e1 = gtirb.CFG(\n            [\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=1, uuid=id1),\n                    gtirb.CodeBlock(size=2, uuid=id2),\n                    gtirb.Edge.Label(\n                        type=gtirb.Edge.Type.Branch,\n                        conditional=True,\n                        direct=False,\n                    ),\n                )\n            ]\n        )\n        self.assertFalse(\n            e1.deep_eq(\n                [\n                    gtirb.Edge(\n                        gtirb.CodeBlock(size=1, uuid=id1),\n                        gtirb.CodeBlock(size=2, uuid=id2),\n                        gtirb.Edge.Label(\n                            type=gtirb.Edge.Type.Branch,\n                            conditional=True,\n                            direct=False,\n                        ),\n                    )\n                ]\n            )\n        )\n\n        e2 = gtirb.CFG(\n            [\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=1, uuid=id1),\n                    gtirb.CodeBlock(size=2, uuid=id2),\n                    gtirb.Edge.Label(\n                        type=gtirb.Edge.Type.Branch,\n                        conditional=True,\n                        direct=False,\n                    ),\n                )\n            ]\n        )\n        self.assertTrue(e1.deep_eq(e2))\n\n        e2 = gtirb.CFG(\n            [\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=3, uuid=id1),\n                    gtirb.CodeBlock(size=2, uuid=id2),\n                    gtirb.Edge.Label(\n                        type=gtirb.Edge.Type.Branch,\n                        conditional=True,\n                        direct=False,\n                    ),\n                )\n            ]\n        )\n        self.assertFalse(e1.deep_eq(e2))\n\n        e2 = gtirb.CFG(\n            [\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=1, uuid=id1),\n                    gtirb.CodeBlock(size=3, uuid=id2),\n                    gtirb.Edge.Label(\n                        type=gtirb.Edge.Type.Branch,\n                        conditional=True,\n                        direct=False,\n                    ),\n                )\n            ]\n        )\n        self.assertFalse(e1.deep_eq(e2))\n\n        e2 = gtirb.CFG(\n            [\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=1, uuid=id1),\n                    gtirb.CodeBlock(size=2, uuid=id2),\n                    gtirb.Edge.Label(\n                        type=gtirb.Edge.Type.Fallthrough,\n                        conditional=True,\n                        direct=False,\n                    ),\n                )\n            ]\n        )\n        self.assertFalse(e1.deep_eq(e2))\n\n        e2 = gtirb.CFG(\n            [\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=1, uuid=id1),\n                    gtirb.CodeBlock(size=2, uuid=id2),\n                    gtirb.Edge.Label(\n                        type=gtirb.Edge.Type.Branch,\n                        conditional=False,\n                        direct=False,\n                    ),\n                )\n            ]\n        )\n        self.assertFalse(e1.deep_eq(e2))\n\n        e2 = gtirb.CFG(\n            [\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=1, uuid=id1),\n                    gtirb.CodeBlock(size=2, uuid=id2),\n                    gtirb.Edge.Label(\n                        type=gtirb.Edge.Type.Branch,\n                        conditional=True,\n                        direct=True,\n                    ),\n                )\n            ]\n        )\n        self.assertFalse(e1.deep_eq(e2))\n\n    def test_module(self):\n        id1 = uuid.uuid4()\n        id2 = uuid.uuid4()\n        id3 = uuid.uuid4()\n        id4 = uuid.uuid4()\n        id5 = uuid.uuid4()\n        id6 = uuid.uuid4()\n        id7 = uuid.uuid4()\n        id8 = uuid.uuid4()\n\n        m1 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.X64,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id3), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(\n                gtirb.Symbol(name=\"sym1\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect2\", uuid=id8),\n            ),\n            uuid=id1,\n        )\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.X64,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id3), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(\n                gtirb.Symbol(name=\"sym1\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect2\", uuid=id8),\n            ),\n            uuid=id1,\n        )\n        self.assertTrue(m1.deep_eq(m2))\n\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"other_value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.X64,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id3), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(\n                gtirb.Symbol(name=\"sym1\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect2\", uuid=id8),\n            ),\n            uuid=id1,\n        )\n        self.assertTrue(m1.deep_eq(m2))\n\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"other_binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.X64,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id3), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(\n                gtirb.Symbol(name=\"sym1\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect2\", uuid=id8),\n            ),\n            uuid=id1,\n        )\n        self.assertFalse(m1.deep_eq(m2))\n\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.PE,\n            isa=gtirb.Module.ISA.X64,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id3), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(\n                gtirb.Symbol(name=\"sym1\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect2\", uuid=id8),\n            ),\n            uuid=id1,\n        )\n        self.assertFalse(m1.deep_eq(m2))\n\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.ARM,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id3), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(\n                gtirb.Symbol(name=\"sym1\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect2\", uuid=id8),\n            ),\n            uuid=id1,\n        )\n        self.assertFalse(m1.deep_eq(m2))\n\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.X64,\n            name=\"other_name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id3), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(\n                gtirb.Symbol(name=\"sym1\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect2\", uuid=id8),\n            ),\n            uuid=id1,\n        )\n        self.assertFalse(m1.deep_eq(m2))\n\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.X64,\n            name=\"name\",\n            preferred_addr=5,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id3), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(\n                gtirb.Symbol(name=\"sym1\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect2\", uuid=id8),\n            ),\n            uuid=id1,\n        )\n        self.assertFalse(m1.deep_eq(m2))\n\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.X64,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=5,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id3), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(\n                gtirb.Symbol(name=\"sym1\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect2\", uuid=id8),\n            ),\n            uuid=id1,\n        )\n        self.assertFalse(m1.deep_eq(m2))\n\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.X64,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=2, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id3), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(\n                gtirb.Symbol(name=\"sym1\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect2\", uuid=id8),\n            ),\n            uuid=id1,\n        )\n        self.assertFalse(m1.deep_eq(m2))\n\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.X64,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id4), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(\n                gtirb.Symbol(name=\"sym1\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect2\", uuid=id8),\n            ),\n            uuid=id1,\n        )\n        self.assertFalse(m1.deep_eq(m2))\n\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.X64,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id4),),\n            symbols=(\n                gtirb.Symbol(name=\"sym1\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect2\", uuid=id8),\n            ),\n            uuid=id1,\n        )\n        self.assertFalse(m1.deep_eq(m2))\n\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.X64,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id3), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(\n                gtirb.Symbol(name=\"sym11\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect2\", uuid=id8),\n            ),\n            uuid=id1,\n        )\n        self.assertFalse(m1.deep_eq(m2))\n\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.X64,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id3), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(gtirb.Symbol(name=\"sym1\", uuid=id5),),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect2\", uuid=id8),\n            ),\n            uuid=id1,\n        )\n        self.assertFalse(m1.deep_eq(m2))\n\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.X64,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id3), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(\n                gtirb.Symbol(name=\"sym1\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect22\", uuid=id8),\n            ),\n            uuid=id1,\n        )\n        self.assertFalse(m1.deep_eq(m2))\n\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.X64,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id3), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(\n                gtirb.Symbol(name=\"sym1\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(gtirb.Section(name=\"sect2\", uuid=id8),),\n            uuid=id1,\n        )\n        self.assertFalse(m1.deep_eq(m2))\n\n        m2 = gtirb.Module(\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.ELF,\n            isa=gtirb.Module.ISA.X64,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            entry_point=gtirb.CodeBlock(size=1, uuid=id2),\n            proxies=(gtirb.ProxyBlock(uuid=id3), gtirb.ProxyBlock(uuid=id4)),\n            symbols=(\n                gtirb.Symbol(name=\"sym1\", uuid=id5),\n                gtirb.Symbol(name=\"sym2\", uuid=id6),\n            ),\n            sections=(\n                gtirb.Section(name=\"sect1\", uuid=id7),\n                gtirb.Section(name=\"sect2\", uuid=id8),\n            ),\n            uuid=id2,\n        )\n        self.assertFalse(m1.deep_eq(m2))\n\n    def test_ir(self):\n        id1 = uuid.uuid4()\n        id2 = uuid.uuid4()\n        id3 = uuid.uuid4()\n        id4 = uuid.uuid4()\n        id5 = uuid.uuid4()\n        id6 = uuid.uuid4()\n        id7 = uuid.uuid4()\n        id8 = uuid.uuid4()\n\n        ir1 = gtirb.IR(\n            modules=(\n                gtirb.Module(name=\"m1\", uuid=id2),\n                gtirb.Module(name=\"m2\", uuid=id3),\n            ),\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            cfg=(\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=1, uuid=id4),\n                    gtirb.CodeBlock(size=2, uuid=id5),\n                ),\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=3, uuid=id6),\n                    gtirb.CodeBlock(size=4, uuid=id7),\n                ),\n            ),\n            version=1,\n            uuid=id1,\n        )\n        ir2 = gtirb.IR(\n            modules=(\n                gtirb.Module(name=\"m1\", uuid=id2),\n                gtirb.Module(name=\"m2\", uuid=id3),\n            ),\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            cfg=(\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=1, uuid=id4),\n                    gtirb.CodeBlock(size=2, uuid=id5),\n                ),\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=3, uuid=id6),\n                    gtirb.CodeBlock(size=4, uuid=id7),\n                ),\n            ),\n            version=1,\n            uuid=id1,\n        )\n        self.assertTrue(ir1.deep_eq(ir2))\n\n        ir2 = gtirb.IR(\n            modules=(\n                gtirb.Module(name=\"m1\", uuid=id2),\n                gtirb.Module(name=\"m2\", uuid=id3),\n            ),\n            aux_data={\"key\": gtirb.AuxData(\"other_value\", \"string\")},\n            cfg=(\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=1, uuid=id4),\n                    gtirb.CodeBlock(size=2, uuid=id5),\n                ),\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=3, uuid=id6),\n                    gtirb.CodeBlock(size=4, uuid=id7),\n                ),\n            ),\n            version=1,\n            uuid=id1,\n        )\n        self.assertTrue(ir1.deep_eq(ir2))\n\n        ir2 = gtirb.IR(\n            modules=(\n                gtirb.Module(name=\"m11\", uuid=id2),\n                gtirb.Module(name=\"m2\", uuid=id3),\n            ),\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            cfg=(\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=1, uuid=id4),\n                    gtirb.CodeBlock(size=2, uuid=id5),\n                ),\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=3, uuid=id6),\n                    gtirb.CodeBlock(size=4, uuid=id7),\n                ),\n            ),\n            version=1,\n            uuid=id1,\n        )\n        self.assertFalse(ir1.deep_eq(ir2))\n\n        ir2 = gtirb.IR(\n            modules=(gtirb.Module(name=\"m1\", uuid=id2),),\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            cfg=(\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=1, uuid=id4),\n                    gtirb.CodeBlock(size=2, uuid=id5),\n                ),\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=3, uuid=id6),\n                    gtirb.CodeBlock(size=4, uuid=id7),\n                ),\n            ),\n            version=1,\n            uuid=id1,\n        )\n        self.assertFalse(ir1.deep_eq(ir2))\n\n        ir2 = gtirb.IR(\n            modules=(\n                gtirb.Module(name=\"m1\", uuid=id2),\n                gtirb.Module(name=\"m2\", uuid=id3),\n            ),\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            cfg=(\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=55, uuid=id4),\n                    gtirb.CodeBlock(size=2, uuid=id5),\n                ),\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=3, uuid=id6),\n                    gtirb.CodeBlock(size=4, uuid=id7),\n                ),\n            ),\n            version=1,\n            uuid=id1,\n        )\n        self.assertFalse(ir1.deep_eq(ir2))\n\n        ir2 = gtirb.IR(\n            modules=(\n                gtirb.Module(name=\"m1\", uuid=id2),\n                gtirb.Module(name=\"m2\", uuid=id3),\n            ),\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            cfg=(\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=3, uuid=id6),\n                    gtirb.CodeBlock(size=4, uuid=id7),\n                ),\n            ),\n            version=1,\n            uuid=id1,\n        )\n        self.assertFalse(ir1.deep_eq(ir2))\n\n        ir2 = gtirb.IR(\n            modules=(\n                gtirb.Module(name=\"m1\", uuid=id2),\n                gtirb.Module(name=\"m2\", uuid=id3),\n            ),\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            cfg=(\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=1, uuid=id4),\n                    gtirb.CodeBlock(size=2, uuid=id5),\n                ),\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=3, uuid=id6),\n                    gtirb.CodeBlock(size=4, uuid=id7),\n                ),\n            ),\n            version=5,\n            uuid=id1,\n        )\n        self.assertFalse(ir1.deep_eq(ir2))\n\n        ir2 = gtirb.IR(\n            modules=(\n                gtirb.Module(name=\"m1\", uuid=id2),\n                gtirb.Module(name=\"m2\", uuid=id3),\n            ),\n            aux_data={\"key\": gtirb.AuxData(\"value\", \"string\")},\n            cfg=(\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=1, uuid=id4),\n                    gtirb.CodeBlock(size=2, uuid=id5),\n                ),\n                gtirb.Edge(\n                    gtirb.CodeBlock(size=3, uuid=id6),\n                    gtirb.CodeBlock(size=4, uuid=id7),\n                ),\n            ),\n            version=1,\n            uuid=id8,\n        )\n        self.assertFalse(ir1.deep_eq(ir2))\n\n\nif __name__ == \"__main__\":\n    unittest.main()\n"
  },
  {
    "path": "python/tests/test_ir.py",
    "content": "import io\nimport os\nimport pathlib\nimport tempfile\nimport unittest\n\nfrom google.protobuf.message import DecodeError\n\nimport gtirb\n\nIR_FILE = tempfile.mktemp(suffix=\".gtirb\")\n\n\nclass IRTest(unittest.TestCase):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\n        ir = gtirb.IR()\n        m = gtirb.Module(\n            binary_path=\"binary_path\",\n            file_format=gtirb.Module.FileFormat.RAW,\n            isa=gtirb.Module.ISA.ValidButUnsupported,\n            name=\"name\",\n            preferred_addr=1,\n            rebase_delta=2,\n            ir=ir,\n        )\n        s = gtirb.Section(\n            name=\"name\",\n            flags=(\n                gtirb.Section.Flag.Executable,\n                gtirb.Section.Flag.Readable,\n                gtirb.Section.Flag.Loaded,\n                gtirb.Section.Flag.Initialized,\n            ),\n            module=m,\n        )\n        bi = gtirb.ByteInterval(\n            address=0, size=10, contents=b\"abcd\", section=s\n        )\n        cb = gtirb.CodeBlock(\n            size=4,\n            offset=0,\n            decode_mode=gtirb.CodeBlock.DecodeMode.Thumb,\n            byte_interval=bi,\n        )\n        _ = gtirb.DataBlock(size=6, offset=4, byte_interval=bi)\n        sym = gtirb.Symbol(name=\"name\", payload=cb, module=m)\n        sac = gtirb.SymAddrConst(\n            0, sym, {gtirb.SymbolicExpression.Attribute.G1}\n        )\n        bi.symbolic_expressions[2] = sac\n        p = gtirb.ProxyBlock(module=m)\n        ir.cfg.add(\n            gtirb.Edge(\n                cb,\n                p,\n                gtirb.Edge.Label(\n                    type=gtirb.Edge.Type.Branch, conditional=False, direct=True\n                ),\n            )\n        )\n        ir.cfg.add(gtirb.Edge(p, p))\n        m.aux_data[\"key\"] = gtirb.AuxData(gtirb.Offset(s, 777), \"Offset\")\n        ir.aux_data[\"key\"] = gtirb.AuxData(\"value\", \"string\")\n\n        self.ir = ir\n\n    def setUp(self):\n        self.ir.save_protobuf(IR_FILE)\n\n    def tearDown(self):\n        os.remove(IR_FILE)\n\n    def test_ir_protobuf_load(self):\n        new_ir = gtirb.IR.load_protobuf(IR_FILE)\n        self.assertTrue(self.ir.deep_eq(new_ir))\n        self.assertNotEqual(\n            self.ir.modules[0].aux_data[\"key\"].data,\n            new_ir.modules[0].aux_data[\"key\"].data,\n        )\n\n    def test_load_pathlib(self):\n        \"\"\"\n        Ensure `load_protobuf` and `save_protobuf` support path-like objects\n        \"\"\"\n        ir_path = pathlib.Path(IR_FILE)\n        new_ir = gtirb.IR.load_protobuf(ir_path)\n        self.assertTrue(self.ir.deep_eq(new_ir))\n        self.assertNotEqual(\n            self.ir.modules[0].aux_data[\"key\"].data,\n            new_ir.modules[0].aux_data[\"key\"].data,\n        )\n        new_ir.save_protobuf(ir_path)\n\n\nclass NotGTIRBTest(unittest.TestCase):\n    def test(self):\n        file_content = io.BytesIO(b\"JUNK\")\n        with self.assertRaises(Exception) as context:\n            gtirb.IR.load_protobuf_file(file_content)\n\n        self.assertEqual(\n            \"File missing GTIRB magic - not a GTIRB file?\",\n            str(context.exception),\n        )\n\n\nclass BadVersionTest(unittest.TestCase):\n    def test(self):\n        file_content = io.BytesIO(b\"GTIRB\\x00\\x00\\xFF\")\n        with self.assertRaises(Exception) as context:\n            gtirb.IR.load_protobuf_file(file_content)\n\n        self.assertTrue(\n            \"Attempt to decode IR of version\" in str(context.exception)\n        )\n\n\nclass BadProtobufTest(unittest.TestCase):\n    def test(self):\n        bytes = b\"GTIRB\\x00\\x00\"\n        bytes += gtirb.version.PROTOBUF_VERSION.to_bytes(1, byteorder=\"little\")\n        bytes += b\"JUNK\"\n        file_content = io.BytesIO(bytes)\n        with self.assertRaises(DecodeError) as context:\n            gtirb.IR.load_protobuf_file(file_content)\n\n\nclass IRMethodTests(unittest.TestCase):\n    def test_modules_named(self):\n        \"\"\"\n        Test the IR.modules_named method\n        \"\"\"\n        ir = gtirb.IR()\n\n        def add_module(name: str):\n            return gtirb.Module(\n                file_format=gtirb.Module.FileFormat.RAW,\n                isa=gtirb.Module.ISA.ValidButUnsupported,\n                name=name,\n                ir=ir,\n            )\n\n        m1 = add_module(\"m1\")\n        m2 = add_module(\"m2\")\n        m3_a = add_module(\"m3\")\n        m3_b = add_module(\"m3\")\n\n        self.assertEqual(next(ir.modules_named(\"m1\")), m1)\n        self.assertEqual(next(ir.modules_named(\"m2\")), m2)\n        m3s = list(ir.modules_named(\"m3\"))\n        self.assertEqual(len(m3s), 2)\n        self.assertIn(m3_a, m3s)\n        self.assertIn(m3_b, m3s)\n\n\nif __name__ == \"__main__\":\n    unittest.main()\n"
  },
  {
    "path": "python/tests/test_module.py",
    "content": "import unittest\n\nimport gtirb\n\n\nclass ModuleTests(unittest.TestCase):\n    def test_symbols_named(self):\n        m = gtirb.Module(name=\"test\")\n        s1 = gtirb.Symbol(name=\"hello\", module=m)\n        s2 = gtirb.Symbol(name=\"world\", module=m)\n\n        found = set(m.symbols_named(\"hello\"))\n        self.assertEqual(found, {s1})\n\n        found = set(m.symbols_named(\"world\"))\n        self.assertEqual(found, {s2})\n\n        # Change the name to verify we update the index\n        s1.name = \"world\"\n        found = set(m.symbols_named(\"hello\"))\n        self.assertEqual(found, set())\n\n        found = set(m.symbols_named(\"world\"))\n        self.assertEqual(found, {s1, s2})\n\n        # Discard the symbol to verify we update the index\n        m.symbols.discard(s1)\n        found = set(m.symbols_named(\"world\"))\n        self.assertEqual(found, {s2})\n\n        # Now add it back to verify we update the index\n        m.symbols.add(s1)\n        found = set(m.symbols_named(\"world\"))\n        self.assertEqual(found, {s1, s2})\n"
  },
  {
    "path": "python/tests/test_node_from_uuid.py",
    "content": "import unittest\nimport uuid\n\nimport gtirb\n\n\nclass NodeFromUUIDTest(unittest.TestCase):\n    def test_get_by_uuid_failed(self):\n        bad_id = uuid.uuid4()\n        node = gtirb.IR().get_by_uuid(bad_id)\n        self.assertIsNone(node)\n\n    def test_get_by_uuid(self):\n        ir1 = gtirb.IR()\n        ir2 = gtirb.IR()\n\n        # test nodes from one IR don't pollute the cache of other IRs\n        self.assertIsNone(ir1.get_by_uuid(ir2.uuid))\n        self.assertIsNone(ir2.get_by_uuid(ir1.uuid))\n        self.assertEqual(ir1.get_by_uuid(ir1.uuid), ir1)\n        self.assertEqual(ir2.get_by_uuid(ir2.uuid), ir2)\n\n        m = gtirb.Module(name=\"M\")\n        m.ir = ir1\n        s = gtirb.Section()\n        s.module = m\n        bi = gtirb.ByteInterval()\n        bi.section = s\n        b = gtirb.CodeBlock()\n        b.byte_interval = bi\n        sym = gtirb.Symbol(\"test\")\n        sym.module = m\n\n        # test all nodes are lookupable by any other node type\n        self.assertEqual(ir1.get_by_uuid(m.uuid), m)\n        self.assertEqual(ir1.get_by_uuid(s.uuid), s)\n        self.assertEqual(ir1.get_by_uuid(bi.uuid), bi)\n        self.assertEqual(ir1.get_by_uuid(b.uuid), b)\n        self.assertEqual(ir1.get_by_uuid(sym.uuid), sym)\n\n        self.assertEqual(m.ir.get_by_uuid(m.uuid), m)\n        self.assertEqual(m.ir.get_by_uuid(s.uuid), s)\n        self.assertEqual(m.ir.get_by_uuid(bi.uuid), bi)\n        self.assertEqual(m.ir.get_by_uuid(b.uuid), b)\n        self.assertEqual(m.ir.get_by_uuid(sym.uuid), sym)\n\n        self.assertEqual(s.ir.get_by_uuid(m.uuid), m)\n        self.assertEqual(s.ir.get_by_uuid(s.uuid), s)\n        self.assertEqual(s.ir.get_by_uuid(bi.uuid), bi)\n        self.assertEqual(s.ir.get_by_uuid(b.uuid), b)\n        self.assertEqual(s.ir.get_by_uuid(sym.uuid), sym)\n\n        self.assertEqual(bi.ir.get_by_uuid(m.uuid), m)\n        self.assertEqual(bi.ir.get_by_uuid(s.uuid), s)\n        self.assertEqual(bi.ir.get_by_uuid(bi.uuid), bi)\n        self.assertEqual(bi.ir.get_by_uuid(b.uuid), b)\n        self.assertEqual(bi.ir.get_by_uuid(sym.uuid), sym)\n\n        self.assertEqual(b.ir.get_by_uuid(m.uuid), m)\n        self.assertEqual(b.ir.get_by_uuid(s.uuid), s)\n        self.assertEqual(b.ir.get_by_uuid(bi.uuid), bi)\n        self.assertEqual(b.ir.get_by_uuid(b.uuid), b)\n        self.assertEqual(b.ir.get_by_uuid(sym.uuid), sym)\n\n        self.assertEqual(sym.ir.get_by_uuid(m.uuid), m)\n        self.assertEqual(sym.ir.get_by_uuid(s.uuid), s)\n        self.assertEqual(sym.ir.get_by_uuid(bi.uuid), bi)\n        self.assertEqual(sym.ir.get_by_uuid(b.uuid), b)\n        self.assertEqual(sym.ir.get_by_uuid(sym.uuid), sym)\n\n        # test removing a node removes all children as well\n        bi.section = None\n\n        self.assertEqual(ir1.get_by_uuid(m.uuid), m)\n        self.assertEqual(ir1.get_by_uuid(s.uuid), s)\n        self.assertIsNone(ir1.get_by_uuid(bi.uuid))\n        self.assertIsNone(ir1.get_by_uuid(b.uuid))\n        self.assertEqual(ir1.get_by_uuid(sym.uuid), sym)\n\n        bi.section = s\n\n        self.assertEqual(ir1.get_by_uuid(m.uuid), m)\n        self.assertEqual(ir1.get_by_uuid(s.uuid), s)\n        self.assertEqual(ir1.get_by_uuid(bi.uuid), bi)\n        self.assertEqual(ir1.get_by_uuid(b.uuid), b)\n        self.assertEqual(ir1.get_by_uuid(sym.uuid), sym)\n\n    def test_remove_from_cache(self):\n        ir = gtirb.IR()\n        m = gtirb.Module(name=\"M\")\n        m.ir = ir\n        s = gtirb.Section()\n\n        s.module = m\n        self.assertEqual(ir.get_by_uuid(s.uuid), s)\n\n        s.module = None\n        self.assertIsNone(ir.get_by_uuid(s.uuid))\n\n        m.sections.discard(s)\n        self.assertIsNone(ir.get_by_uuid(s.uuid))\n\n\nif __name__ == \"__main__\":\n    unittest.main()\n"
  },
  {
    "path": "python/tests/test_properties.py",
    "content": "import unittest\n\nimport gtirb\n\n\nclass TestProperties(unittest.TestCase):\n    def test_data_blocks(self):\n        b = gtirb.DataBlock()\n\n        self.assertEqual(b.address, None)\n        self.assertEqual(b.contents, b\"\")\n        self.assertEqual(set(b.references), set())\n\n        bi = gtirb.ByteInterval(address=1, contents=b\"abcd1234\")\n        b.offset = 2\n        b.size = 3\n        b.byte_interval = bi\n\n        self.assertEqual(b.address, 3)\n        self.assertEqual(b.contents, b\"cd1\")\n        self.assertEqual(set(b.references), set())\n\n        s = gtirb.Section()\n        bi.section = s\n        m = gtirb.Module(name=\"M\")\n        sym1 = gtirb.Symbol(\"test\", payload=b)\n        sym2 = gtirb.Symbol(\"test\", payload=123)\n        sym3 = gtirb.Symbol(\"test\", payload=b)\n        m.symbols |= {sym1, sym2, sym3}\n        s.module = m\n\n        self.assertEqual(b.address, 3)\n        self.assertEqual(b.contents, b\"cd1\")\n        self.assertEqual(set(b.references), {sym1, sym3})\n\n    def test_code_blocks(self):\n        b = gtirb.CodeBlock()\n\n        self.assertEqual(b.address, None)\n        self.assertEqual(b.contents, b\"\")\n        self.assertEqual(set(b.references), set())\n        self.assertEqual(set(b.incoming_edges), set())\n        self.assertEqual(set(b.outgoing_edges), set())\n\n        bi = gtirb.ByteInterval(address=1, contents=b\"abcd1234\")\n        b.offset = 2\n        b.size = 3\n        b.byte_interval = bi\n\n        self.assertEqual(b.address, 3)\n        self.assertEqual(b.contents, b\"cd1\")\n        self.assertEqual(set(b.references), set())\n        self.assertEqual(set(b.incoming_edges), set())\n        self.assertEqual(set(b.outgoing_edges), set())\n\n        s = gtirb.Section()\n        bi.section = s\n        m = gtirb.Module(name=\"M\")\n        sym1 = gtirb.Symbol(\"test\", payload=b)\n        sym2 = gtirb.Symbol(\"test\", payload=123)\n        sym3 = gtirb.Symbol(\"test\", payload=b)\n        m.symbols |= {sym1, sym2, sym3}\n        s.module = m\n\n        self.assertEqual(b.address, 3)\n        self.assertEqual(b.contents, b\"cd1\")\n        self.assertEqual(set(b.references), {sym1, sym3})\n        self.assertEqual(set(b.incoming_edges), set())\n        self.assertEqual(set(b.outgoing_edges), set())\n\n        i = gtirb.IR()\n        m.ir = i\n        p1 = gtirb.ProxyBlock()\n        p2 = gtirb.ProxyBlock()\n        p3 = gtirb.ProxyBlock()\n        p4 = gtirb.ProxyBlock()\n        i.cfg.add(gtirb.Edge(b, p1))\n        i.cfg.add(gtirb.Edge(p2, b))\n        i.cfg.add(gtirb.Edge(p3, p4))\n        i.cfg.add(gtirb.Edge(b, b))\n\n        self.assertEqual(b.address, 3)\n        self.assertEqual(b.contents, b\"cd1\")\n        self.assertEqual(set(b.references), {sym1, sym3})\n        self.assertEqual(\n            set((s, t) for s, t, l in b.incoming_edges), {(p2, b), (b, b)}\n        )\n        self.assertEqual(\n            set((s, t) for s, t, l in b.outgoing_edges), {(b, p1), (b, b)}\n        )\n\n    def test_proxy_blocks(self):\n        b = gtirb.ProxyBlock()\n\n        self.assertEqual(set(b.references), set())\n        self.assertEqual(set(b.incoming_edges), set())\n        self.assertEqual(set(b.outgoing_edges), set())\n\n        m = gtirb.Module(name=\"M\")\n        sym1 = gtirb.Symbol(\"test\", payload=b)\n        sym2 = gtirb.Symbol(\"test\", payload=123)\n        sym3 = gtirb.Symbol(\"test\", payload=b)\n        m.symbols |= {sym1, sym2, sym3}\n        b.module = m\n\n        self.assertEqual(set(b.references), {sym1, sym3})\n        self.assertEqual(set(b.incoming_edges), set())\n        self.assertEqual(set(b.outgoing_edges), set())\n\n        i = gtirb.IR()\n        m.ir = i\n        p1 = gtirb.ProxyBlock()\n        p2 = gtirb.ProxyBlock()\n        p3 = gtirb.ProxyBlock()\n        p4 = gtirb.ProxyBlock()\n        i.cfg.add(gtirb.Edge(b, p1))\n        i.cfg.add(gtirb.Edge(p2, b))\n        i.cfg.add(gtirb.Edge(p3, p4))\n        i.cfg.add(gtirb.Edge(b, b))\n\n        self.assertEqual(set(b.references), {sym1, sym3})\n        self.assertEqual(\n            set((s, t) for s, t, l in b.incoming_edges), {(p2, b), (b, b)}\n        )\n        self.assertEqual(\n            set((s, t) for s, t, l in b.outgoing_edges), {(b, p1), (b, b)}\n        )\n\n    def test_sections(self):\n        s = gtirb.Section()\n        self.assertEqual(s.address, None)\n        self.assertEqual(s.size, None)\n\n        s.byte_intervals.clear()\n        s.byte_intervals |= {gtirb.ByteInterval()}\n        self.assertEqual(s.address, None)\n        self.assertEqual(s.size, None)\n\n        s.byte_intervals.clear()\n        s.byte_intervals |= {gtirb.ByteInterval(size=3)}\n        self.assertEqual(s.address, None)\n        self.assertEqual(s.size, None)\n\n        s.byte_intervals.clear()\n        s.byte_intervals |= {gtirb.ByteInterval(address=2, size=4)}\n        self.assertEqual(s.address, 2)\n        self.assertEqual(s.size, 4)\n\n        s.byte_intervals.clear()\n        s.byte_intervals |= {\n            gtirb.ByteInterval(address=2, size=4),\n            gtirb.ByteInterval(size=3),\n        }\n        self.assertEqual(s.address, None)\n        self.assertEqual(s.size, None)\n\n        s.byte_intervals.clear()\n        s.byte_intervals |= {\n            gtirb.ByteInterval(address=2, size=4),\n            gtirb.ByteInterval(address=100, size=3),\n        }\n        self.assertEqual(s.address, 2)\n        self.assertEqual(s.size, 101)\n\n    def test_modules(self):\n        s1 = gtirb.Section(\n            name=\"s1\", byte_intervals=[gtirb.ByteInterval(address=4, size=4)]\n        )\n        s2 = gtirb.Section(\n            name=\"s2\", byte_intervals=[gtirb.ByteInterval(address=8, size=8)]\n        )\n        s3 = gtirb.Section(\n            name=\"s3\", byte_intervals=[gtirb.ByteInterval(address=100, size=1)]\n        )\n        s4 = gtirb.Section(\n            name=\"s4\", byte_intervals=[gtirb.ByteInterval(size=1000)]\n        )\n        m = gtirb.Module(name=\"M\", sections=[s1, s2, s3, s4])\n\n        self.assertEqual(set(m.sections_on(3)), set())\n        self.assertEqual(set(m.sections_on(4)), {s1})\n        self.assertEqual(set(m.sections_on(7)), {s1})\n        self.assertEqual(set(m.sections_on(8)), {s2})\n        self.assertEqual(set(m.sections_on(15)), {s2})\n        self.assertEqual(set(m.sections_on(16)), set())\n        self.assertEqual(set(m.sections_on(99)), set())\n        self.assertEqual(set(m.sections_on(100)), {s3})\n        self.assertEqual(set(m.sections_on(101)), set())\n\n        self.assertEqual(set(m.sections_on(range(0, 100))), {s1, s2})\n        self.assertEqual(set(m.sections_on(range(0, 101))), {s1, s2, s3})\n        self.assertEqual(set(m.sections_on(range(0, 102))), {s1, s2, s3})\n        self.assertEqual(set(m.sections_on(range(7, 7 + 4))), {s1, s2})\n        self.assertEqual(set(m.sections_on(range(8, 8 + 4))), {s2})\n        self.assertEqual(set(m.sections_on(range(17, 17 + 80))), set())\n\n        self.assertEqual(set(m.sections_at(3)), set())\n        self.assertEqual(set(m.sections_at(4)), {s1})\n        self.assertEqual(set(m.sections_at(5)), set())\n        self.assertEqual(set(m.sections_at(7)), set())\n        self.assertEqual(set(m.sections_at(8)), {s2})\n        self.assertEqual(set(m.sections_at(9)), set())\n        self.assertEqual(set(m.sections_at(99)), set())\n        self.assertEqual(set(m.sections_at(100)), {s3})\n        self.assertEqual(set(m.sections_at(101)), set())\n\n        self.assertEqual(set(m.sections_at(range(0, 100))), {s1, s2})\n        self.assertEqual(set(m.sections_at(range(0, 101))), {s1, s2, s3})\n        self.assertEqual(set(m.sections_at(range(5, 10))), {s2})\n        self.assertEqual(set(m.sections_at(range(95, 105))), {s3})\n\n    def test_byte_intervals(self):\n        s = gtirb.Symbol(name=\"test\")\n        se1 = gtirb.SymAddrConst(0, s)\n        se3 = gtirb.SymAddrAddr(0, 1, s, s)\n        bi = gtirb.ByteInterval(\n            address=10, size=5, symbolic_expressions={0: se1, 4: se3}\n        )\n\n        self.assertEqual(set(bi.symbolic_expressions_at(9)), set())\n        self.assertEqual(set(bi.symbolic_expressions_at(10)), {(bi, 0, se1)})\n        self.assertEqual(set(bi.symbolic_expressions_at(11)), set())\n        self.assertEqual(set(bi.symbolic_expressions_at(13)), set())\n        self.assertEqual(set(bi.symbolic_expressions_at(14)), {(bi, 4, se3)})\n        self.assertEqual(set(bi.symbolic_expressions_at(15)), set())\n\n        self.assertEqual(set(bi.symbolic_expressions_at(range(0, 9))), set())\n        self.assertEqual(set(bi.symbolic_expressions_at(range(11, 14))), set())\n        self.assertEqual(set(bi.symbolic_expressions_at(range(20, 90))), set())\n        self.assertEqual(\n            set(bi.symbolic_expressions_at(range(0, 90))),\n            {(bi, 0, se1), (bi, 4, se3)},\n        )\n        self.assertEqual(\n            set(bi.symbolic_expressions_at(range(10, 15))),\n            {(bi, 0, se1), (bi, 4, se3)},\n        )\n        self.assertEqual(\n            set(bi.symbolic_expressions_at(range(11, 18))), {(bi, 4, se3)}\n        )\n\n    def test_sym_exprs(self):\n        node = gtirb.SymAddrConst(\n            offset=123,\n            symbol=gtirb.Symbol(name=\"symbol\", payload=gtirb.ProxyBlock()),\n        )\n        self.assertEqual({x.name for x in node.symbols}, {\"symbol\"})\n\n        node = gtirb.SymAddrAddr(\n            offset=123,\n            scale=2,\n            symbol1=gtirb.Symbol(name=\"symbol1\", payload=gtirb.ProxyBlock()),\n            symbol2=gtirb.Symbol(name=\"symbol2\", payload=gtirb.ProxyBlock()),\n        )\n        self.assertEqual(\n            {x.name for x in node.symbols}, {\"symbol1\", \"symbol2\"}\n        )\n"
  },
  {
    "path": "python/tests/test_repr.py",
    "content": "\"\"\"isort:skip_file\"\"\"\n\nimport unittest\nimport gtirb\nimport uuid\n\n# imports needed because repr's use of unqualified names\nfrom uuid import UUID  # noqa: F401,F403,F401\nfrom gtirb import *  # noqa: F401,F403,F401\n\n\nclass ReprTest(unittest.TestCase):\n    def test_auxdata(self):\n        node = gtirb.AuxData(\n            type_name=\"mapping<string,set<UUID>>\",\n            data={\n                \"a\": set([uuid.uuid4(), uuid.uuid4()]),\n                \"b\": set([uuid.uuid4()]),\n            },\n        )\n        string = repr(node)\n        new_node = eval(string)\n        # auxdata has no deep_eq\n        # (because how can we ensure \"data\" has a deep_eq?)\n        self.assertEqual(node.type_name, new_node.type_name)\n        self.assertEqual(node.data, new_node.data)\n\n    def test_block(self):\n        node = gtirb.CodeBlock(\n            offset=123, size=456, decode_mode=gtirb.CodeBlock.DecodeMode.Thumb\n        )\n        string = repr(node)\n        new_node = eval(string)\n        self.assertTrue(node.deep_eq(new_node))\n\n    def test_proxy_block(self):\n        node = gtirb.ProxyBlock()\n        string = repr(node)\n        new_node = eval(string)\n        self.assertTrue(node.deep_eq(new_node))\n\n    def test_data_object(self):\n        node = gtirb.DataBlock(offset=123, size=456)\n        string = repr(node)\n        new_node = eval(string)\n        self.assertTrue(node.deep_eq(new_node))\n\n    def test_ir(self):\n        # TODO: expand this\n        node = gtirb.IR()\n        string = repr(node)\n        new_node = eval(string)\n        self.assertTrue(node.deep_eq(new_node))\n\n    def test_cfg(self):\n        node = gtirb.CFG()\n        node.add(\n            gtirb.Edge(\n                gtirb.CodeBlock(offset=1, size=2),\n                gtirb.CodeBlock(offset=3, size=4),\n                gtirb.Edge.Label(\n                    type=gtirb.Edge.Type.Fallthrough,\n                    conditional=True,\n                    direct=False,\n                ),\n            )\n        )\n        node.add(\n            gtirb.Edge(\n                gtirb.CodeBlock(offset=5, size=6),\n                gtirb.CodeBlock(offset=7, size=8),\n                gtirb.Edge.Label(\n                    type=gtirb.Edge.Type.Branch,\n                    conditional=True,\n                    direct=False,\n                ),\n            )\n        )\n        string = repr(node)\n        new_node = eval(string)\n        self.assertTrue(node.deep_eq(new_node))\n\n    def test_module(self):\n        # TODO: expand this\n        node = gtirb.Module(name=\"M\")\n        string = repr(node)\n        new_node = eval(string)\n        self.assertTrue(node.deep_eq(new_node))\n\n    def test_offset(self):\n        node = gtirb.Offset(element_id=uuid.uuid4(), displacement=123)\n        string = repr(node)\n        new_node = eval(string)\n        self.assertEqual(node.element_id, new_node.element_id)\n        self.assertEqual(node.displacement, new_node.displacement)\n\n    def test_section(self):\n        node = gtirb.Section(\n            name=\".text\",\n            flags=(gtirb.Section.Flag.Readable, gtirb.Section.Flag.Writable),\n        )\n        string = repr(node)\n        new_node = eval(string)\n        self.assertTrue(node.deep_eq(new_node))\n\n    def test_symbol(self):\n        node = gtirb.Symbol(name=\"symbol1\", payload=gtirb.ProxyBlock())\n        string = repr(node)\n        new_node = eval(string)\n        self.assertTrue(node.deep_eq(new_node))\n\n        node = gtirb.Symbol(name=\"symbol2\", payload=0x123)\n        string = repr(node)\n        new_node = eval(string)\n        self.assertTrue(node.deep_eq(new_node))\n\n        node = gtirb.Symbol(name=\"symbol3\", payload=None)\n        string = repr(node)\n        new_node = eval(string)\n        self.assertTrue(node.deep_eq(new_node))\n\n    def test_sym_expr(self):\n        node = gtirb.SymAddrConst(\n            offset=123,\n            symbol=gtirb.Symbol(name=\"symbol\", payload=gtirb.ProxyBlock()),\n            attributes=set(),\n        )\n        string = repr(node)\n        new_node = eval(string)\n        self.assertTrue(node.deep_eq(new_node))\n\n        node = gtirb.SymAddrAddr(\n            offset=123,\n            scale=2,\n            symbol1=gtirb.Symbol(name=\"symbol1\", payload=gtirb.ProxyBlock()),\n            symbol2=gtirb.Symbol(name=\"symbol2\", payload=gtirb.ProxyBlock()),\n            attributes={\n                gtirb.SymbolicExpression.Attribute.ABS,\n                gtirb.SymbolicExpression.Attribute.G0,\n            },\n        )\n        string = repr(node)\n        new_node = eval(string)\n        self.assertTrue(node.deep_eq(new_node))\n\n    def test_byte_interval(self):\n        node = gtirb.ByteInterval(\n            address=0x123,\n            initialized_size=456,\n            size=789,\n            contents=b\"abc\",\n            blocks=(gtirb.DataBlock(size=0),),\n            symbolic_expressions={\n                1: gtirb.SymAddrConst(offset=1, symbol=gtirb.Symbol(\"test\"))\n            },\n        )\n        string = repr(node)\n        new_node = eval(string)\n        self.assertTrue(node.deep_eq(new_node))\n\n\nif __name__ == \"__main__\":\n    unittest.main()\n"
  },
  {
    "path": "python/tests/test_section.py",
    "content": "import unittest\n\nimport gtirb\n\n\nclass SectionTests(unittest.TestCase):\n    def test_byte_blocks(self):\n        s = gtirb.Section()\n\n        bi1 = gtirb.ByteInterval(size=4, section=s)\n        bi1_code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi1)\n        bi1_data_block = gtirb.DataBlock(offset=1, size=1, byte_interval=bi1)\n\n        bi2 = gtirb.ByteInterval(size=4, section=s)\n        bi2_code_block = gtirb.CodeBlock(offset=0, size=1, byte_interval=bi2)\n        bi2_data_block = gtirb.DataBlock(offset=1, size=1, byte_interval=bi2)\n\n        self.assertEqual(\n            set(s.byte_blocks),\n            {bi1_code_block, bi1_data_block, bi2_code_block, bi2_data_block},\n        )\n        self.assertEqual(set(s.code_blocks), {bi1_code_block, bi2_code_block})\n        self.assertEqual(set(s.data_blocks), {bi1_data_block, bi2_data_block})\n"
  },
  {
    "path": "python/tests/test_serialization.py",
    "content": "import io\nimport unittest\n\nimport gtirb.serialization\nfrom gtirb.serialization import Variant\n\n\nclass TestSerialization(unittest.TestCase):\n    def test_parse_type(self):\n        def test_positive(type_name, oracle):\n            self.assertEqual(\n                gtirb.serialization.Serialization._parse_type(type_name),\n                oracle,\n            )\n\n        positive_tests = [\n            (\"mapping\", (\"mapping\", ())),\n            (\"mapping<FOO,BAR>\", (\"mapping\", ((\"FOO\", ()), (\"BAR\", ())))),\n            (\n                \"mapping<FOO,set<BAR>>\",\n                (\"mapping\", ((\"FOO\", ()), (\"set\", ((\"BAR\", ()),)))),\n            ),\n            (\n                \"mapping<FOO,mapping<BAR,BAZ>>\",\n                (\n                    \"mapping\",\n                    ((\"FOO\", ()), (\"mapping\", ((\"BAR\", ()), (\"BAZ\", ())))),\n                ),\n            ),\n            (\n                \"mapping<mapping<BAR,BAZ>,FOO>\",\n                (\n                    \"mapping\",\n                    ((\"mapping\", ((\"BAR\", ()), (\"BAZ\", ()))), (\"FOO\", ())),\n                ),\n            ),\n        ]\n        for type_name, oracle in positive_tests:\n            test_positive(type_name, oracle)\n\n        def test_negative(type_name):\n            with self.assertRaises(\n                gtirb.serialization.TypeNameError, msg=type_name\n            ):\n                gtirb.serialization.Serialization._parse_type(type_name)\n\n        negative_tests = [\n            \"mapping<<>\",\n            \"mapping<>>\",\n            \"mapping<><>\",\n            \"mapping<<><>>\",\n            \"mapping<<foo><bar>>\",\n            \"mapping<,>\",\n            \"mapping<FOO,>\",\n            \"mapping<,BAR>\",\n        ]\n        for type_name in negative_tests:\n            test_negative(type_name)\n\n    def test_unknown_codec(self):\n        serializer = gtirb.serialization.Serialization()\n        blob = serializer.decode(b\"abcd\", \"foobar\")\n        self.assertIsInstance(blob, gtirb.serialization.UnknownData)\n        self.assertEqual(blob, b\"abcd\")\n        ostream = io.BytesIO()\n        serializer.encode(ostream, blob, \"foobar\")\n        self.assertEqual(ostream.getvalue(), b\"abcd\")\n\n    def test_nested_unknown_codec(self):\n        serializer = gtirb.serialization.Serialization()\n        ostream = io.BytesIO()\n        serializer.encode(\n            ostream,\n            {\"a\": [\"b\", \"c\"], \"d\": [\"e\"]},\n            \"mapping<string,sequence<string>>\",\n        )\n        raw_bytes = ostream.getvalue()\n\n        blob = serializer.decode(raw_bytes, \"mapping<string,sequence<foobar>>\")\n        self.assertIsInstance(blob, gtirb.serialization.UnknownData)\n        ostream = io.BytesIO()\n        serializer.encode(ostream, blob, \"mapping<string,sequence<foobar>>\")\n        self.assertEqual(ostream.getvalue(), raw_bytes)\n\n        blob = serializer.decode(raw_bytes, \"mapping<foobar,sequence<string>>\")\n        self.assertIsInstance(blob, gtirb.serialization.UnknownData)\n        ostream = io.BytesIO()\n        serializer.encode(ostream, blob, \"mapping<foobar,sequence<string>>\")\n        self.assertEqual(ostream.getvalue(), raw_bytes)\n\n    def test_uuid_codec(self):\n        ir = gtirb.IR(\n            modules=[\n                gtirb.Module(\n                    name=\"M\",\n                    sections=[\n                        gtirb.Section(\n                            byte_intervals=[\n                                gtirb.ByteInterval(blocks=[gtirb.CodeBlock()])\n                            ]\n                        )\n                    ],\n                )\n            ]\n        )\n        b = next(iter(ir.code_blocks))\n\n        # test finding block in same IR\n        bstream = io.BytesIO()\n        gtirb.AuxData.serializer.encode(bstream, b.uuid, \"UUID\")\n        result = gtirb.AuxData.serializer.decode(\n            bstream.getvalue(), \"UUID\", ir.get_by_uuid\n        )\n        self.assertEqual(result, b)\n\n        # test not finding block with same UUID in other IR\n        ir2 = gtirb.IR(\n            modules=[\n                gtirb.Module(\n                    name=\"M\",\n                    sections=[\n                        gtirb.Section(\n                            byte_intervals=[\n                                gtirb.ByteInterval(\n                                    blocks=[gtirb.CodeBlock(uuid=b.uuid)]\n                                )\n                            ]\n                        )\n                    ],\n                )\n            ]\n        )\n        b2 = next(iter(ir2.code_blocks))\n\n        bstream = io.BytesIO()\n        gtirb.AuxData.serializer.encode(bstream, b.uuid, \"UUID\")\n        result = gtirb.AuxData.serializer.decode(\n            bstream.getvalue(), \"UUID\", ir.get_by_uuid\n        )\n        self.assertEqual(result, b)\n\n        bstream = io.BytesIO()\n        gtirb.AuxData.serializer.encode(bstream, b.uuid, \"UUID\")\n        result = gtirb.AuxData.serializer.decode(\n            bstream.getvalue(), \"UUID\", ir2.get_by_uuid\n        )\n        self.assertEqual(result, b2)\n\n        # test not finding the UUID of a free block\n        b3 = gtirb.CodeBlock()\n\n        bstream = io.BytesIO()\n        gtirb.AuxData.serializer.encode(bstream, b3.uuid, \"UUID\")\n        result = gtirb.AuxData.serializer.decode(\n            bstream.getvalue(), \"UUID\", ir.get_by_uuid\n        )\n        self.assertEqual(result, b3.uuid)\n\n    def test_variant_codec(self):\n        serializer = gtirb.serialization.Serialization()\n        ostream = io.BytesIO()\n        variant = Variant(2, {5: [\"a\", \"b\"], 15: [\"cc\", \"ddd\"]})\n        serializer.encode(\n            ostream,\n            variant,\n            \"variant<string,int64_t,mapping<int64_t,sequence<string>>>\",\n        )\n        raw_bytes = ostream.getvalue()\n        var_val = serializer.decode(\n            raw_bytes,\n            \"variant<string,int64_t,mapping<int64_t,sequence<string>>>\",\n        )\n        self.assertEqual(var_val, variant)\n\n        ostream = io.BytesIO()\n        variant = Variant(1, 10)\n        serializer.encode(\n            ostream,\n            variant,\n            \"variant<string,int64_t,string>\",\n        )\n        raw_bytes = ostream.getvalue()\n        var_val = serializer.decode(\n            raw_bytes, \"variant<string,int64_t,string>\"\n        )\n        self.assertEqual(var_val, variant)\n\n        ostream = io.BytesIO()\n        variant = Variant(0, \"zzzz\")\n        serializer.encode(\n            ostream,\n            variant,\n            \"variant<string,int64_t,string>\",\n        )\n        raw_bytes = ostream.getvalue()\n        var_val = serializer.decode(\n            raw_bytes, \"variant<string,int64_t,string>\"\n        )\n        self.assertEqual(var_val, variant)\n\n        ostream = io.BytesIO()\n        mapping = {\"aa\": Variant(0, 5), \"bbb\": Variant(1, \"ccccc\")}\n        serializer.encode(\n            ostream,\n            mapping,\n            \"mapping<string,variant<int64_t,string>>\",\n        )\n        raw_bytes = ostream.getvalue()\n        mapping_val = serializer.decode(\n            raw_bytes, \"mapping<string,variant<int64_t,string>>\"\n        )\n        self.assertEqual(mapping_val, mapping)\n\n    def _check_val(self, typename, val):\n        bstream = io.BytesIO()\n        gtirb.AuxData.serializer.encode(bstream, val, typename)\n        result = gtirb.AuxData.serializer.decode(bstream.getvalue(), typename)\n        self.assertEqual(result, val)\n\n    def test_int_serializers(self):\n        # Signed types\n        def _test_range(typename, minval, maxval):\n            self._check_val(typename, 127)\n            self._check_val(typename, minval)\n            self._check_val(typename, maxval)\n\n        _test_range(\"int8_t\", -(2**7), (2**7) - 1)\n        _test_range(\"int16_t\", -(2**15), (2**15) - 1)\n        _test_range(\"int32_t\", -(2**31), (2**31) - 1)\n        _test_range(\"int64_t\", -(2**63), (2**63) - 1)\n        _test_range(\"uint8_t\", 0, (2**8) - 1)\n        _test_range(\"uint16_t\", 0, (2**16) - 1)\n        _test_range(\"uint32_t\", 0, (2**32) - 1)\n        _test_range(\"uint64_t\", 0, (2**64) - 1)\n\n    def test_float_serializers(self):\n        self._check_val(\"float\", 0.4000000059604645)\n        self._check_val(\"double\", 0.4)\n\n\nif __name__ == \"__main__\":\n    unittest.main()\n"
  },
  {
    "path": "python/tests/test_symbolic_expression.py",
    "content": "import io\nimport unittest\n\nfrom helpers import create_interval_etc\n\nimport gtirb\n\n\nclass SymbolicExpressionAttributes(unittest.TestCase):\n    def test_unknown_attributes(self):\n        ir, m, s, bi = create_interval_etc(address=0x1000, size=5)\n        sym = gtirb.Symbol(name=\"foo\")\n        m.symbols.add(sym)\n        expr = gtirb.SymAddrConst(\n            0, sym, {gtirb.SymbolicExpression.Attribute.GOT, 0xBEEF}\n        )\n        bi.symbolic_expressions[0] = expr\n\n        out = io.BytesIO()\n        ir.save_protobuf_file(out)\n        out.seek(0)\n\n        ir = gtirb.IR.load_protobuf_file(out)\n        bi = next(ir.byte_intervals)\n        expr = bi.symbolic_expressions[0]\n\n        self.assertTrue(\n            gtirb.SymbolicExpression.Attribute.GOT in expr.attributes\n        )\n        self.assertTrue(0xBEEF in expr.attributes)\n"
  },
  {
    "path": "python/tests/test_symbolic_expressions_at.py",
    "content": "import unittest\n\nfrom helpers import SearchScope, create_interval_etc, parameterize_one\n\nimport gtirb\n\n\nclass SymbolicExpressionsAtTests(unittest.TestCase):\n    @parameterize_one(\"scope\", list(SearchScope))\n    def test_symbolic_expressions_at(self, scope):\n        ir, m, s, bi = create_interval_etc(address=0x1000, size=5)\n        search_in = scope.select(ir, m, s, bi)\n\n        sym = gtirb.Symbol(name=\"hello\")\n        expr = gtirb.SymAddrConst(0, sym)\n        bi.symbolic_expressions[1] = expr\n        bi.symbolic_expressions[2] = expr\n        bi.symbolic_expressions[3] = expr\n        bi.symbolic_expressions[4] = expr\n\n        found = set(search_in.symbolic_expressions_at(0x1001))\n        self.assertEqual(found, {(bi, 1, expr)})\n\n        found = set(search_in.symbolic_expressions_at(range(0x1000, 0x1004)))\n        self.assertEqual(found, {(bi, 1, expr), (bi, 2, expr), (bi, 3, expr)})\n\n        found = set(\n            search_in.symbolic_expressions_at(range(0x1000, 0x1004, 2))\n        )\n        self.assertEqual(found, {(bi, 2, expr)})\n\n        # Now just verify that the index updates correctly when deleting\n        del bi.symbolic_expressions[1]\n\n        found = set(search_in.symbolic_expressions_at(0x1001))\n        self.assertEqual(found, set())\n"
  },
  {
    "path": "python/tests/test_wrapper.py",
    "content": "import unittest\n\nimport gtirb.util\n\n\nclass RecordingList(gtirb.util.ListWrapper):\n    def __init__(self, *args):\n        self.record = []\n        super().__init__(*args)\n\n    def _add(self, value):\n        self.record.append((\"add\", value))\n\n    def _remove(self, value):\n        self.record.append((\"remove\", value))\n\n\nclass ListWrapperTests(unittest.TestCase):\n    def test_empty_init(self):\n        lst = RecordingList()\n        self.assertFalse(lst.record)\n\n    def test_values_init(self):\n        lst = RecordingList([\"A\", \"B\", \"C\"])\n        self.assertEqual(\n            lst.record, [(\"add\", \"A\"), (\"add\", \"B\"), (\"add\", \"C\")]\n        )\n\n    def test_getitem_int(self):\n        lst = RecordingList([\"A\", \"B\", \"C\"])\n        self.assertEqual(lst[0], \"A\")\n        self.assertEqual(lst[1], \"B\")\n        self.assertEqual(lst[2], \"C\")\n\n    def test_getitem_slice(self):\n        lst = RecordingList([\"A\", \"B\", \"C\"])\n        self.assertEqual(lst[1:2], [\"B\"])\n        self.assertEqual(lst[:2], [\"A\", \"B\"])\n        self.assertEqual(lst[1:], [\"B\", \"C\"])\n\n    def test_setitem_int(self):\n        lst = RecordingList([\"A\", \"B\", \"C\"])\n        lst[1] = \"D\"\n        self.assertEqual(list(lst), [\"A\", \"D\", \"C\"])\n        self.assertEqual(\n            lst.record,\n            [\n                (\"add\", \"A\"),\n                (\"add\", \"B\"),\n                (\"add\", \"C\"),\n                (\"remove\", \"B\"),\n                (\"add\", \"D\"),\n            ],\n        )\n\n    def test_setitem_slice(self):\n        lst = RecordingList([\"A\", \"B\", \"C\"])\n        lst[1:2] = [\"D\", \"E\"]\n        self.assertEqual(list(lst), [\"A\", \"D\", \"E\", \"C\"])\n        self.assertEqual(\n            lst.record,\n            [\n                (\"add\", \"A\"),\n                (\"add\", \"B\"),\n                (\"add\", \"C\"),\n                (\"remove\", \"B\"),\n                (\"add\", \"D\"),\n                (\"add\", \"E\"),\n            ],\n        )\n\n    def test_delitem_int(self):\n        lst = RecordingList([\"A\", \"B\"])\n        del lst[0]\n        self.assertEqual(list(lst), [\"B\"])\n        self.assertEqual(\n            lst.record, [(\"add\", \"A\"), (\"add\", \"B\"), (\"remove\", \"A\")]\n        )\n\n    def test_delitem_slice(self):\n        lst = RecordingList([\"A\", \"B\", \"C\"])\n        del lst[1:]\n        self.assertEqual(list(lst), [\"A\"])\n        self.assertEqual(\n            lst.record,\n            [\n                (\"add\", \"A\"),\n                (\"add\", \"B\"),\n                (\"add\", \"C\"),\n                (\"remove\", \"B\"),\n                (\"remove\", \"C\"),\n            ],\n        )\n\n    def test_len(self):\n        lst = RecordingList([\"A\", \"B\", \"C\"])\n        self.assertEqual(len(lst), 3)\n\n    def test_insert(self):\n        lst = RecordingList([\"A\", \"B\"])\n        lst.insert(1, \"C\")\n        self.assertEqual(list(lst), [\"A\", \"C\", \"B\"])\n        self.assertEqual(\n            lst.record, [(\"add\", \"A\"), (\"add\", \"B\"), (\"add\", \"C\")]\n        )\n\n    def test_append(self):\n        lst = RecordingList([\"A\", \"B\"])\n        lst.append(\"C\")\n        self.assertEqual(list(lst), [\"A\", \"B\", \"C\"])\n        self.assertEqual(\n            lst.record, [(\"add\", \"A\"), (\"add\", \"B\"), (\"add\", \"C\")]\n        )\n\n    def test_remove(self):\n        lst = RecordingList([\"A\", \"B\"])\n        lst.remove(\"A\")\n        self.assertEqual(list(lst), [\"B\"])\n        self.assertEqual(\n            lst.record, [(\"add\", \"A\"), (\"add\", \"B\"), (\"remove\", \"A\")]\n        )\n\n    def test_extend(self):\n        lst = RecordingList()\n        lst.extend([\"A\", \"B\"])\n        self.assertEqual(list(lst), [\"A\", \"B\"])\n        self.assertEqual(lst.record, [(\"add\", \"A\"), (\"add\", \"B\")])\n\n    def test_str(self):\n        lst = RecordingList([\"A\", \"B\"])\n        self.assertEqual(str(lst), str([\"A\", \"B\"]))\n"
  },
  {
    "path": "python/tox.ini",
    "content": "[tox]\nrequires =\n    tox >= 4\n    tox-uv >= 1.0\n\nenv_list =\n    mypy\n    py3{8-13}-{oldest,prerelease}\n    report\n\n[testenv]\npackage = wheel\nsetenv =\n    COVERAGE_FILE = .coverage.{envname}\n# Work around https://github.com/tox-dev/tox-uv/issues/195. Fixed in 1.26.0,\n# which we can require once we finally drop support for python 3.8.\ninstall_command = uv pip install {packages}\n\n[testenv:mypy]\ndescription = check types with mypy\ndeps = -r requirements-mypy.txt\ncommands = mypy gtirb\n\n[testenv:py3{8-13}-{oldest,newest,prerelease}]\n# Test environments for supported python versions. Use py3*-oldest to test using\n# oldest supported dependencies, py3*-newest to test using the newest supported\n# dependencies, and py3*-prerelease to test using prerelease dependency versions\n# (if available).\ndescription = run the tests with pytest under {envname}\ndeps = -r requirements-dev.txt\nuv_resolution =\n    {newest,prerelease}: highest  # install the newest available versions\n    oldest: lowest-direct         # install the oldest available versions\npip_pre =\n    prerelease: true              # install pre-release versions\n    {oldest,newest}: false        # do not install pre-release versions\ncommands =\n    pytest {posargs:--cov --junit-xml=junit-{envname}.xml --junit-prefix={envname}}\n\n[testenv:report]\n# Combine coverage reports.\ndescription = report coverage from recent tests\ndepends = py3{8-13}-{oldest,prerelease}\nskip_install = true\ndeps = -r requirements-dev.txt\nsetenv =\n    COVERAGE_FILE = .coverage\ncommands =\n    coverage combine\n    # Always write the XML report.\n    coverage xml --fail-under=0\n    # Report to the terminal and fail if coverage is under threshold.\n    coverage report\n"
  },
  {
    "path": "python/version.py.in",
    "content": "# Build with CMake to ensure consistent versions across all supported languages.\nAPI_VERSION = (\n    \"@PROJECT_VERSION_MAJOR@.\"\n    \"@PROJECT_VERSION_MINOR@.\"\n    \"@PROJECT_VERSION_PATCH@\"\n    \"@GTIRB_PYTHON_DEV_SUFFIX@\"\n)  # type: str\n\"\"\"The semantic version of this API.\"\"\"\n\nPROTOBUF_VERSION = @GTIRB_PROTOBUF_VERSION@  # type: int\n\"\"\"The version of Protobuf this API can read and write from.\nAttempts to load old Protobuf versions will raise a ``ValueError``.\n\"\"\"\n"
  },
  {
    "path": "resources/windows_version_resource.rc.in",
    "content": "#include <winresrc.h>\n\n#define VER_FILEVERSION             @GTIRB_MAJOR_VERSION@,@GTIRB_MINOR_VERSION@,@GTIRB_PATCH_VERSION@,0\n#define VER_FILEVERSION_STR         \"@GTIRB_MAJOR_VERSION@.@GTIRB_MINOR_VERSION@.@GTIRB_PATCH_VERSION@.0\\0\"\n\n#define VER_PRODUCTVERSION          @GTIRB_MAJOR_VERSION@,@GTIRB_MINOR_VERSION@,@GTIRB_PATCH_VERSION@,0\n#define VER_PRODUCTVERSION_STR      \"@GTIRB_MAJOR_VERSION@.@GTIRB_MINOR_VERSION@.@GTIRB_PATCH_VERSION@.0\\0\"\n\n#ifndef DEBUG\n#define VER_DEBUG                   0\n#else\n#define VER_DEBUG                   VS_FF_DEBUG\n#endif\n\n#if @GTIRB_IS_PRERELEASE@\n#define VER_PRERELEASE              VS_FF_PRERELEASE\n#else\n#define VER_PRERELEASE              0\n#endif\n\n#define VER_INTERNALNAME_STR        \"@PROJECT_NAME@\"\n#define VER_PRODUCTNAME_STR         \"@PROJECT_NAME@\"\n#define VER_COMPANYNAME_STR         \"GrammaTech, Inc\"\n#define VER_FILEDESCRIPTION_STR     \"Intermediate representation for binary analysis and transformation\"\n#define VER_LEGALCOPYRIGHT_STR      \"Copyright (C) 2020 GrammaTech, Inc.\"\n\nVS_VERSION_INFO VERSIONINFO\nFILEVERSION     VER_FILEVERSION\nPRODUCTVERSION  VER_PRODUCTVERSION\nFILEFLAGSMASK   VS_FFI_FILEFLAGSMASK\nFILEFLAGS       (VER_PRERELEASE|VER_DEBUG)\nFILEOS          VOS__WINDOWS32\nFILETYPE        VFT_DLL\nFILESUBTYPE     VFT2_UNKNOWN\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904E4\"\n        BEGIN\n            VALUE \"CompanyName\",      VER_COMPANYNAME_STR\n            VALUE \"FileDescription\",  VER_FILEDESCRIPTION_STR\n            VALUE \"FileVersion\",      VER_FILEVERSION_STR\n            VALUE \"InternalName\",     VER_INTERNALNAME_STR\n            VALUE \"LegalCopyright\",   VER_LEGALCOPYRIGHT_STR\n            VALUE \"ProductName\",      VER_PRODUCTNAME_STR\n            VALUE \"ProductVersion\",   VER_PRODUCTVERSION_STR\n        END\n    END\n\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        /* The following line should only be modified for localized versions.     */\n        /* It consists of any number of WORD,WORD pairs, with each pair           */\n        /* describing a language,codepage combination supported by the file.      */\n        /*                                                                        */\n        /* For example, a file might have values \"0x409,1252\" indicating that it  */\n        /* supports English language (0x409) in the Windows ANSI codepage (1252). */\n\n        VALUE \"Translation\", 0x409, 1252\n    END\nEND\n"
  },
  {
    "path": "src/AuxData.cpp",
    "content": "//===- AuxData.cpp ---------------------------------------------*- C++-*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"AuxData.hpp\"\n#include <gtirb/proto/AuxData.pb.h>\n\nnamespace gtirb {\nvoid AuxData::fromProtobuf(AuxData& Result, const MessageType& Message) {\n  Result.SF.ProtobufType = Message.type_name();\n  Result.SF.RawBytes = Message.data();\n}\n\nvoid AuxData::toProtobuf(MessageType* Message,\n                         const AuxData::SerializedForm& SFToSerialize) const {\n  *Message->mutable_type_name() = SFToSerialize.ProtobufType;\n  *Message->mutable_data() = SFToSerialize.RawBytes;\n}\n\nbool AuxData::checkAuxDataMessageType(const AuxData::MessageType& Message,\n                                      const std::string& ExpectedName) {\n  return Message.type_name() == ExpectedName;\n}\n\n// Present for testing purposes only.\nvoid AuxData::save(std::ostream& Out) const {\n  MessageType Message;\n  this->toProtobuf(&Message);\n  Message.SerializeToOstream(&Out);\n}\n\n// Present for testing purposes only.\nstd::unique_ptr<AuxData>\nAuxData::load(std::istream& In,\n              std::unique_ptr<AuxData> (*FPPtr)(const MessageType&)) {\n  MessageType Message;\n  Message.ParseFromIstream(&In);\n  auto AD = FPPtr(Message);\n  return AD;\n}\n} // namespace gtirb\n"
  },
  {
    "path": "src/AuxDataContainer.cpp",
    "content": "//===- AuxDataContainer.cpp -------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n\n#include \"AuxDataContainer.hpp\"\n#include \"AuxData.hpp\"\n#include \"Context.hpp\"\n#include \"Serialization.hpp\"\n\n#include <memory>\n#include <string>\n\nnamespace gtirb {\n\nstruct AuxDataTypeMap {\n  bool Locked = false;\n  std::map<std::string, std::unique_ptr<AuxDataContainer::AuxDataType>> Map;\n};\n\n// Note: we are explicitly allocating the type map here w/ static\n// storage to avoid having a variable symbol in the DLL interface on\n// Windows. This allows us to not have to worry about dllimport'ing\n// this symbol in client applications.\nstatic AuxDataTypeMap TypeMap;\n\nvoid AuxDataContainer::registerAuxDataTypeInternal(\n    const char* Name, std::unique_ptr<AuxDataType> ADT) {\n  assert(!TypeMap.Locked && \"New AuxData types cannot be added at this point.\");\n\n  if (auto it = TypeMap.Map.find(Name); it != TypeMap.Map.end()) {\n    // Failing this assertion indicates that two attempts to\n    // register the same AuxData name are using different types.\n    assert(it->second->getApiTypeId() == ADT->getApiTypeId() &&\n           \"Different types registered for the same AuxData name.\");\n    return;\n  }\n\n  TypeMap.Map.insert(std::make_pair(std::string(Name), std::move(ADT)));\n}\n\nbool AuxDataContainer::checkAuxDataRegistration(const char* Name,\n                                                std::size_t Id) {\n  auto TypeEntry = TypeMap.Map.find(Name);\n  return TypeEntry != TypeMap.Map.end() &&\n         TypeEntry->second->getApiTypeId() == Id;\n}\n\nconst AuxDataContainer::AuxDataType*\nAuxDataContainer::lookupAuxDataType(const std::string& Name) {\n  if (auto It = TypeMap.Map.find(Name); It != TypeMap.Map.end()) {\n    return It->second.get();\n  }\n  return nullptr;\n}\n\nAuxDataContainer::AuxDataContainer(Context& C, Node::Kind knd) : Node(C, knd) {\n  // Once this is called, we outlaw registering new AuxData types.\n  TypeMap.Locked = true;\n}\n\nAuxDataContainer::AuxDataContainer(Context& C, Node::Kind knd, const UUID& U)\n    : Node(C, knd, U) {\n  // Once this is called, we outlaw registering new AuxData types.\n  TypeMap.Locked = true;\n}\n\n}; // namespace gtirb\n"
  },
  {
    "path": "src/ByteInterval.cpp",
    "content": "//===- ByteInterval.cpp -----------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"IR.hpp\"\n#include \"Serialization.hpp\"\n#include \"SymbolicExpressionSerialization.hpp\"\n#include <gtirb/ByteInterval.hpp>\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/DataBlock.hpp>\n#include <gtirb/Module.hpp>\n#include <gtirb/Section.hpp>\n#include <gtirb/Utility.hpp>\n#include <gtirb/proto/ByteInterval.pb.h>\n#include <iterator>\n\nusing namespace gtirb;\n\nclass ByteInterval::CodeBlockObserverImpl : public CodeBlockObserver {\npublic:\n  CodeBlockObserverImpl(ByteInterval* BI_) : BI(BI_) {}\n\n  ChangeStatus sizeChange(CodeBlock* B, uint64_t OldSize,\n                          uint64_t NewSize) override;\n\n  ChangeStatus decodeModeChange(CodeBlock* B, DecodeMode OldMode,\n                                DecodeMode NewMode) override;\n\nprivate:\n  ByteInterval* BI;\n};\n\nclass ByteInterval::DataBlockObserverImpl : public DataBlockObserver {\npublic:\n  DataBlockObserverImpl(ByteInterval* BI_) : BI(BI_) {}\n\n  ChangeStatus sizeChange(DataBlock* B, uint64_t OldSize,\n                          uint64_t NewSize) override;\n\nprivate:\n  ByteInterval* BI;\n};\n\nByteInterval::ByteInterval(Context& C) : ByteInterval(C, std::nullopt, 0, 0) {}\n\nByteInterval::ByteInterval(Context& C, std::optional<Addr> A, uint64_t S,\n                           uint64_t InitSize)\n    : Node(C, Kind::ByteInterval), Address(A), Size(S), Bytes(InitSize),\n      CBO(std::make_unique<CodeBlockObserverImpl>(this)),\n      DBO(std::make_unique<DataBlockObserverImpl>(this)) {}\n\nByteInterval::ByteInterval(Context& C, std::optional<Addr> A, uint64_t S,\n                           uint64_t InitSize, const UUID& U)\n    : Node(C, Kind::ByteInterval, U), Address(A), Size(S), Bytes(InitSize),\n      CBO(std::make_unique<CodeBlockObserverImpl>(this)),\n      DBO(std::make_unique<DataBlockObserverImpl>(this)) {}\n\nvoid ByteInterval::toProtobuf(MessageType* Message) const {\n  nodeUUIDToBytes(this, *Message->mutable_uuid());\n\n  if (Address.has_value()) {\n    Message->set_has_address(true);\n    Message->set_address((uint64_t)*Address);\n  } else {\n    Message->set_has_address(false);\n  }\n\n  Message->set_size(getSize());\n  auto BytesIt = bytes_begin<char>();\n  auto InitSize = getInitializedSize();\n  Message->mutable_contents()->reserve(InitSize);\n  std::copy(BytesIt, BytesIt + InitSize,\n            std::back_inserter(*Message->mutable_contents()));\n\n  for (const auto& N : this->blocks()) {\n    auto* ProtoBlock = Message->add_blocks();\n\n    switch (N.getKind()) {\n    case Node::Kind::CodeBlock: {\n      auto& B = cast<CodeBlock>(N);\n      ProtoBlock->set_offset(B.getOffset());\n      B.toProtobuf(ProtoBlock->mutable_code());\n    } break;\n    case Node::Kind::DataBlock: {\n      auto& B = cast<DataBlock>(N);\n      ProtoBlock->set_offset(B.getOffset());\n      B.toProtobuf(ProtoBlock->mutable_data());\n    } break;\n    default: {\n      assert(!\"unknown Node::Kind in ByteInterval::toProtobuf\");\n    }\n    }\n  }\n\n  auto& ProtoSymExpr = *Message->mutable_symbolic_expressions();\n  for (const auto& SEE : this->symbolic_expressions()) {\n    ProtoSymExpr[SEE.getOffset()] =\n        gtirb::toProtobuf(SEE.getSymbolicExpression());\n  }\n}\n\nErrorOr<ByteInterval*> ByteInterval::fromProtobuf(Context& C,\n                                                  const MessageType& Message) {\n  std::optional<Addr> A;\n  if (Message.has_address()) {\n    A = Addr(Message.address());\n  }\n\n  UUID Id;\n  if (!uuidFromBytes(Message.uuid(), Id)) {\n    std::stringstream ss;\n    ss << \"Could not load ByteInterval\";\n    if (A)\n      ss << \"@ \" << *A;\n\n    return {IR::load_error::BadUUID, ss.str()};\n  }\n\n  ByteInterval* BI = ByteInterval::Create(\n      C, A, Message.contents().begin(), Message.contents().end(),\n      Message.size(), Message.contents().size(), Id);\n  std::stringstream ss;\n  if (A) {\n    ss << \"@\" << A;\n  }\n  ErrorInfo Err{IR::load_error::CorruptByteInterval, ss.str()};\n  for (const auto& ProtoBlock : Message.blocks()) {\n    switch (ProtoBlock.value_case()) {\n    case proto::Block::ValueCase::kCode: {\n      auto B = CodeBlock::fromProtobuf(C, ProtoBlock.code());\n      if (!B) {\n        Err.Msg += \"\\n\" + B.getError().message();\n        return Err;\n      }\n      BI->addBlock(ProtoBlock.offset(), *B);\n    } break;\n    case proto::Block::ValueCase::kData: {\n      auto B = DataBlock::fromProtobuf(C, ProtoBlock.data());\n      if (!B) {\n        Err.Msg += \"\\n\" + B.getError().message();\n        return Err;\n      }\n      BI->addBlock(ProtoBlock.offset(), *B);\n    } break;\n    default: {\n      return {IR::load_error::CorruptFile,\n              \"unknown Block::ValueCase in ByteInterval::fromProtobuf\"};\n    }\n    }\n  }\n  return BI;\n}\n\nbool ByteInterval::symbolicExpressionsFromProtobuf(Context& C,\n                                                   const MessageType& Message) {\n  bool Result = true;\n  for (const auto& Pair : Message.symbolic_expressions()) {\n    SymbolicExpression SymExpr;\n    if (gtirb::fromProtobuf(C, SymExpr, Pair.second))\n      SymbolicExpressions[Pair.first] = SymExpr;\n    else {\n      Result = false;\n      break;\n    }\n  }\n  return Result;\n}\n\n// Present for testing purposes only.\nvoid ByteInterval::save(std::ostream& Out) const {\n  MessageType Message;\n  this->toProtobuf(&Message);\n  Message.SerializeToOstream(&Out);\n}\n\n// Present for testing purposes only.\nByteInterval* ByteInterval::load(Context& C, std::istream& In) {\n  MessageType Message;\n  Message.ParseFromIstream(&In);\n  auto BI = ByteInterval::fromProtobuf(C, Message);\n  if (BI) {\n    return *BI;\n  }\n  return nullptr;\n}\n\n// Present for testing purposes only.\nbool ByteInterval::loadSymbolicExpressions(Context& C, std::istream& In) {\n  MessageType Message;\n  Message.ParseFromIstream(&In);\n  return ByteInterval::symbolicExpressionsFromProtobuf(C, Message);\n}\n\nvoid ByteInterval::setAddress(std::optional<Addr> A) {\n  if (Observer) {\n    [[maybe_unused]] ChangeStatus Status = Observer->changeExtent(\n        this, [&A](ByteInterval* BI) { BI->Address = A; });\n    assert(Status != ChangeStatus::Rejected &&\n           \"recovering from rejected address change is not implemented yet\");\n    Status = Observer->moveCodeBlocks(this, code_blocks());\n    assert(Status != ChangeStatus::Rejected &&\n           \"recovering from rejected address change is not implemented yet\");\n    Status = Observer->moveDataBlocks(this, data_blocks());\n    assert(Status != ChangeStatus::Rejected &&\n           \"recovering from rejected address change is not implemented yet\");\n  } else {\n    Address = A;\n  }\n}\n\nvoid ByteInterval::setSize(uint64_t S) {\n  if (Observer) {\n    [[maybe_unused]] ChangeStatus Status =\n        Observer->changeExtent(this, [&S](ByteInterval* BI) { BI->Size = S; });\n    assert(Status != ChangeStatus::Rejected &&\n           \"recovering from rejected size change is not implemented yet\");\n  } else {\n    Size = S;\n  }\n  if (S < getInitializedSize()) {\n    setInitializedSize(S);\n  }\n}\n\nstatic inline ChangeStatus removeBlocks(ByteIntervalObserver* Observer,\n                                        ByteInterval* BI,\n                                        ByteInterval::code_block_range Range) {\n  return Observer->removeCodeBlocks(BI, Range);\n}\n\nstatic inline ChangeStatus removeBlocks(ByteIntervalObserver* Observer,\n                                        ByteInterval* BI,\n                                        ByteInterval::data_block_range Range) {\n  return Observer->removeDataBlocks(BI, Range);\n}\n\ntemplate <typename BlockType, typename IterType>\nChangeStatus ByteInterval::removeBlock(BlockType* B) {\n  auto& Index = Blocks.get<by_pointer>();\n  if (auto Iter = Index.find(B); Iter != Index.end()) {\n    if (Observer) {\n      auto Begin = Blocks.project<0>(Iter);\n      auto End = std::next(Begin);\n      auto Range = boost::make_iterator_range(\n          IterType(typename IterType::base_type(Begin, End)),\n          IterType(typename IterType::base_type(End, End)));\n      [[maybe_unused]] ChangeStatus Status =\n          removeBlocks(Observer, this, Range);\n      // None of the known observers reject removals. If that changes, this\n      // implementation will need to be changed as well. Because addBlock\n      // assumes that this removal will not be rejected, it will also need to\n      // be updated.\n      assert(Status != ChangeStatus::Rejected &&\n             \"recovering from rejected removal is not implemented yet\");\n    }\n\n    updateIntervalMap(B, B->getSize(), std::nullopt);\n    Index.erase(Iter);\n    B->setParent(nullptr, nullptr);\n    return ChangeStatus::Accepted;\n  }\n  return ChangeStatus::NoChange;\n}\n\nChangeStatus ByteInterval::removeBlock(CodeBlock* B) {\n  return removeBlock<CodeBlock, code_block_iterator>(B);\n}\n\nChangeStatus ByteInterval::removeBlock(DataBlock* B) {\n  return removeBlock<DataBlock, data_block_iterator>(B);\n}\n\nstatic inline CodeBlockObserver* getObserver(CodeBlock*, CodeBlockObserver* CBO,\n                                             DataBlockObserver*) {\n  return CBO;\n}\n\nstatic inline DataBlockObserver* getObserver(DataBlock*, CodeBlockObserver*,\n                                             DataBlockObserver* DBO) {\n  return DBO;\n}\n\nstatic inline ChangeStatus addBlocks(ByteIntervalObserver* Observer,\n                                     ByteInterval* BI,\n                                     ByteInterval::code_block_range Range) {\n  return Observer->addCodeBlocks(BI, Range);\n}\n\nstatic inline ChangeStatus addBlocks(ByteIntervalObserver* Observer,\n                                     ByteInterval* BI,\n                                     ByteInterval::data_block_range Range) {\n  return Observer->addDataBlocks(BI, Range);\n}\n\nstatic inline ChangeStatus moveBlocks(ByteIntervalObserver* Observer,\n                                      ByteInterval* BI,\n                                      ByteInterval::code_block_range Range) {\n  return Observer->moveCodeBlocks(BI, Range);\n}\n\nstatic inline ChangeStatus moveBlocks(ByteIntervalObserver* Observer,\n                                      ByteInterval* BI,\n                                      ByteInterval::data_block_range Range) {\n  return Observer->moveDataBlocks(BI, Range);\n}\n\ntemplate <typename BlockType, typename IterType>\nChangeStatus ByteInterval::addBlock(uint64_t Off, BlockType* B) {\n  // Determine if we're moving or adding a block.\n  bool IsMove = false;\n  ByteInterval* BI = B->getByteInterval();\n  if (BI == this) {\n    if (Off == B->getOffset()) {\n      return ChangeStatus::NoChange;\n    } else {\n      IsMove = true;\n    }\n  }\n\n  // Remove the old block.\n  if (!IsMove) {\n    if (BI) {\n      [[maybe_unused]] ChangeStatus Status = BI->removeBlock(B);\n      assert(Status != ChangeStatus::Rejected &&\n             \"failed to remove node from parent\");\n    }\n\n    B->setParent(this, getObserver(B, CBO.get(), DBO.get()));\n  }\n\n  // Remove the block from the interval map at the old offset.\n  if (IsMove) {\n    updateIntervalMap(B, B->getSize(), std::nullopt);\n  }\n\n  // Actually modify the offset.\n  auto Begin = Blocks.get<by_offset>().end();\n  if (IsMove) {\n    Blocks.get<by_pointer>().modify(Blocks.get<by_pointer>().find(B),\n                                    [Off](auto& Entry) { Entry.Offset = Off; });\n    Begin = Blocks.project<by_offset>(Blocks.get<by_pointer>().find(B));\n  } else {\n    Begin = Blocks.emplace(Off, B).first;\n  }\n\n  // Add the block to the interval map at the new offset.\n  updateIntervalMap(B, std::nullopt, B->getSize());\n\n  // Only fire events if we have an observer.\n  if (!Observer) {\n    return ChangeStatus::Accepted;\n  }\n\n  // Get the range to use.\n  assert(Begin != Blocks.get<by_offset>().end());\n  auto End = std::next(Begin);\n  auto Range = boost::make_iterator_range(\n      IterType(typename IterType::base_type(Begin, End)),\n      IterType(typename IterType::base_type(End, End)));\n\n  // Fire the move/add event.\n  [[maybe_unused]] ChangeStatus Status;\n  if (IsMove) {\n    Status = moveBlocks(Observer, this, Range);\n  } else {\n    Status = addBlocks(Observer, this, Range);\n  }\n\n  // None of the known observers reject insertions. If that changes, this\n  // implementation must be updated.\n  assert(Status != ChangeStatus::Rejected &&\n         \"recovering from rejected insertion is unimplemented\");\n\n  // All good.\n  return ChangeStatus::Accepted;\n}\n\nChangeStatus ByteInterval::addBlock(uint64_t Off, CodeBlock* B) {\n  return addBlock<CodeBlock, code_block_iterator>(Off, B);\n}\n\nChangeStatus ByteInterval::addBlock(uint64_t Off, DataBlock* B) {\n  return addBlock<DataBlock, data_block_iterator>(Off, B);\n}\n\nChangeStatus ByteInterval::CodeBlockObserverImpl::sizeChange(CodeBlock* B,\n                                                             uint64_t OldSize,\n                                                             uint64_t NewSize) {\n  return BI->sizeChange(B, OldSize, NewSize);\n}\n\nChangeStatus ByteInterval::CodeBlockObserverImpl::decodeModeChange(\n    CodeBlock* B, DecodeMode OldMode, DecodeMode NewMode) {\n  return BI->decodeModeChange(B, OldMode, NewMode);\n}\n\nChangeStatus ByteInterval::DataBlockObserverImpl::sizeChange(DataBlock* B,\n                                                             uint64_t OldSize,\n                                                             uint64_t NewSize) {\n  return BI->sizeChange(B, OldSize, NewSize);\n}\n\nvoid ByteInterval::updateIntervalMap(Node* N, std::optional<uint64_t> OldSize,\n                                     std::optional<uint64_t> NewSize) {\n  auto& Index = Blocks.get<by_pointer>();\n  auto Iter = Index.find(N);\n  assert(Iter != Index.end() && \"block observed by non-owner\");\n  if (OldSize)\n    BlockOffsets.subtract(\n        std::make_pair(ByteInterval::BlockIntMap::interval_type::right_open(\n                           Iter->Offset, Iter->Offset + *OldSize),\n                       ByteInterval::BlockIntMap::codomain_type({&*Iter})));\n  if (NewSize)\n    BlockOffsets.add(\n        std::make_pair(ByteInterval::BlockIntMap::interval_type::right_open(\n                           Iter->Offset, Iter->Offset + *NewSize),\n                       ByteInterval::BlockIntMap::codomain_type({&*Iter})));\n}\n\nvoid ByteInterval::updateBlockSortOrder(Node* N) {\n  auto& Index = Blocks.get<by_pointer>();\n  auto Iter = Index.find(N);\n  assert(Iter != Index.end() && \"block observed by non-owner\");\n  Blocks.get<by_pointer>().modify(Iter, [](auto&) {});\n}\n\nChangeStatus ByteInterval::sizeChange(Node* N, uint64_t OldSize,\n                                      uint64_t NewSize) {\n  updateIntervalMap(N, OldSize, NewSize);\n  updateBlockSortOrder(N);\n  return ChangeStatus::Accepted;\n}\n\nChangeStatus ByteInterval::decodeModeChange(CodeBlock* B, DecodeMode,\n                                            DecodeMode) {\n  updateBlockSortOrder(B);\n  return ChangeStatus::Accepted;\n}\n\nboost::endian::order gtirb::ByteInterval::getBoostEndianOrder() const {\n  if (auto* S = getSection()) {\n    if (auto* M = S->getModule()) {\n      switch (M->getByteOrder()) {\n      case (ByteOrder::Big):\n        return boost::endian::order::big;\n      case (ByteOrder::Little):\n        return boost::endian::order::little;\n      default:\n        return boost::endian::order::native;\n      }\n    }\n  }\n\n  return boost::endian::order::native;\n}\n"
  },
  {
    "path": "src/CFG.cpp",
    "content": "//===- CFG.cpp --------------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2021 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"CFG.hpp\"\n#include \"Serialization.hpp\"\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/proto/CFG.pb.h>\n#include <map>\n#include <tuple>\n\nnamespace gtirb {\nGTIRB_EXPORT_API std::ostream& operator<<(std::ostream& OS,\n                                          const ConditionalEdge& CE) {\n  switch (CE) {\n  case ConditionalEdge::OnFalse:\n    OS << \"OnFalse\";\n    break;\n  case ConditionalEdge::OnTrue:\n    OS << \"OnTrue\";\n    break;\n  }\n  return OS;\n}\n\nGTIRB_EXPORT_API std::ostream& operator<<(std::ostream& OS,\n                                          const EdgeType& ET) {\n  switch (ET) {\n  case EdgeType::Branch:\n    OS << \"Branch\";\n    break;\n  case EdgeType::Call:\n    OS << \"Call\";\n    break;\n  case EdgeType::Fallthrough:\n    OS << \"Fallthrough\";\n    break;\n  case EdgeType::Return:\n    OS << \"Return\";\n    break;\n  case EdgeType::Syscall:\n    OS << \"Syscall\";\n    break;\n  case EdgeType::Sysret:\n    OS << \"Sysret\";\n    break;\n  }\n  return OS;\n}\n\nGTIRB_EXPORT_API std::ostream& operator<<(std::ostream& OS,\n                                          const DirectEdge& DE) {\n  switch (DE) {\n  case DirectEdge::IsIndirect:\n    OS << \"IsIndirect\";\n    break;\n  case DirectEdge::IsDirect:\n    OS << \"IsDirect\";\n    break;\n  }\n  return OS;\n}\n\nGTIRB_EXPORT_API std::ostream& operator<<(std::ostream& OS,\n                                          const EdgeLabel& Label) {\n  if (!Label) {\n    OS << \"<No EdgeLabel>\";\n  } else {\n    auto ET = std::get<EdgeType>(*Label);\n    auto DE = std::get<DirectEdge>(*Label);\n    auto CE = std::get<ConditionalEdge>(*Label);\n    OS << \"(\" << CE << \", \" << DE << \", \" << ET << \")\";\n  }\n  return OS;\n}\n\nstd::pair<CFG::vertex_descriptor, bool> addVertex(CfgNode* B, CFG& Cfg) {\n  auto& IdTable = Cfg[boost::graph_bundle];\n  if (auto it = IdTable.find(B); it != IdTable.end()) {\n    return std::make_pair(it->second, false);\n  }\n\n  auto Vertex = add_vertex(Cfg);\n  Cfg[Vertex] = B;\n  IdTable[B] = Vertex;\n  return std::make_pair(Vertex, true);\n}\n\nbool removeVertex(CfgNode* N, CFG& Cfg) {\n  auto& IdTable = Cfg[boost::graph_bundle];\n  if (auto it = IdTable.find(N); it != IdTable.end()) {\n    clear_vertex(it->second, Cfg);\n    remove_vertex(it->second, Cfg);\n    IdTable.erase(it);\n    return true;\n  }\n  return false;\n}\n\nstd::optional<CFG::vertex_descriptor> getVertex(const CfgNode* N,\n                                                const CFG& Cfg) {\n  auto& IdTable = Cfg[boost::graph_bundle];\n  if (auto it = IdTable.find(N); it != IdTable.end()) {\n    return it->second;\n  }\n  return std::nullopt;\n}\n\nstd::optional<CFG::edge_descriptor> addEdge(const CfgNode* From,\n                                            const CfgNode* To, CFG& Cfg) {\n  const auto& IdTable = Cfg[boost::graph_bundle];\n  if (auto it = IdTable.find(From); it != IdTable.end()) {\n    auto FromVertex = it->second;\n    if (it = IdTable.find(To); it != IdTable.end()) {\n      auto ToVertex = it->second;\n      return add_edge(FromVertex, ToVertex, Cfg).first;\n    }\n  }\n  return std::nullopt;\n}\n\nbool removeEdge(const CfgNode* From, const CfgNode* To, CFG& Cfg) {\n  const auto& IdTable = Cfg[boost::graph_bundle];\n  if (auto it = IdTable.find(From); it != IdTable.end()) {\n    auto FromVertex = it->second;\n    if (it = IdTable.find(To); it != IdTable.end()) {\n      auto ToVertex = it->second;\n      remove_edge(FromVertex, ToVertex, Cfg);\n      return true;\n    }\n  }\n  return false;\n}\n\nbool removeEdge(const CfgNode* From, const CfgNode* To, const EdgeLabel Label,\n                CFG& Cfg) {\n  bool remove_called = true, deleted = false;\n  const auto& IdTable = Cfg[boost::graph_bundle];\n  boost::graph_traits<CFG>::out_edge_iterator ei, edge_end;\n  if (auto it = IdTable.find(From); it != IdTable.end()) {\n    auto FromVertex = it->second;\n    if (it = IdTable.find(To); it != IdTable.end()) {\n      while (remove_called) {\n        remove_called = false;\n        for (boost::tie(ei, edge_end) = out_edges(FromVertex, Cfg);\n             ei != edge_end; ++ei) {\n          if (Cfg[*ei] == Label) {\n            remove_edge(ei, Cfg);\n            // As remove_edge invalidate all iterators\n            // the iteration process should be restarted\n            remove_called = true;\n            deleted = true;\n            break;\n          }\n        }\n      }\n    }\n  }\n  return deleted;\n}\n\nboost::iterator_range<const_cfg_iterator> nodes(const CFG& Cfg) {\n  auto Vs = vertices(Cfg);\n  return boost::make_iterator_range(\n      const_cfg_iterator(cfg_node_iter_base(Cfg, Vs.first)),\n      const_cfg_iterator(cfg_node_iter_base(Cfg, Vs.second)));\n}\n\nboost::iterator_range<cfg_iterator> nodes(CFG& Cfg) {\n  auto Vs = vertices(Cfg);\n  return boost::make_iterator_range(\n      cfg_iterator(cfg_node_iter_base(Cfg, Vs.first)),\n      cfg_iterator(cfg_node_iter_base(Cfg, Vs.second)));\n}\n\nboost::iterator_range<const_block_iterator> blocks(const CFG& Cfg) {\n  auto Vs = vertices(Cfg);\n  return boost::make_iterator_range(\n      const_block_iterator(Cfg, Vs.first, Vs.second),\n      const_block_iterator(Cfg, Vs.second, Vs.second));\n}\n\nboost::iterator_range<block_iterator> blocks(CFG& Cfg) {\n  auto Vs = vertices(Cfg);\n  return boost::make_iterator_range(block_iterator(Cfg, Vs.first, Vs.second),\n                                    block_iterator(Cfg, Vs.second, Vs.second));\n}\n\nproto::CFG toProtobuf(const CFG& Cfg) {\n  proto::CFG Message;\n  auto MessageVertices = Message.mutable_vertices();\n  for (const Node& N : nodes(Cfg)) {\n    auto* M = MessageVertices->Add();\n    nodeUUIDToBytes(&N, *M);\n  }\n\n  auto MessageEdges = Message.mutable_edges();\n  for (const auto& E : boost::make_iterator_range(edges(Cfg))) {\n    auto M = MessageEdges->Add();\n    nodeUUIDToBytes(Cfg[source(E, Cfg)], *M->mutable_source_uuid());\n    nodeUUIDToBytes(Cfg[target(E, Cfg)], *M->mutable_target_uuid());\n    if (auto Label = Cfg[E]) {\n      auto* L = M->mutable_label();\n      L->set_conditional(std::get<ConditionalEdge>(*Label) ==\n                         ConditionalEdge::OnTrue);\n      L->set_direct(std::get<DirectEdge>(*Label) == DirectEdge::IsDirect);\n      L->set_type(static_cast<proto::EdgeType>(std::get<EdgeType>(*Label)));\n    }\n  }\n  return Message;\n}\n\nbool fromProtobuf(Context& C, CFG& Result, const proto::CFG& Message) {\n  // Because we're deserializing, we have to assume the data is attacker-\n  // controlled and may be malicious. We cannot use cast<> because an attacker\n  // could specify the UUID to a node of the incorrect type. Instead, we use\n  // dyn_cast<> and assert as needed.\n  for (const auto& M : Message.vertices()) {\n    UUID Id;\n    if (!uuidFromBytes(M, Id))\n      return false;\n    auto* N = dyn_cast_or_null<CfgNode>(Node::getByUUID(C, Id));\n    assert(N && \"CFG message contains vertex that is not a CfgNode!\");\n    if (!N)\n      return false;\n    addVertex(N, Result);\n  }\n  for (const auto& M : Message.edges()) {\n    UUID Id;\n    if (!uuidFromBytes(M.source_uuid(), Id))\n      return false;\n    CfgNode* Source = dyn_cast_or_null<CfgNode>(Node::getByUUID(C, Id));\n\n    if (!uuidFromBytes(M.target_uuid(), Id))\n      return false;\n    CfgNode* Target = dyn_cast_or_null<CfgNode>(Node::getByUUID(C, Id));\n    if (Source && Target) {\n      if (auto E = addEdge(Source, Target, Result); E && M.has_label()) {\n        auto& L = M.label();\n        Result[*E] = std::make_tuple(L.conditional() ? ConditionalEdge::OnTrue\n                                                     : ConditionalEdge::OnFalse,\n                                     L.direct() ? DirectEdge::IsDirect\n                                                : DirectEdge::IsIndirect,\n                                     static_cast<EdgeType>(L.type()));\n      }\n    }\n  }\n  return true;\n}\n\n// This function is defined here w/ GTIRB_EXPORT_API to provide a\n// means for test code to directly invoke serialization routines on a\n// CFG. This is a capability not supported for GTIRB clients, but must\n// be made available to the testing system.\nvoid GTIRB_EXPORT_API cfgSave(const CFG& Cfg, std::ostream& Out) {\n  proto::CFG Message = toProtobuf(Cfg);\n  Message.SerializeToOstream(&Out);\n}\n\n// This function is defined here w/ GTIRB_EXPORT_API to provide a\n// means for test code to directly invoke serialization routines on a\n// CFG. This is a capability not supported for GTIRB clients, but must\n// be made available to the testing system.\nvoid GTIRB_EXPORT_API cfgLoad(Context& C, CFG& Result, std::istream& In) {\n  proto::CFG Message;\n  Message.ParseFromIstream(&In);\n  (void)fromProtobuf(C, Result, Message);\n}\n\n} // namespace gtirb\n"
  },
  {
    "path": "src/CFGSerialization.hpp",
    "content": "//===- CFGSerialization.hpp -------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n\n#ifndef GTIRB_CFG_SERIALIZATION_HPP\n#define GTIRB_CFG_SERIALIZATION_HPP\n\n#include <gtirb/CFG.hpp>\n\nnamespace gtirb {\nclass Context;\nnamespace proto {\nclass CFG;\n}\n\n/// @cond INTERNAL\n/// \\ingroup CFG_GROUP\n/// \\brief Serialize a \\ref CFG into a protobuf message.\n///\n/// \\param Cfg   The CFG to serialize.\n///\n/// \\return A protobuf message representing the \\ref CFG and its\n/// component blocks (\\ref Block).\nproto::CFG toProtobuf(const CFG& Cfg);\n\n/// \\ingroup CFG_GROUP\n/// \\brief Initialize a \\ref CFG from a protobuf message.\n///\n/// \\param      C        The Context in which the deserialized CFG will be held.\n/// \\param      Message  The protobuf message from which to deserialize.\n/// \\param[out] Result   The CFG to initialize.\n///\n/// \\return true if the \\ref CFG could be deserialized, false otherwise.\nbool fromProtobuf(Context& C, CFG& Result, const proto::CFG& Message);\n/// @endcond\n\n} // namespace gtirb\n\n#endif // GTIRB_CFG_SERIALIZATION_HPP\n"
  },
  {
    "path": "src/CMakeLists.txt",
    "content": "set(PROJECT_NAME gtirb)\n\nadd_subdirectory(gtirb/proto)\n\nif(GTIRB_RUN_CLANG_TIDY)\n  find_program(\n    CLANG_TIDY_EXE\n    NAMES \"clang-tidy\"\n    DOC \"Path to clang-tidy executable\"\n  )\n  if(NOT CLANG_TIDY_EXE)\n    message(STATUS \"clang-tidy not found.\")\n  else()\n    message(STATUS \"clang-tidy found: ${CLANG_TIDY_EXE}\")\n  endif()\nelse()\n  message(STATUS \"clang-tidy disabled.\")\nendif()\n\nif(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)\n  # add_compile_options(-wd4251)  # Non-exportable template classes.\n  add_compile_options(-DBOOST_UUID_RANDOM_PROVIDER_FORCE_WINCRYPT)\nelseif(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU)\n  # add_compile_options(-Wno-unused-function)\n  add_compile_options(-mtune=generic)\n  add_compile_options(-pthread)\nelseif(${CMAKE_CXX_COMPILER_ID} STREQUAL Clang)\n  # add_compile_options(-Wno-unused-function)\n  add_compile_options(-mtune=generic)\n  add_compile_options(-pthread)\nendif()\n\n# generate version.h from version.h.in\nconfigure_file(\n  \"${CMAKE_SOURCE_DIR}/include/gtirb/version.h.in\"\n  \"${CMAKE_BINARY_DIR}/include/gtirb/version.h\" @ONLY\n)\n\n# specify header files that need to be installed\nset(${PROJECT_NAME}_H\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/Addr.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/Allocator.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/AuxData.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/AuxDataContainer.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/AuxDataSchema.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/ByteInterval.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/CFG.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/Casting.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/CfgNode.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/CodeBlock.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/Context.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/DataBlock.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/DecodeMode.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/ErrorOr.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/Export.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/IR.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/Module.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/Node.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/Observer.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/Offset.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/ProxyBlock.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/Section.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/Symbol.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/SymbolicExpression.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/Utility.hpp\"\n    \"${CMAKE_SOURCE_DIR}/include/gtirb/gtirb.hpp\"\n)\n\n# specify source files\nset(${PROJECT_NAME}_SRC\n    AuxData.cpp\n    AuxDataContainer.cpp\n    ByteInterval.cpp\n    CodeBlock.cpp\n    Context.cpp\n    CFG.cpp\n    DataBlock.cpp\n    ErrorOr.cpp\n    IR.cpp\n    Module.cpp\n    Node.cpp\n    Offset.cpp\n    ProxyBlock.cpp\n    Section.cpp\n    Serialization.cpp\n    Symbol.cpp\n    SymbolicExpression.cpp\n    Utility.cpp\n)\n\nfile(GLOB ProtoFiles \"${CMAKE_CURRENT_SOURCE_DIR}/gtirb/proto/*.proto\")\nset(${PROJECT_NAME}_PROTO ${ProtoFiles})\nsource_group(\"proto\" FILES ${ProtoFiles})\n\nif(UNIX AND NOT WIN32)\n  set(SYSLIBS ${CMAKE_DL_LIBS})\nelse()\n  set(SYSLIBS)\nendif()\n\ngtirb_add_library()\n# FIXME We should be setting SOVERSION with an ABI version number once the ABI\n# stabilizes. For now, since most patches affect the ABI anyway, we just use the\n# GTIRB_VERSION as the SOVERSION.\nset_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${GTIRB_VERSION})\nif(WIN32)\n  # FIXME: We need to figure out how to handle cutting a release build. For the\n  # moment, treat everything as a pre-release build.\n  set(GTIRB_IS_PRERELEASE 1)\n  configure_file(\n    ${CMAKE_SOURCE_DIR}/resources/windows_version_resource.rc.in\n    ${CMAKE_BINARY_DIR}/version.rc @ONLY\n  )\n  target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR}/version.rc)\n  source_group(Resources FILES ${CMAKE_BINARY_DIR}/version.rc)\nendif()\n\n# Find our headers\ntarget_include_directories(\n  ${PROJECT_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>\n)\ntarget_include_directories(\n  ${PROJECT_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/include>\n)\ntarget_include_directories(\n  ${PROJECT_NAME} PRIVATE $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include/gtirb>\n)\ntarget_include_directories(\n  ${PROJECT_NAME} PRIVATE $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/src/>\n)\n\n# NOTE (2020-12): tried using protobuf::libprotobuf to get relocatable exports,\n# but it is apparently treated inconsistently between static and shared builds.\n# For simplicity, we revert to using ${Protobuf_LIBRARIES} for now.\n\ntarget_link_libraries(\n  ${PROJECT_NAME}\n  PUBLIC ${SYSLIBS}\n         ${Boost_LIBRARIES}\n         ${Protobuf_LIBRARIES}\n         # Link in this static lib, but don't make it a transitive dependency of\n         # TestGTIRB, etc\n  PRIVATE gtirb_proto\n)\ntarget_compile_definitions(\n  ${PROJECT_NAME} PRIVATE GTIRB_${PROJECT_NAME}_EXPORTS\n  GTIRB_WRAP_UTILS_IN_NAMESPACE\n)\ntarget_include_directories(${PROJECT_NAME} PUBLIC \"${PROTOBUF_INCLUDE_DIRS}\")\n\nif(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)\n  # These four warnings come from protobuf headers, disabling them this way\n  # means that projects which link to gtirb via cmake won't have to deal with\n  # them.\n  target_compile_options(${PROJECT_NAME} PUBLIC -wd4100) # unreferenced formal\n                                                         # parameter\n  target_compile_options(\n    ${PROJECT_NAME} PUBLIC -wd4127\n  ) # conditional expression is constant\n  target_compile_options(\n    ${PROJECT_NAME} PUBLIC -wd4244\n  ) # conversion from 'type1' to 'type2', possible loss of data\n  target_compile_definitions(\n    ${PROJECT_NAME} PUBLIC\n    _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING\n  )\n\n  target_compile_options(\n    ${PROJECT_NAME} PUBLIC -wd4251\n  ) # 'identifier' : class 'type' needs to have dll- interface to be used by\n    # clients of class 'type2'\n  target_compile_options(${PROJECT_NAME} PUBLIC -wd4275) # Non-dll interface\n                                                         # base classes.\nendif()\n\nif(UNIX\n   AND NOT CYGWIN\n   AND (\"${CMAKE_BUILD_TYPE}\" STREQUAL \"RelWithDebInfo\" OR \"${CMAKE_BUILD_TYPE}\"\n                                                           STREQUAL \"Debug\")\n   AND ${GTIRB_STRIP_DEBUG_SYMBOLS}\n)\n  string(\n    RANDOM\n    LENGTH 32\n    ALPHABET \"abcdef0123456789\" BUILD_ID\n  )\n  string(SUBSTRING \"${BUILD_ID}\" 0 2 BUILD_ID_PREFIX)\n  string(SUBSTRING \"${BUILD_ID}\" 2 32 BUILD_ID_SUFFIX)\n  target_link_libraries(${PROJECT_NAME} PRIVATE \"-Wl,--build-id=0x${BUILD_ID}\")\n  add_custom_command(\n    TARGET ${PROJECT_NAME}\n    POST_BUILD\n    COMMAND objcopy --only-keep-debug $<TARGET_FILE:${PROJECT_NAME}>\n            ${CMAKE_BINARY_DIR}/bin/${BUILD_ID_SUFFIX}.debug\n    COMMAND objcopy --strip-debug $<TARGET_FILE:${PROJECT_NAME}>\n  )\n  install(\n    FILES \"${CMAKE_BINARY_DIR}/bin/${BUILD_ID_SUFFIX}.debug\"\n    COMPONENT debug-file\n    DESTINATION \"lib/debug/.build-id/${BUILD_ID_PREFIX}\"\n  )\nendif()\n\nif(CLANG_TIDY_EXE)\n  set_target_properties(\n    ${PROJECT_NAME} PROPERTIES CXX_CLANG_TIDY \"${CLANG_TIDY_EXE}\"\n  )\nendif()\n\nif(GTIRB_ENABLE_TESTS)\n  add_subdirectory(test)\nendif()\n\ninstall(\n  TARGETS ${PROJECT_NAME}\n  COMPONENT library\n  EXPORT gtirbTargets\n  INCLUDES\n  DESTINATION include\n  RUNTIME DESTINATION bin\n  LIBRARY DESTINATION lib\n  ARCHIVE DESTINATION lib\n)\ninstall(\n  FILES ${${PROJECT_NAME}_H}\n  COMPONENT headers\n  DESTINATION include/gtirb\n)\ninstall(\n  DIRECTORY \"${CMAKE_BINARY_DIR}/include/gtirb/proto\"\n  COMPONENT headers\n  DESTINATION include/gtirb\n)\ninstall(\n  FILES \"${CMAKE_BINARY_DIR}/include/gtirb/version.h\"\n  COMPONENT headers\n  DESTINATION include/gtirb\n)\n"
  },
  {
    "path": "src/CodeBlock.cpp",
    "content": "//===- CodeBlock.cpp --------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"IR.hpp\"\n#include \"Serialization.hpp\"\n#include <gtirb/ByteInterval.hpp>\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/proto/CodeBlock.pb.h>\n\nusing namespace gtirb;\n\nvoid CodeBlock::toProtobuf(MessageType* Message) const {\n  nodeUUIDToBytes(this, *Message->mutable_uuid());\n  Message->set_size(this->Size);\n  Message->set_decode_mode(static_cast<proto::DecodeMode>(this->DecodeMode));\n}\n\nErrorOr<CodeBlock*> CodeBlock::fromProtobuf(Context& C,\n                                            const MessageType& Message) {\n  // Because we do not have an offset, we cannot create the code block and\n  // set its parent at the same time.\n  UUID Id;\n  if (!uuidFromBytes(Message.uuid(), Id))\n    return {IR::load_error::BadUUID, \"Cannot load code block\"};\n\n  return CodeBlock::Create(\n      C, Message.size(), static_cast<gtirb::DecodeMode>(Message.decode_mode()),\n      Id);\n}\n\nuint64_t CodeBlock::getOffset() const {\n  assert(Parent &&\n         \"invalid call to CodeBlock::getOffset: Parent must not be null!\");\n  return Parent->nodeToBlock(this).getOffset();\n}\n\nstd::optional<Addr> CodeBlock::getAddress() const {\n  if (!Parent) {\n    return std::nullopt;\n  }\n  if (auto BaseAddr = Parent->getAddress()) {\n    return *BaseAddr + getOffset();\n  }\n  return std::nullopt;\n}\n\n// Present for testing purposes only.\nvoid CodeBlock::save(std::ostream& Out) const {\n  MessageType Message;\n  this->toProtobuf(&Message);\n  Message.SerializeToOstream(&Out);\n}\n\n// Present for testing purposes only.\nCodeBlock* CodeBlock::load(Context& C, std::istream& In) {\n  MessageType Message;\n  Message.ParseFromIstream(&In);\n  auto CB = CodeBlock::fromProtobuf(C, Message);\n  if (CB)\n    return *CB;\n  return nullptr;\n}\n"
  },
  {
    "path": "src/Context.cpp",
    "content": "//===- Context.cpp ----------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"Context.hpp\"\n#include <gtirb/ByteInterval.hpp>\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/DataBlock.hpp>\n#include <gtirb/IR.hpp>\n#include <gtirb/Module.hpp>\n#include <gtirb/Node.hpp>\n#include <gtirb/ProxyBlock.hpp>\n#include <gtirb/Section.hpp>\n#include <gtirb/Symbol.hpp>\n\nusing namespace gtirb;\n\n// By moving these declarations here, we avoid instantiating the default\n// ctor/dtor in other compilation units which include Context.hpp, where some\n// of the Node types may be incomplete.\nContext::Context() = default;\nContext::~Context() = default;\n\nvoid Context::unregisterNode(const Node* N) { UuidMap.erase(N->getUUID()); }\n\nvoid Context::ForgetAllocations() {\n  NodeAllocator.ForgetAllocations();\n  CodeBlockAllocator.ForgetAllocations();\n  ByteIntervalAllocator.ForgetAllocations();\n  DataBlockAllocator.ForgetAllocations();\n  IrAllocator.ForgetAllocations();\n  ModuleAllocator.ForgetAllocations();\n  ProxyBlockAllocator.ForgetAllocations();\n  SectionAllocator.ForgetAllocations();\n  SymbolAllocator.ForgetAllocations();\n}\n\nconst Node* Context::findNode(const UUID& ID) const {\n  auto Iter = UuidMap.find(ID);\n  return Iter != UuidMap.end() ? Iter->second : nullptr;\n}\n\nNode* Context::findNode(const UUID& ID) {\n  auto Iter = UuidMap.find(ID);\n  return Iter != UuidMap.end() ? Iter->second : nullptr;\n}\n\ntemplate <> void* Context::Allocate<Node>() const {\n  return NodeAllocator.Allocate();\n}\ntemplate <> void* Context::Allocate<CodeBlock>() const {\n  return CodeBlockAllocator.Allocate();\n}\ntemplate <> void* Context::Allocate<ByteInterval>() const {\n  return ByteIntervalAllocator.Allocate();\n}\ntemplate <> void* Context::Allocate<DataBlock>() const {\n  return DataBlockAllocator.Allocate();\n}\ntemplate <> void* Context::Allocate<IR>() const {\n  return IrAllocator.Allocate();\n}\ntemplate <> void* Context::Allocate<Module>() const {\n  return ModuleAllocator.Allocate();\n}\ntemplate <> void* Context::Allocate<ProxyBlock>() const {\n  return ProxyBlockAllocator.Allocate();\n}\ntemplate <> void* Context::Allocate<Section>() const {\n  return SectionAllocator.Allocate();\n}\ntemplate <> void* Context::Allocate<Symbol>() const {\n  return SymbolAllocator.Allocate();\n}\n"
  },
  {
    "path": "src/DataBlock.cpp",
    "content": "//===- DataBlock.cpp -------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"IR.hpp\"\n#include \"Serialization.hpp\"\n#include <gtirb/ByteInterval.hpp>\n#include <gtirb/DataBlock.hpp>\n#include <gtirb/proto/DataBlock.pb.h>\n\nusing namespace gtirb;\n\nvoid DataBlock::toProtobuf(MessageType* Message) const {\n  nodeUUIDToBytes(this, *Message->mutable_uuid());\n  Message->set_size(this->Size);\n}\n\nErrorOr<DataBlock*> DataBlock::fromProtobuf(Context& C,\n                                            const MessageType& Message) {\n  UUID Id;\n  if (!uuidFromBytes(Message.uuid(), Id))\n    return {IR::load_error::BadUUID, \"Cannot load DataBlock\"};\n\n  // Because we do not have an offset, we cannot create the data block and\n  // set its parent at the same time.\n  return DataBlock::Create(C, Message.size(), Id);\n}\n\nuint64_t DataBlock::getOffset() const {\n  assert(Parent &&\n         \"invalid call to DataBlock::getOffset: Parent must not be null!\");\n  return Parent->nodeToBlock(this).getOffset();\n}\n\nstd::optional<Addr> DataBlock::getAddress() const {\n  if (!Parent) {\n    return std::nullopt;\n  }\n  if (auto BaseAddr = Parent->getAddress()) {\n    return *BaseAddr + getOffset();\n  }\n  return std::nullopt;\n}\n\n// Present for testing purposes only.\nvoid DataBlock::save(std::ostream& Out) const {\n  MessageType Message;\n  this->toProtobuf(&Message);\n  Message.SerializeToOstream(&Out);\n}\n\n// Present for testing purposes only.\nDataBlock* DataBlock::load(Context& C, std::istream& In) {\n  MessageType Message;\n  Message.ParseFromIstream(&In);\n  auto DB = DataBlock::fromProtobuf(C, Message);\n  if (DB)\n    return *DB;\n  return nullptr;\n}\n"
  },
  {
    "path": "src/ErrorOr.cpp",
    "content": "#include <ErrorOr.hpp>\n#include <sstream>\n\nnamespace gtirb {\n\nstd::string ErrorInfo::message() const {\n  std::stringstream Stream;\n  Stream << *this;\n  return Stream.str();\n}\n\n} // namespace gtirb\n"
  },
  {
    "path": "src/IR.cpp",
    "content": "//===- IR.cpp ---------------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"CFGSerialization.hpp\"\n#include \"Serialization.hpp\"\n#include <gtirb/DataBlock.hpp>\n#include <gtirb/IR.hpp>\n#include <gtirb/Module.hpp>\n#include <gtirb/Section.hpp>\n#include <gtirb/Symbol.hpp>\n#include <gtirb/SymbolicExpression.hpp>\n#include <gtirb/proto/IR.pb.h>\n#include <google/protobuf/io/coded_stream.h>\n#include <google/protobuf/io/zero_copy_stream_impl.h>\n#include <google/protobuf/util/json_util.h>\n#include <iostream>\n#include <memory>\n\nusing namespace gtirb;\n\nstatic constexpr const char* GTIRB_MAGIC_CHARS = \"GTIRB\";\n\nclass IR::ModuleObserverImpl : public ModuleObserver {\npublic:\n  explicit ModuleObserverImpl(IR* I_) : I(I_) {}\n\n  ChangeStatus nameChange(Module* M, const std::string& /*OldName*/,\n                          const std::string& /*NewName*/) override {\n    auto& Index = I->Modules.get<by_pointer>();\n    auto It = Index.find(M);\n    assert(It != Index.end() && \"module observed by non-owner\");\n    // The lambda would ordinarily update the Module such that the result\n    // of Module::getName changes. Because that change happened before this\n    // method was called, the lambda doesn't need to do anything.\n    Index.modify(It, [](Module*) {});\n    return ChangeStatus::Accepted;\n  }\n\n  ChangeStatus addProxyBlocks(Module* /*M*/,\n                              Module::proxy_block_range Blocks) override {\n    ChangeStatus Status = ChangeStatus::NoChange;\n    if (!Blocks.empty()) {\n      for (ProxyBlock& PB : Blocks) {\n        // User could have called addVertex themselves, so check whether we\n        // actually modified the graph.\n        if (addVertex(&PB, I->Cfg).second)\n          Status = ChangeStatus::Accepted;\n      }\n    }\n    return Status;\n  }\n\n  ChangeStatus removeProxyBlocks(Module* /*M*/,\n                                 Module::proxy_block_range Blocks) override {\n    ChangeStatus Status = ChangeStatus::NoChange;\n    if (!Blocks.empty()) {\n      for (ProxyBlock& PB : Blocks) {\n        // User could have called removeVertex themselves, so check whether\n        // we actually modified the graph.\n        if (removeVertex(&PB, I->Cfg))\n          Status = ChangeStatus::Accepted;\n      }\n    }\n    return Status;\n  }\n\n  ChangeStatus addCodeBlocks(Module* /*M*/,\n                             Module::code_block_range Blocks) override {\n    ChangeStatus Status = ChangeStatus::NoChange;\n    if (!Blocks.empty()) {\n      for (CodeBlock& CB : Blocks) {\n        // User could have called addVertex themselves, so check whether we\n        // actually modified the graph.\n        if (addVertex(&CB, I->Cfg).second)\n          Status = ChangeStatus::Accepted;\n      }\n    }\n    return Status;\n  }\n\n  ChangeStatus removeCodeBlocks(Module* /*M*/,\n                                Module::code_block_range Blocks) override {\n    ChangeStatus Status = ChangeStatus::NoChange;\n    if (!Blocks.empty()) {\n      for (CodeBlock& CB : Blocks) {\n        // User could have called removeVertex themselves, so check whether\n        // we actually modified the graph.\n        if (removeVertex(&CB, I->Cfg))\n          Status = ChangeStatus::Accepted;\n      }\n    }\n    return Status;\n  }\n\nprivate:\n  IR* I;\n};\n\nIR::IR(Context& C)\n    : AuxDataContainer(C, Kind::IR),\n      MO(std::make_unique<ModuleObserverImpl>(this)) {}\n\nIR::IR(Context& C, const UUID& U)\n    : AuxDataContainer(C, Kind::IR, U),\n      MO(std::make_unique<ModuleObserverImpl>(this)) {}\n\nclass IRLoadErrorCategory : public std::error_category {\npublic:\n  [[nodiscard]] const char* name() const noexcept override {\n    return \"gt.gtirb.ir\";\n  }\n  [[nodiscard]] std::string message(int Condition) const override {\n    switch (static_cast<IR::load_error>(Condition)) {\n    case IR::load_error::IncorrectVersion:\n      return \"Incompatible protobuf version\";\n    case IR::load_error::CorruptFile:\n      return \"Corrupted GTIRB file\";\n    case IR::load_error::CorruptModule:\n      return \"Corrupted GTIRB module\";\n    case IR::load_error::CorruptSection:\n      return \"Corrupted GTIRB section\";\n    case IR::load_error::CorruptByteInterval:\n      return \"Corrupted byte interval\";\n    case IR::load_error::CorruptCFG:\n      return \"Error in parsing CFG\";\n    case IR::load_error::BadUUID:\n      return \"Bytes not valid UUID\";\n    case IR::load_error::MissingUUID:\n      return \"Could not locate UUID\";\n    case IR::load_error::NotGTIRB:\n      return \"File does not contain GTIRB\";\n    }\n    assert(false && \"Expected to handle all error codes\");\n    return \"\";\n  }\n};\n\nconst std::error_category& gtirb::loadErrorCategory() {\n  static IRLoadErrorCategory Cat;\n  return Cat;\n}\n\nvoid IR::toProtobuf(MessageType* Message) const {\n  nodeUUIDToBytes(this, *Message->mutable_uuid());\n  *Message->mutable_cfg() = gtirb::toProtobuf(this->Cfg);\n  containerToProtobuf(this->Modules, Message->mutable_modules());\n  AuxDataContainer::toProtobuf(Message);\n  Message->set_version(Version);\n}\n\nErrorOr<IR*> IR::fromProtobuf(Context& C, const MessageType& Message) {\n  UUID Id;\n  if (!uuidFromBytes(Message.uuid(), Id))\n    return {load_error::CorruptFile, \"Cannot load IR\"};\n\n  auto* I = IR::Create(C, Id);\n  int i = 0;\n  for (const auto& Elt : Message.modules()) {\n    auto M = Module::fromProtobuf(C, Elt);\n    if (!M) {\n      ErrorInfo Err{load_error::CorruptModule, \"#\" + std::to_string(i)};\n      Err.Msg += \"\\n\" + M.getError().message();\n      return Err;\n    }\n    I->addModule(*M);\n    ++i;\n  }\n  if (!gtirb::fromProtobuf(C, I->Cfg, Message.cfg()))\n    return load_error::CorruptCFG;\n  static_cast<AuxDataContainer*>(I)->fromProtobuf(Message);\n  I->Version = Message.version();\n\n  if (I->Version != GTIRB_PROTOBUF_VERSION) {\n    std::stringstream ss;\n    ss << I->Version << \"; expected version \" << GTIRB_PROTOBUF_VERSION;\n    return {load_error::IncorrectVersion, ss.str()};\n  }\n  return I;\n}\n\nvoid IR::save(std::ostream& Out) const {\n  // Magic signature\n  // Magic signature\n  // Bytes 0-4 contain the ASCII characters: GTIRB.\n  // Bytes 5-6 are considered reserved for future use and should be 0.\n  // Byte 7 contains the GTIRB protobuf spec version in use.\n  Out << GTIRB_MAGIC_CHARS << static_cast<uint8_t>(0) << static_cast<uint8_t>(0)\n      << static_cast<uint8_t>(GTIRB_PROTOBUF_VERSION);\n\n  // Protobuf\n  MessageType Message;\n  this->toProtobuf(&Message);\n  Message.SerializeToOstream(&Out);\n}\n\nErrorOr<IR*> IR::load(Context& C, std::istream& In) {\n  constexpr size_t magic_len =\n      std::string::traits_type::length(GTIRB_MAGIC_CHARS);\n  std::array<char, magic_len> magic;\n  In.read(magic.data(), magic_len);\n  if (memcmp(magic.data(), GTIRB_MAGIC_CHARS, magic_len) != 0) {\n    return {load_error::NotGTIRB, \"GTIRB magic signature not found\"};\n  }\n\n  uint8_t res0;\n  In >> res0;\n\n  uint8_t res1;\n  In >> res1;\n\n  uint8_t protobuf_version;\n  In >> protobuf_version;\n  if (protobuf_version != GTIRB_PROTOBUF_VERSION) {\n    std::stringstream ss;\n    ss << \"GTIRB protobuf version mismatch. Expected: \"\n       << GTIRB_PROTOBUF_VERSION << \" Saw: \" << protobuf_version;\n    return {load_error::IncorrectVersion, ss.str()};\n  }\n\n  google::protobuf::io::IstreamInputStream InputStream(&In);\n  google::protobuf::io::CodedInputStream CodedStream(&InputStream);\n#ifdef PROTOBUF_SET_BYTES_LIMIT\n  CodedStream.SetTotalBytesLimit(INT_MAX, INT_MAX);\n#endif\n\n  MessageType Message;\n  if (!Message.ParseFromCodedStream(&CodedStream)) {\n    return {load_error::CorruptFile, \"Protobuf unable to be parsed\"};\n  }\n\n  return IR::fromProtobuf(C, Message);\n}\n\nvoid IR::saveJSON(std::ostream& Out) const {\n  MessageType Message;\n  this->toProtobuf(&Message);\n  std::string S;\n  auto status = google::protobuf::util::MessageToJsonString(Message, &S);\n  assert(status.ok());\n  Out << S;\n}\n\nErrorOr<IR*> IR::loadJSON(Context& C, std::istream& In) {\n  MessageType Message;\n  std::string S;\n  auto status = google::protobuf::util::JsonStringToMessage(\n      std::string(std::istreambuf_iterator<char>(In), {}), &Message);\n  if (!status.ok()) {\n    return {load_error::CorruptFile, status.ToString()};\n  } else {\n    return IR::fromProtobuf(C, Message);\n  }\n}\n"
  },
  {
    "path": "src/Module.cpp",
    "content": "//===- Module.cpp -----------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2021 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"Module.hpp\"\n#include \"Serialization.hpp\"\n#include <gtirb/CFG.hpp>\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/IR.hpp>\n#include <gtirb/SymbolicExpression.hpp>\n#include <array>\n#include <map>\n\nusing namespace gtirb;\n\nclass Module::SectionObserverImpl : public SectionObserver {\npublic:\n  SectionObserverImpl(Module* M_) : M(M_) {}\n\n  ChangeStatus nameChange(Section* S, const std::string& OldName,\n                          const std::string& NewName) override;\n\n  ChangeStatus addCodeBlocks(Section* S,\n                             Section::code_block_range Blocks) override;\n\n  ChangeStatus moveCodeBlocks(Section* S,\n                              Section::code_block_range Blocks) override;\n\n  ChangeStatus removeCodeBlocks(Section* S,\n                                Section::code_block_range Blocks) override;\n\n  ChangeStatus addDataBlocks(Section* S,\n                             Section::data_block_range Blocks) override;\n\n  ChangeStatus moveDataBlocks(Section* S,\n                              Section::data_block_range Blocks) override;\n\n  ChangeStatus removeDataBlocks(Section* S,\n                                Section::data_block_range Blocks) override;\n\n  ChangeStatus changeExtent(Section* S,\n                            std::function<void(Section*)> Callback) override;\n\nprivate:\n  Module* M;\n};\n\nclass Module::SymbolObserverImpl : public SymbolObserver {\npublic:\n  explicit SymbolObserverImpl(Module* M_) : M(M_) {}\n\n  ChangeStatus nameChange(Symbol* S, const std::string& OldName,\n                          const std::string& NewName) override;\n\n  ChangeStatus referentChange(\n      Symbol* S, std::variant<std::monostate, Addr, Node*> OldReferent,\n      std::variant<std::monostate, Addr, Node*> NewReferent) override;\n\nprivate:\n  Module* M;\n};\n\nModule::Module(Context& C, const std::string& N)\n    : AuxDataContainer(C, Kind::Module), Name(N),\n      SecObs(std::make_unique<SectionObserverImpl>(this)),\n      SymObs(std::make_unique<SymbolObserverImpl>(this)) {}\nModule::Module(Context& C, const std::string& N, const UUID& U)\n    : AuxDataContainer(C, Kind::Module, U), Name(N),\n      SecObs(std::make_unique<SectionObserverImpl>(this)),\n      SymObs(std::make_unique<SymbolObserverImpl>(this)) {}\n\nvoid Module::toProtobuf(MessageType* Message) const {\n  nodeUUIDToBytes(this, *Message->mutable_uuid());\n  Message->set_binary_path(this->BinaryPath);\n  Message->set_preferred_addr(static_cast<uint64_t>(this->PreferredAddr));\n  Message->set_rebase_delta(this->RebaseDelta);\n  Message->set_file_format(static_cast<proto::FileFormat>(this->FileFormat));\n  Message->set_isa(static_cast<proto::ISA>(this->Isa));\n  Message->set_name(this->Name);\n  sequenceToProtobuf(ProxyBlocks.begin(), ProxyBlocks.end(),\n                     Message->mutable_proxies());\n  sequenceToProtobuf(sections_begin(), sections_end(),\n                     Message->mutable_sections());\n  containerToProtobuf(Symbols, Message->mutable_symbols());\n  if (EntryPoint) {\n    nodeUUIDToBytes(EntryPoint, *Message->mutable_entry_point());\n  }\n  Message->set_byte_order(static_cast<proto::ByteOrder>(this->ByteOrder));\n  AuxDataContainer::toProtobuf(Message);\n}\n\n// FIXME: improve containerFromProtobuf so it can handle a pair where one\n// element is a pointer to a Node subclass.\ntemplate <class T, class U, class V, class W>\nstatic void nodeMapFromProtobuf(Context& C, std::map<T, U*>& Values,\n                                const google::protobuf::Map<V, W>& Message) {\n  Values.clear();\n  std::for_each(Message.begin(), Message.end(), [&Values, &C](const auto& M) {\n    std::pair<T, U*> Val;\n    fromProtobuf(C, Val.first, M.first);\n    Val.second = U::fromProtobuf(C, M.second);\n    Values.insert(std::move(Val));\n  });\n}\n\nErrorOr<Module*> Module::fromProtobuf(Context& C, const MessageType& Message) {\n  UUID Id;\n  if (!uuidFromBytes(Message.uuid(), Id))\n    return {IR::load_error::BadUUID, \"Cannot load module\"};\n\n  ErrorInfo Problem{IR::load_error::CorruptModule,\n                    \"Cannot load module \" + Message.name()};\n\n  Module* M = Module::Create(C, Message.name(), Id);\n  M->BinaryPath = Message.binary_path();\n  M->PreferredAddr = Addr(Message.preferred_addr());\n  M->RebaseDelta = Message.rebase_delta();\n  M->FileFormat = static_cast<gtirb::FileFormat>(Message.file_format());\n  M->Isa = static_cast<ISA>(Message.isa());\n  for (const auto& Elt : Message.proxies()) {\n    auto PB = ProxyBlock::fromProtobuf(C, Elt);\n    if (!PB) {\n      Problem.Msg += \"\\n\" + PB.getError().message();\n      return Problem;\n    }\n    M->addProxyBlock(*PB);\n  }\n  for (const auto& Elt : Message.sections()) {\n    auto S = Section::fromProtobuf(C, Elt);\n    if (!S) {\n      Problem.Msg += \"\\n\" + S.getError().message();\n      return Problem;\n    }\n    M->addSection(*S);\n  }\n  for (const auto& Elt : Message.symbols()) {\n    auto S = Symbol::fromProtobuf(C, Elt);\n    if (!S) {\n      Problem.Msg += \"\\n\" + S.getError().message();\n      return Problem;\n    }\n    M->addSymbol(*S);\n  }\n  for (const auto& ProtoS : Message.sections()) {\n    for (const auto& ProtoBI : ProtoS.byte_intervals()) {\n      if (!uuidFromBytes(ProtoBI.uuid(), Id)) {\n        Problem.Msg += \"\\nCould not parse UUID for ByteInterval in section \" +\n                       ProtoS.name();\n        return Problem;\n      }\n      auto* BI = dyn_cast_or_null<ByteInterval>(getByUUID(C, Id));\n      if (!BI) {\n        Problem.Msg += \"\\nCould not find UUID for ByteInterval in section \" +\n                       ProtoS.name();\n        return Problem;\n      }\n      if (!BI->symbolicExpressionsFromProtobuf(C, ProtoBI)) {\n        std::stringstream msg{\n            \"Could not deserialize symbolic expression in ByteInterval\"};\n        if (auto Addr = BI->getAddress())\n          msg << \" @\" << Addr;\n        msg << \"in section \" << ProtoS.name();\n        Problem.Msg += msg.str();\n        return Problem;\n      }\n    }\n  }\n\n  if (!Message.entry_point().empty()) {\n    if (!uuidFromBytes(Message.entry_point(), Id)) {\n      Problem.Msg += \"\\nCould not parse UUID for entry point\";\n      return Problem;\n    }\n    M->EntryPoint = dyn_cast_or_null<CodeBlock>(Node::getByUUID(C, Id));\n    if (!M->EntryPoint) {\n      Problem.Msg += \"\\nCould not find entry point\";\n      return Problem;\n    }\n  }\n  M->ByteOrder = static_cast<gtirb::ByteOrder>(Message.byte_order());\n  static_cast<AuxDataContainer*>(M)->fromProtobuf(Message);\n  return M;\n}\n\nChangeStatus Module::removeProxyBlock(ProxyBlock* B) {\n  if (auto It = ProxyBlocks.find(B); It != ProxyBlocks.end()) {\n    if (Observer) {\n      auto BlockRange = boost::make_iterator_range(It, std::next(It));\n      [[maybe_unused]] ChangeStatus status =\n          Observer->removeProxyBlocks(this, BlockRange);\n      // The known observers do not reject removals. If that changes, this\n      // method must be updated. Because addProxyBlock(ProxyBlock*) also\n      // assumes removals are never rejected, that method should be updated\n      // as well.\n      assert(status != ChangeStatus::Rejected &&\n             \"recovering from rejected removal is unimplemented\");\n    }\n    ProxyBlocks.erase(It);\n    B->setModule(nullptr);\n    return ChangeStatus::Accepted;\n  }\n  return ChangeStatus::NoChange;\n}\n\nChangeStatus Module::addProxyBlock(ProxyBlock* B) {\n  if (Module* M = B->getModule()) {\n    if (M == this)\n      return ChangeStatus::NoChange;\n    [[maybe_unused]] ChangeStatus status = M->removeProxyBlock(B);\n    assert(status != ChangeStatus::Rejected &&\n           \"failed to remove block from former parent\");\n  }\n\n  B->setModule(this);\n  auto [It, Inserted] = ProxyBlocks.insert(B);\n  if (Inserted && Observer) {\n    auto BlockRange = boost::make_iterator_range(It, std::next(It));\n    [[maybe_unused]] ChangeStatus status =\n        Observer->addProxyBlocks(this, BlockRange);\n    // The known observers do not reject insertions. If that changes, this\n    // method must be updated.\n    assert(status != ChangeStatus::Rejected &&\n           \"recovering from rejected insertion is unimplemented\");\n  }\n  return ChangeStatus::Accepted;\n}\n\n// Present for testing purposes only.\nvoid Module::save(std::ostream& Out) const {\n  MessageType Message;\n  this->toProtobuf(&Message);\n  Message.SerializeToOstream(&Out);\n}\n\n// Present for testing purposes only.\nModule* Module::load(Context& C, std::istream& In) {\n  MessageType Message;\n  Message.ParseFromIstream(&In);\n  auto M = Module::fromProtobuf(C, Message);\n  if (M) {\n    return *M;\n  }\n  return nullptr;\n}\n\nChangeStatus Module::removeSection(Section* S) {\n  auto& Index = Sections.get<by_pointer>();\n  if (auto Iter = Index.find(S); Iter != Index.end()) {\n    if (Observer) {\n      auto Begin = Sections.project<by_address>(Iter);\n      auto End = std::next(Begin);\n      auto BlockRange = makeCodeBlockRange(Begin, End);\n      [[maybe_unused]] ChangeStatus Status =\n          Observer->removeCodeBlocks(this, BlockRange);\n      // The known observers do not reject removals. If that changes, this\n      // method must be updated. Because addSection(Section*) also assumes\n      // removals are never rejected, that method should be updated as well.\n      assert(Status != ChangeStatus::Rejected &&\n             \"recovering from rejected removal is unimplemented\");\n    }\n\n    removeSectionAddrs(S);\n    Index.erase(Iter);\n    S->setParent(nullptr, nullptr);\n    return ChangeStatus::Accepted;\n  }\n  return ChangeStatus::NoChange;\n}\n\nChangeStatus Module::addSection(Section* S) {\n  if (Module* M = S->getModule()) {\n    if (M == this)\n      return ChangeStatus::NoChange;\n    [[maybe_unused]] ChangeStatus Status = M->removeSection(S);\n    assert(Status != ChangeStatus::Rejected &&\n           \"failed to remove section from former parent\");\n  }\n\n  S->setParent(this, SecObs.get());\n\n  auto [Iter, Inserted] = Sections.emplace(S);\n  if (Inserted && Observer) {\n    auto BlockRange = makeCodeBlockRange(Iter, std::next(Iter));\n    [[maybe_unused]] ChangeStatus Status =\n        Observer->addCodeBlocks(this, BlockRange);\n    // The known observers do not reject insertions. If that changes, this\n    // method must be updated.\n    assert(Status != ChangeStatus::Rejected &&\n           \"recovering from rejected insertion is unimplemented\");\n  }\n\n  insertSectionAddrs(S);\n  return ChangeStatus::Accepted;\n}\n\nvoid Module::removeSectionAddrs(Section* S) {\n  if (std::optional<AddrRange> OldExtent = addressRange(*S)) {\n    SectionAddrs.subtract(\n        std::make_pair(SectionIntMap::interval_type::right_open(\n                           OldExtent->lower(), OldExtent->upper()),\n                       SectionIntMap::codomain_type({S})));\n  }\n}\n\nvoid Module::insertSectionAddrs(Section* S) {\n  if (std::optional<AddrRange> NewExtent = addressRange(*S)) {\n    SectionAddrs.add(std::make_pair(SectionIntMap::interval_type::right_open(\n                                        NewExtent->lower(), NewExtent->upper()),\n                                    SectionIntMap::codomain_type({S})));\n  }\n}\n\nstatic auto NoOp = [](auto*) {};\n\nChangeStatus\nModule::SectionObserverImpl::nameChange(Section* S,\n                                        const std::string& /*OldName*/,\n                                        const std::string& /*NewName*/) {\n  auto& Index = M->Sections.get<by_pointer>();\n  auto It = Index.find(S);\n  assert(It != Index.end() && \"section observed by non-owner\");\n  // The following lambda is intentionally a no-op. Because the Section's name\n  // has already been updated before this method executes, we only need to tell\n  // the index to re-synchronize.\n  Index.modify(It, NoOp);\n  return ChangeStatus::Accepted;\n}\n\nChangeStatus\nModule::SectionObserverImpl::addCodeBlocks([[maybe_unused]] Section* S,\n                                           Section::code_block_range Blocks) {\n  ChangeStatus Status = ChangeStatus::NoChange;\n  if (M->Observer) {\n    [[maybe_unused]] auto& SectionIndex = M->Sections.get<by_pointer>();\n    assert(SectionIndex.find(S) != SectionIndex.end() &&\n           \"section observed by non-owner\");\n    // code_block_iterator takes a range of ranges, so wrap the given block\n    // range in a one-element array.\n    std::array<decltype(Blocks), 1> Range{Blocks};\n    Status = M->Observer->addCodeBlocks(\n        M, boost::make_iterator_range(code_block_iterator(Range),\n                                      code_block_iterator()));\n    assert(Status != ChangeStatus::Rejected &&\n           \"recovering from rejected insertion is not implemented\");\n  }\n\n  if (moveCodeBlocks(S, Blocks) == ChangeStatus::Accepted)\n    return ChangeStatus::Accepted;\n  return Status;\n}\n\nChangeStatus\nModule::SectionObserverImpl::moveCodeBlocks([[maybe_unused]] Section* S,\n                                            Section::code_block_range Blocks) {\n  ChangeStatus Status = ChangeStatus::NoChange;\n  auto& Index = M->Symbols.get<by_referent>();\n\n  // Remove the affected symbols from M->Symbols and reinsert them. We cannot\n  // simply call modify() because the by_address index may be arbitrarily\n  // corrupt when this method is called. If we try to modify a symbol that\n  // happens to be in the correct position relative to its neighbors, that\n  // symbol will not be updated even if the neighbors are not in their correct\n  // positions.\n\n  std::vector<Symbol*> ModifiedSymbols;\n  for (CodeBlock& Block : Blocks) {\n    for (auto [It, End] = Index.equal_range(&Block); It != End;) {\n      ModifiedSymbols.push_back(*It);\n      It = Index.erase(It);\n      Status = ChangeStatus::Accepted;\n    }\n  }\n  M->Symbols.insert(ModifiedSymbols.begin(), ModifiedSymbols.end());\n\n  return Status;\n}\n\nChangeStatus Module::SectionObserverImpl::removeCodeBlocks(\n    [[maybe_unused]] Section* S, Section::code_block_range Blocks) {\n  ChangeStatus Status = ChangeStatus::NoChange;\n  if (M->Observer) {\n    [[maybe_unused]] auto& SectionIndex = M->Sections.get<by_pointer>();\n    assert(SectionIndex.find(S) != SectionIndex.end() &&\n           \"section observed by non-owner\");\n    // code_block_iterator takes a range of ranges, so wrap the given block\n    // range in a one-element array.\n    std::array<decltype(Blocks), 1> Range{Blocks};\n    Status = M->Observer->removeCodeBlocks(\n        M, boost::make_iterator_range(code_block_iterator(Range),\n                                      code_block_iterator()));\n    assert(Status != ChangeStatus::Rejected &&\n           \"recovering from failed removal is not implemented\");\n  }\n\n  if (moveCodeBlocks(S, Blocks) == ChangeStatus::Accepted)\n    return ChangeStatus::Accepted;\n  return Status;\n}\n\nChangeStatus\nModule::SectionObserverImpl::addDataBlocks(Section* S,\n                                           Section::data_block_range Blocks) {\n  return moveDataBlocks(S, Blocks);\n}\n\nChangeStatus\nModule::SectionObserverImpl::moveDataBlocks(Section* /* S */,\n                                            Section::data_block_range Blocks) {\n  ChangeStatus Status = ChangeStatus::NoChange;\n  auto& Index = M->Symbols.get<by_referent>();\n\n  // Remove the affected symbols from M->Symbols and reinsert them. We cannot\n  // simply call modify() because the by_address index may be arbitrarily\n  // corrupt when this method is called. If we try to modify a symbol that\n  // happens to be in the correct position relative to its neighbors, that\n  // symbol will not be updated even if the neighbors are not in their correct\n  // positions.\n\n  std::vector<Symbol*> ModifiedSymbols;\n  for (DataBlock& Block : Blocks) {\n    for (auto [It, End] = Index.equal_range(&Block); It != End;) {\n      ModifiedSymbols.push_back(*It);\n      It = Index.erase(It);\n      Status = ChangeStatus::Accepted;\n    }\n  }\n  M->Symbols.insert(ModifiedSymbols.begin(), ModifiedSymbols.end());\n\n  return Status;\n}\n\nChangeStatus Module::SectionObserverImpl::removeDataBlocks(\n    Section* S, Section::data_block_range Blocks) {\n  return moveDataBlocks(S, Blocks);\n}\n\nChangeStatus Module::SectionObserverImpl::changeExtent(\n    Section* S, std::function<void(Section*)> Callback) {\n  auto& Index = M->Sections.get<by_pointer>();\n  if (auto It = Index.find(S); It != Index.end()) {\n    M->removeSectionAddrs(S);\n    Index.modify(It, Callback);\n    M->insertSectionAddrs(S);\n  }\n  return ChangeStatus::NoChange;\n}\n\nChangeStatus Module::SymbolObserverImpl::nameChange(Symbol* S,\n                                                    const std::string&,\n                                                    const std::string&) {\n  auto& Index = M->Symbols.get<by_pointer>();\n  auto It = Index.find(S);\n  assert(It != Index.end() && \"symbol observed by non-owner\");\n  // The following lambda is intentionally a no-op. Because the Symbol's name\n  // has already been updated before this method executes, we only need to tell\n  // the index to re-synchronize.\n  Index.modify(It, NoOp);\n  return ChangeStatus::Accepted;\n}\n\nChangeStatus Module::SymbolObserverImpl::referentChange(\n    Symbol* S, std::variant<std::monostate, Addr, Node*>,\n    std::variant<std::monostate, Addr, Node*>) {\n  auto& Index = M->Symbols.get<by_pointer>();\n  auto It = Index.find(S);\n  assert(It != Index.end() && \"symbol observed by non-owner\");\n  // The following lambda is intentionally a no-op. Because the Symbol's\n  // referent or address has already been updated before this method executes,\n  // we only need to tell the index to re-synchronize.\n  Index.modify(It, NoOp);\n  return ChangeStatus::Accepted;\n}\n"
  },
  {
    "path": "src/Node.cpp",
    "content": "//===- Node.cpp -------------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"Node.hpp\"\n#include \"gtirb/Module.hpp\"\n#include <boost/uuid/uuid_generators.hpp>\n\nusing namespace gtirb;\n\n// TODO: accessing this object between threads requires synchronization.\nstatic boost::uuids::random_generator UUIDGenerator;\n\nNode::Node(Context& C, Kind Knd, const UUID& U) : K(Knd), Uuid(U), Ctx(&C) {\n  Ctx->registerNode(Uuid, this);\n}\n\nNode::Node(Context& C, Kind Knd) : Node(C, Knd, UUIDGenerator()) {}\n\nNode::~Node() noexcept { Ctx->unregisterNode(this); }\n"
  },
  {
    "path": "src/Offset.cpp",
    "content": "//===- Offset.cpp -----------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"Serialization.hpp\"\n#include <gtirb/Offset.hpp>\n#include <gtirb/proto/Offset.pb.h>\n\nusing namespace gtirb;\n\nvoid Offset::toProtobuf(MessageType* Message) const {\n  uuidToBytes(this->ElementId, *Message->mutable_element_id());\n  Message->set_displacement(this->Displacement);\n}\n\nbool Offset::fromProtobuf(Context&, const MessageType& Message) {\n  if (!uuidFromBytes(Message.element_id(), this->ElementId))\n    return false;\n  this->Displacement = Message.displacement();\n  return true;\n}\n"
  },
  {
    "path": "src/ProxyBlock.cpp",
    "content": "//===- ProxyBlock.cpp -------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"ProxyBlock.hpp\"\n#include \"IR.hpp\"\n#include \"Serialization.hpp\"\n#include <gtirb/proto/ProxyBlock.pb.h>\n\nusing namespace gtirb;\n\nvoid ProxyBlock::toProtobuf(MessageType* Message) const {\n  nodeUUIDToBytes(this, *Message->mutable_uuid());\n}\n\nErrorOr<ProxyBlock*> ProxyBlock::fromProtobuf(Context& C,\n                                              const MessageType& Message) {\n  UUID Id;\n  if (!uuidFromBytes(Message.uuid(), Id))\n    return {IR::load_error::BadUUID, \"Could not create proxy block\"};\n\n  return Create(C, Id);\n}\n\n// Present for testing purposes only.\nvoid ProxyBlock::save(std::ostream& Out) const {\n  MessageType Message;\n  this->toProtobuf(&Message);\n  Message.SerializeToOstream(&Out);\n}\n\n// Present for testing purposes only.\nProxyBlock* ProxyBlock::load(Context& C, std::istream& In) {\n  MessageType Message;\n  Message.ParseFromIstream(&In);\n  auto CB = ProxyBlock::fromProtobuf(C, Message);\n  if (CB)\n    return *CB;\n  return nullptr;\n}\n"
  },
  {
    "path": "src/Section.cpp",
    "content": "//===- Section.cpp ----------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"Section.hpp\"\n#include \"IR.hpp\"\n#include \"Serialization.hpp\"\n\nusing namespace gtirb;\n\nclass Section::ByteIntervalObserverImpl : public ByteIntervalObserver {\npublic:\n  ByteIntervalObserverImpl(Section* S_) : S(S_) {}\n\n  ChangeStatus addCodeBlocks(ByteInterval* BI,\n                             ByteInterval::code_block_range Blocks) override;\n\n  ChangeStatus moveCodeBlocks(ByteInterval* BI,\n                              ByteInterval::code_block_range Blocks) override;\n\n  ChangeStatus removeCodeBlocks(ByteInterval* BI,\n                                ByteInterval::code_block_range Blocks) override;\n\n  ChangeStatus addDataBlocks(ByteInterval* BI,\n                             ByteInterval::data_block_range Blocks) override;\n\n  ChangeStatus moveDataBlocks(ByteInterval* BI,\n                              ByteInterval::data_block_range Blocks) override;\n\n  ChangeStatus removeDataBlocks(ByteInterval* BI,\n                                ByteInterval::data_block_range Blocks) override;\n\n  ChangeStatus\n  changeExtent(ByteInterval* BI,\n               std::function<void(ByteInterval*)> Callback) override;\n\nprivate:\n  Section* S;\n};\n\nSection::Section(Context& C) : Section(C, std::string{}) {}\n\nSection::Section(Context& C, const std::string& N)\n    : Node(C, Kind::Section), Name(N),\n      BIO(std::make_unique<ByteIntervalObserverImpl>(this)) {}\n\nSection::Section(Context& C, const std::string& N, const UUID& U)\n    : Node(C, Kind::Section, U), Name(N),\n      BIO(std::make_unique<ByteIntervalObserverImpl>(this)) {}\n\nbool Section::operator==(const Section& Other) const {\n  return this->getAddress() == Other.getAddress() &&\n         this->getSize() == Other.getSize() && this->Name == Other.Name;\n}\n\nbool Section::operator!=(const Section& Other) const {\n  return !(*this == Other);\n}\n\nvoid Section::toProtobuf(MessageType* Message) const {\n  nodeUUIDToBytes(this, *Message->mutable_uuid());\n  Message->set_name(this->Name);\n  for (auto Flag : flags()) {\n    Message->add_section_flags(static_cast<proto::SectionFlag>(Flag));\n  }\n  for (const auto& Interval : byte_intervals()) {\n    Interval.toProtobuf(Message->add_byte_intervals());\n  }\n}\n\nErrorOr<Section*> Section::fromProtobuf(Context& C,\n                                        const MessageType& Message) {\n  UUID Id;\n  if (!uuidFromBytes(Message.uuid(), Id))\n    return {IR::load_error::BadUUID, \"Could not load section\"};\n\n  auto* S = Section::Create(C, Message.name(), Id);\n  for (int I = 0, E = Message.section_flags_size(); I != E; ++I) {\n    S->addFlag(static_cast<SectionFlag>(Message.section_flags(I)));\n  }\n  for (const auto& ProtoInterval : Message.byte_intervals()) {\n    auto BI = ByteInterval::fromProtobuf(C, ProtoInterval);\n    if (!BI) {\n      ErrorInfo err{IR::load_error::CorruptSection,\n                    \"Could not load section\" + Message.name() + \"\\n\" +\n                        BI.getError().message()};\n      return err;\n    }\n    S->addByteInterval(*BI);\n  }\n  return S;\n}\n\n// Present for testing purposes only.\nvoid Section::save(std::ostream& Out) const {\n  MessageType Message;\n  this->toProtobuf(&Message);\n  Message.SerializeToOstream(&Out);\n}\n\n// Present for testing purposes only.\nSection* Section::load(Context& C, std::istream& In) {\n  MessageType Message;\n  Message.ParseFromIstream(&In);\n  auto S = Section::fromProtobuf(C, Message);\n  if (S)\n    return *S;\n  return nullptr;\n}\n\nChangeStatus Section::removeByteInterval(ByteInterval* BI) {\n  auto& Index = ByteIntervals.get<by_pointer>();\n  if (auto Iter = Index.find(BI); Iter != Index.end()) {\n    if (Observer) {\n      auto Begin = ByteIntervals.project<by_address>(Iter);\n      auto End = std::next(Begin);\n      [[maybe_unused]] ChangeStatus Status =\n          Observer->removeCodeBlocks(this, makeCodeBlockRange(Begin, End));\n      // None of the known observers reject removals. If that changes, this\n      // implementation will need to be changed as well. Because\n      // addByteInterval assumes that removal will not be rejected, it will\n      // need to be updated.\n      assert(Status != ChangeStatus::Rejected &&\n             \"recovering from rejected removal is not implemented yet\");\n    }\n\n    removeByteIntervalAddrs(BI);\n    Index.erase(Iter);\n    BI->setParent(nullptr, nullptr);\n    [[maybe_unused]] ChangeStatus Status = updateExtent();\n    assert(Status != ChangeStatus::Rejected &&\n           \"failed to change Section extent after removing ByteInterval\");\n    return ChangeStatus::Accepted;\n  }\n  return ChangeStatus::NoChange;\n}\n\nChangeStatus Section::addByteInterval(ByteInterval* BI) {\n  if (Section* S = BI->getSection()) {\n    if (S == this) {\n      return ChangeStatus::NoChange;\n    }\n    [[maybe_unused]] ChangeStatus Status = S->removeByteInterval(BI);\n    assert(Status != ChangeStatus::Rejected &&\n           \"failed to remove node from parent\");\n  }\n\n  BI->setParent(this, BIO.get());\n  auto P = ByteIntervals.emplace(BI);\n  if (P.second && Observer) {\n    auto Blocks = makeCodeBlockRange(P.first, std::next(P.first));\n    [[maybe_unused]] ChangeStatus Status =\n        Observer->addCodeBlocks(this, Blocks);\n    // None of the known observers reject insertions. If that changes, this\n    // implementation must be updated.\n    assert(Status != ChangeStatus::Rejected &&\n           \"recovering from rejected insertion is unimplemented\");\n  }\n\n  insertByteIntervalAddrs(BI);\n  [[maybe_unused]] ChangeStatus Status = updateExtent();\n  assert(Status != ChangeStatus::Rejected &&\n         \"failed to change Section extent after adding ByteInterval\");\n  return ChangeStatus::Accepted;\n}\n\nvoid Section::removeByteIntervalAddrs(ByteInterval* BI) {\n  if (std::optional<AddrRange> OldExtent = addressRange(*BI)) {\n    ByteIntervalAddrs.subtract(\n        std::make_pair(ByteIntervalIntMap::interval_type::right_open(\n                           OldExtent->lower(), OldExtent->upper()),\n                       ByteIntervalIntMap::codomain_type({BI})));\n  }\n}\n\nvoid Section::insertByteIntervalAddrs(ByteInterval* BI) {\n  if (std::optional<AddrRange> NewExtent = addressRange(*BI)) {\n    ByteIntervalAddrs.add(\n        std::make_pair(ByteIntervalIntMap::interval_type::right_open(\n                           NewExtent->lower(), NewExtent->upper()),\n                       ByteIntervalIntMap::codomain_type({BI})));\n  }\n}\n\nChangeStatus Section::updateExtent() {\n  std::optional<AddrRange> NewExtent;\n  if (!ByteIntervals.empty()) {\n    // Any ByteIntervals without an address will be at the front of the map\n    // because nullopt sorts lower than any address.\n    if (std::optional<Addr> Lower = (*ByteIntervals.begin())->getAddress()) {\n      // All the ByteIntervals have an address, so we can calculate the\n      // Section's extent. Get the address of the last ByteInterval in case it\n      // has zero size; ByteIntervalAddrs does not track empty ByteIntervals.\n      Addr Upper = *(*ByteIntervals.rbegin())->getAddress();\n      if (!ByteIntervalAddrs.empty()) {\n        // The last address is the max of the first address in the last\n        // interval and the last address in intervals with non-zero size.\n        Upper = std::max(Upper, ByteIntervalAddrs.rbegin()->first.upper());\n      }\n      NewExtent = AddrRange{*Lower, static_cast<uint64_t>(Upper - *Lower)};\n    }\n  }\n\n  if (NewExtent != Extent) {\n    if (Observer) {\n      [[maybe_unused]] ChangeStatus Status = Observer->changeExtent(\n          this, [&NewExtent](Section* S) { S->Extent = NewExtent; });\n      assert(Status != ChangeStatus::Rejected &&\n             \"recovering from rejected extent changes is unimplemented\");\n    } else {\n      Extent = NewExtent;\n    }\n    return ChangeStatus::Accepted;\n  }\n  return ChangeStatus::NoChange;\n}\n\nChangeStatus Section::ByteIntervalObserverImpl::addCodeBlocks(\n    [[maybe_unused]] ByteInterval* BI, ByteInterval::code_block_range Blocks) {\n  if (S->Observer) {\n    [[maybe_unused]] auto& Index = S->ByteIntervals.get<by_pointer>();\n    assert(Index.find(BI) != Index.end() &&\n           \"byte interval observed by non-owner\");\n    // code_block_iterator takes a range of ranges, so wrap the given block\n    // range in a one-element array.\n    std::array<decltype(Blocks), 1> Range{Blocks};\n    return S->Observer->addCodeBlocks(\n        S, boost::make_iterator_range(code_block_iterator(Range),\n                                      code_block_iterator()));\n  }\n  return ChangeStatus::NoChange;\n}\n\nChangeStatus Section::ByteIntervalObserverImpl::moveCodeBlocks(\n    [[maybe_unused]] ByteInterval* BI, ByteInterval::code_block_range Blocks) {\n  if (S->Observer) {\n    [[maybe_unused]] auto& Index = S->ByteIntervals.get<by_pointer>();\n    assert(Index.find(BI) != Index.end() &&\n           \"byte interval observed by non-owner\");\n    // code_block_iterator takes a range of ranges, so wrap the given block\n    // range in a one-element array.\n    std::array<decltype(Blocks), 1> Range{Blocks};\n    return S->Observer->moveCodeBlocks(\n        S, boost::make_iterator_range(code_block_iterator(Range),\n                                      code_block_iterator()));\n  }\n  return ChangeStatus::NoChange;\n}\n\nChangeStatus Section::ByteIntervalObserverImpl::removeCodeBlocks(\n    [[maybe_unused]] ByteInterval* BI, ByteInterval::code_block_range Blocks) {\n  if (S->Observer) {\n    [[maybe_unused]] auto& Index = S->ByteIntervals.get<by_pointer>();\n    assert(Index.find(BI) != Index.end() &&\n           \"byte interval observed by non-owner\");\n    // code_block_iterator takes a range of ranges, so wrap the given block\n    // range in a one-element array.\n    std::array<decltype(Blocks), 1> Range{Blocks};\n    return S->Observer->removeCodeBlocks(\n        S, boost::make_iterator_range(code_block_iterator(Range),\n                                      code_block_iterator()));\n  }\n  return ChangeStatus::NoChange;\n}\n\nChangeStatus Section::ByteIntervalObserverImpl::addDataBlocks(\n    [[maybe_unused]] ByteInterval* BI, ByteInterval::data_block_range Blocks) {\n  if (S->Observer) {\n    [[maybe_unused]] auto& Index = S->ByteIntervals.get<by_pointer>();\n    assert(Index.find(BI) != Index.end() &&\n           \"byte interval observed by non-owner\");\n    // data_block_iterator takes a range of ranges, so wrap the given block\n    // range in a one-element array.\n    std::array<decltype(Blocks), 1> Range{Blocks};\n    return S->Observer->addDataBlocks(\n        S, boost::make_iterator_range(data_block_iterator(Range),\n                                      data_block_iterator()));\n  }\n  return ChangeStatus::NoChange;\n}\n\nChangeStatus Section::ByteIntervalObserverImpl::moveDataBlocks(\n    [[maybe_unused]] ByteInterval* BI, ByteInterval::data_block_range Blocks) {\n  if (S->Observer) {\n    [[maybe_unused]] auto& Index = S->ByteIntervals.get<by_pointer>();\n    assert(Index.find(BI) != Index.end() &&\n           \"byte interval observed by non-owner\");\n    // data_block_iterator takes a range of ranges, so wrap the given block\n    // range in a one-element array.\n    std::array<decltype(Blocks), 1> Range{Blocks};\n    return S->Observer->moveDataBlocks(\n        S, boost::make_iterator_range(data_block_iterator(Range),\n                                      data_block_iterator()));\n  }\n  return ChangeStatus::NoChange;\n}\n\nChangeStatus Section::ByteIntervalObserverImpl::removeDataBlocks(\n    [[maybe_unused]] ByteInterval* BI, ByteInterval::data_block_range Blocks) {\n  if (S->Observer) {\n    [[maybe_unused]] auto& Index = S->ByteIntervals.get<by_pointer>();\n    assert(Index.find(BI) != Index.end() &&\n           \"byte interval observed by non-owner\");\n    // data_block_iterator takes a range of ranges, so wrap the given block\n    // range in a one-element array.\n    std::array<decltype(Blocks), 1> Range{Blocks};\n    return S->Observer->removeDataBlocks(\n        S, boost::make_iterator_range(data_block_iterator(Range),\n                                      data_block_iterator()));\n  }\n  return ChangeStatus::NoChange;\n}\n\nChangeStatus Section::ByteIntervalObserverImpl::changeExtent(\n    ByteInterval* BI, std::function<void(ByteInterval*)> Callback) {\n  auto& Index = S->ByteIntervals.get<by_pointer>();\n  if (auto It = Index.find(BI); It != Index.end()) {\n    S->removeByteIntervalAddrs(BI);\n    Index.modify(It, Callback);\n    S->insertByteIntervalAddrs(BI);\n  }\n\n  return S->updateExtent();\n}\n"
  },
  {
    "path": "src/Serialization.cpp",
    "content": "//===- Serialization.cpp ----------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"Serialization.hpp\"\n#include <gtirb/Node.hpp>\n\nnamespace gtirb {\nbool uuidFromBytes(const std::string& Bytes, UUID& Uuid) {\n  if (Bytes.size() == sizeof(Uuid)) {\n    std::copy(Bytes.begin(), Bytes.end(), std::begin(Uuid));\n    return true;\n  }\n  return false;\n}\n\nvoid uuidToBytes(UUID Uuid, std::string& Bytes) {\n  Bytes.clear();\n  Bytes.reserve(sizeof(Uuid));\n  std::copy(std::begin(Uuid), std::end(Uuid), std::back_inserter(Bytes));\n}\n\nvoid nodeUUIDToBytes(const Node* Node, std::string& Bytes) {\n  uuidToBytes(Node->getUUID(), Bytes);\n}\n\nuint64_t toProtobuf(const Addr Val) { return static_cast<uint64_t>(Val); }\n\nstd::string toProtobuf(const std::string& Val) { return Val; }\n\nint64_t toProtobuf(const int64_t& Val) { return Val; }\n\nuint64_t toProtobuf(const uint64_t& Val) { return Val; }\n\nstd::string toProtobuf(const UUID& Val) {\n  std::string Result;\n  uuidToBytes(Val, Result);\n  return Result;\n}\n\nbool fromProtobuf(Context&, Addr& Result, const uint64_t& Message) {\n  Result = Addr(Message);\n  return true;\n}\n\nbool fromProtobuf(Context&, UUID& Result, const std::string& Message) {\n  return uuidFromBytes(Message, Result);\n}\n\n} // namespace gtirb\n"
  },
  {
    "path": "src/Serialization.hpp",
    "content": "//===- Serialization.hpp ----------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#ifndef GTIRB_SERIALIZATION_H\n#define GTIRB_SERIALIZATION_H\n\n#include <gtirb/Addr.hpp>\n#include <gtirb/Node.hpp>\n#include <gtirb/Offset.hpp>\n#include <google/protobuf/map.h>\n#include <google/protobuf/repeated_field.h>\n#include <type_traits>\n\n// Utilities for serialization\n\nnamespace gtirb {\n/// \\brief Create UUID from string containing raw bytes.\n///\n/// \\param Bytes  A string containing the raw bytes of the UUID.\n/// \\param Uuid   A reference to the resulting UUID.\n///\n/// \\return true if the bytes can be decoded into a UUID, false otherwise.\nbool uuidFromBytes(const std::string& Bytes, UUID& Uuid);\n\n/// \\brief Copy raw bytes of UUID into a string.\n///\n/// \\param Uuid   The UUID to store.\n/// \\param Bytes  The string in which to store the UUID bytes.\n///\n/// \\return void\nvoid uuidToBytes(UUID Uuid, std::string& Bytes);\n\n/// \\brief Copy raw bytes of Node's UUID into a string.\n///\n/// \\param Node   Store this Node's UUID.\n/// \\param Bytes  The string in which to store the UUID bytes.\n///\n/// \\return void\nvoid nodeUUIDToBytes(const Node* Node, std::string& Bytes);\n\n// Generic protobuf conversion for IR classes which implement toProtobuf.\ntemplate <typename T> typename T::MessageType toProtobuf(const T& Val) {\n  typename T::MessageType Message;\n  Val.toProtobuf(&Message);\n  return Message;\n}\n\n// Serialize Addr to uint64_t\nuint64_t toProtobuf(const Addr Val);\n\n// Overloads for various standard types\nstd::string toProtobuf(const std::string& Val);\nint64_t toProtobuf(const int64_t& Val);\nuint64_t toProtobuf(const uint64_t& Val);\nstd::string toProtobuf(const UUID& Val);\n\ntemplate <typename T> T& deref_if_ptr(T& V) { return V; }\ntemplate <typename T> const T& deref_if_ptr(const T& V) { return V; }\ntemplate <typename T> T& deref_if_ptr(T* V) { return *V; }\ntemplate <typename T> const T& deref_if_ptr(const T* V) { return *V; }\ntemplate <typename T> const T& deref_if_ptr(const std::unique_ptr<T>& V) {\n  return *V;\n}\n\ntemplate <typename T, typename U>\nauto toProtobuf(const std::pair<T, U>& Val) -> google::protobuf::MapPair<\n    decltype(toProtobuf(Val.first)),\n    decltype(toProtobuf(deref_if_ptr(Val.second)))> {\n  return {toProtobuf(Val.first), toProtobuf(deref_if_ptr(Val.second))};\n}\n\n// Generic interface for setting up a container. Clear and reserve space\n// if the container supports it.\ntemplate <typename T>\nvoid initContainer(google::protobuf::RepeatedField<T>* Container, size_t Size) {\n  Container->Clear();\n  Container->Reserve(static_cast<int>(Size));\n}\ntemplate <typename T>\nvoid initContainer(google::protobuf::RepeatedPtrField<T>* Container,\n                   size_t Size) {\n  Container->Clear();\n  Container->Reserve(static_cast<int>(Size));\n}\ntemplate <typename T>\nvoid initContainer(std::vector<T>& Container, size_t Size) {\n  Container.clear();\n  Container.reserve(Size);\n}\ntemplate <typename T> void initContainer(T* Container, size_t) {\n  Container->clear();\n}\ntemplate <typename T> void initContainer(T& Container, size_t) {\n  Container.clear();\n}\n\n// Generic interface for adding elements to a container.\ntemplate <typename T>\nvoid addElement(google::protobuf::RepeatedField<T>* Container, T&& Element) {\n  Container->Add(std::move(Element));\n}\ntemplate <typename T>\nvoid addElement(google::protobuf::RepeatedPtrField<T>* Container, T&& Element) {\n  *Container->Add() = std::move(Element);\n}\ntemplate <typename T, typename U>\nvoid addElement(google::protobuf::Map<T, U>* Container,\n                typename google::protobuf::Map<T, U>::value_type&& Element) {\n  Container->insert(std::move(Element));\n}\ntemplate <typename T> void addElement(std::vector<T>& Container, T&& Element) {\n  Container.push_back(std::move(Element));\n}\ntemplate <typename T, typename U>\nvoid addElement(std::map<T, U>* Container,\n                typename std::map<T, U>::value_type&& Element) {\n  Container->insert(std::move(Element));\n}\ntemplate <typename T, typename ContainerType>\nstd::enable_if_t<std::is_destructible_v<\n    decltype(std::declval<ContainerType>().insert(std::declval<T>()))*>>\naddElement(ContainerType& Container, T&& Element) {\n  Container.insert(std::move(Element));\n}\n\n// Convert the contents of a Container into protobuf messages.\ntemplate <typename ContainerT, typename MessageT>\nvoid containerToProtobuf(const ContainerT& Values, MessageT* Message) {\n  initContainer(Message, Values.size());\n  std::for_each(Values.begin(), Values.end(), [Message](const auto& N) {\n    addElement(Message, toProtobuf(deref_if_ptr(N)));\n  });\n}\n\ntemplate <typename IterT, typename MessageT>\nvoid sequenceToProtobuf(IterT First, IterT Last, MessageT* Message) {\n  while (First != Last)\n    addElement(Message, toProtobuf(deref_if_ptr(*First++)));\n}\n\n// Generic conversion from protobuf for IR classes which implement fromProtobuf;\ntemplate <typename T, typename U>\nT* fromProtobuf(Context& C, const U& Message) {\n  return T::fromProtobuf(C, Message);\n}\n\n// Generic template for simple types which require no conversion.\ntemplate <typename T> bool fromProtobuf(Context&, T& Result, const T& Message) {\n  Result = Message;\n  return true;\n}\n\ninline bool fromProtobuf(Context& C, Offset& Result,\n                         const Offset::MessageType& Message) {\n  return Result.fromProtobuf(C, Message);\n}\n\n/// @cond INTERNAL\nnamespace details {\ntemplate <typename T> struct remove_pointer_ref_quals {\n  using type =\n      std::remove_pointer_t<std::remove_reference_t<std::remove_cv_t<T>>>;\n};\ntemplate <typename T>\nusing remove_pointer_ref_quals_t = typename remove_pointer_ref_quals<T>::type;\n} // namespace details\n/// @endcond\n\n// Overrides for various other types.\ntemplate <typename T, typename U, typename V, typename W>\nbool fromProtobuf(Context& C, std::pair<T, U>& Val,\n                  const google::protobuf::MapPair<V, W>& Message) {\n  return fromProtobuf(C, Val.first, Message.first) &&\n         fromProtobuf(C, Val.second, Message.second);\n}\n\nbool fromProtobuf(Context&, Addr& Result, const uint64_t& Message);\nbool fromProtobuf(Context&, UUID& Result, const std::string& Message);\n\n// Convert the contents for a Container into IR classes; does not participate\n// in overload resolution if the container stores Node subclasses.\ntemplate <typename ContainerT, typename MessageT>\nbool containerFromProtobuf(\n    Context& C, ContainerT& Values, MessageT& Message,\n    std::enable_if_t<\n        !std::is_base_of_v<Node, details::remove_pointer_ref_quals_t<\n                                     typename ContainerT::value_type>>>* =\n        nullptr) {\n  initContainer(Values, Message.size());\n  std::for_each(Message.begin(), Message.end(), [&Values, &C](const auto& M) {\n    typename ContainerT::value_type Val;\n    if (!fromProtobuf(C, Val, M))\n      return false;\n    addElement(Values, std::move(Val));\n  });\n  return true;\n}\n\n// Convert the contents for a Container into IR classes. Only participates in\n// overload resolution if the container stores Node subclasses.\ntemplate <typename ContainerT, typename MessageT>\nbool containerFromProtobuf(\n    Context& C, ContainerT& Values, MessageT& Message,\n    std::enable_if_t<\n        std::is_base_of_v<Node, details::remove_pointer_ref_quals_t<\n                                    typename ContainerT::value_type>>>* =\n        nullptr) {\n  using BaseType =\n      details::remove_pointer_ref_quals_t<typename ContainerT::value_type>;\n  initContainer(Values, Message.size());\n  std::for_each(Message.begin(), Message.end(), [&Values, &C](const auto& M) {\n    BaseType* Elem = BaseType::fromProtobuf(C, M);\n    if (!Elem)\n      return false;\n    addElement(Values, Elem);\n  });\n  return true;\n}\n\n// Special case for std::map\ntemplate <typename KeyType, typename ValueType, typename MessageT>\nbool containerFromProtobuf(Context& C, std::map<KeyType, ValueType>& Values,\n                           MessageT& Message) {\n  Values.clear();\n  std::for_each(Message.begin(), Message.end(), [&Values, &C](const auto& M) {\n    // NOTE: if we could use MapT::value_type here, then this could\n    // all be rolled into containerFromProtobuf. But that gives us a\n    // pair where the first Element is const, so we can't pass it to\n    // fromProtobuf().\n    std::pair<KeyType, ValueType> Val;\n    if (!fromProtobuf(C, Val, M))\n      return false;\n    Values.insert(std::move(Val));\n  });\n  return true;\n}\n} // namespace gtirb\n\n#endif // GTIRB_SERIALIZATION_H\n"
  },
  {
    "path": "src/Symbol.cpp",
    "content": "//===- Symbol.cpp -----------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"Symbol.hpp\"\n#include \"IR.hpp\"\n#include \"Serialization.hpp\"\n#include <gtirb/ByteInterval.hpp>\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/DataBlock.hpp>\n#include <gtirb/proto/Symbol.pb.h>\n\nusing namespace gtirb;\n\nclass StorePayload {\npublic:\n  StorePayload(proto::Symbol* Message) : M(Message) {}\n  void operator()(std::monostate) const { M->clear_value(); }\n  void operator()(Addr X) const { M->set_value(static_cast<uint64_t>(X)); }\n  void operator()(const Node* Referent) const {\n    nodeUUIDToBytes(Referent, *M->mutable_referent_uuid());\n  }\n\nprivate:\n  proto::Symbol* M;\n};\n\nstd::optional<Addr> Symbol::getAddress() const {\n  return std::visit(\n      [this](const auto& Arg) -> std::optional<Addr> {\n        using T = std::decay_t<decltype(Arg)>;\n        if constexpr (std::is_same_v<T, std::monostate>) {\n          return std::nullopt;\n        } else if constexpr (std::is_same_v<T, Addr>) {\n          return Arg;\n        } else if constexpr (std::is_same_v<T, Node*>) {\n          if (auto* B = dyn_cast_or_null<CodeBlock>(Arg)) {\n            if (auto A = B->getAddress()) {\n              return *A + (AtEnd ? B->getSize() : 0);\n            } else {\n              return std::nullopt;\n            }\n          } else if (auto* D = dyn_cast_or_null<DataBlock>(Arg)) {\n            if (auto A = D->getAddress()) {\n              return *A + (AtEnd ? D->getSize() : 0);\n            } else {\n              return std::nullopt;\n            }\n          } else if (auto* P = dyn_cast_or_null<ProxyBlock>(Arg)) {\n            return std::nullopt;\n          } else {\n            assert(Arg == nullptr && \"unsupported referent type\");\n          }\n          return std::nullopt;\n        } else {\n          static_assert(\n              // Assert condition must depend on T, but will always be false.\n              std::bool_constant<!std::is_same_v<T, T>>::value,\n              \"unsupported symbol payload type\");\n        }\n      },\n      Payload);\n}\n\nvoid Symbol::toProtobuf(MessageType* Message) const {\n  nodeUUIDToBytes(this, *Message->mutable_uuid());\n  std::visit(StorePayload(Message), Payload);\n  Message->set_name(this->Name);\n  Message->set_at_end(this->AtEnd);\n}\n\nErrorOr<Symbol*> Symbol::fromProtobuf(Context& C, const MessageType& Message) {\n  UUID Id;\n  if (!uuidFromBytes(Message.uuid(), Id))\n    return {IR::load_error::BadUUID, \"could not load Symbol\"};\n\n  Symbol* S = Symbol::Create(C, Message.name(), Message.at_end(), Id);\n\n  switch (Message.optional_payload_case()) {\n  case proto::Symbol::kValue: {\n    S->Payload = Addr{Message.value()};\n  } break;\n  case proto::Symbol::kReferentUuid: {\n    if (uuidFromBytes(Message.referent_uuid(), Id)) {\n      if (auto* N = Node::getByUUID(C, Id)) {\n        S->Payload = N;\n      } else {\n        S->Payload = std::monostate{};\n      }\n    } else {\n      return nullptr;\n    }\n  } break;\n  default:\n      /* nothing to do */;\n  }\n  return S;\n}\n\n// Present for testing purposes only.\nvoid Symbol::save(std::ostream& Out) const {\n  MessageType Message;\n  this->toProtobuf(&Message);\n  Message.SerializeToOstream(&Out);\n}\n\n// Present for testing purposes only.\nSymbol* Symbol::load(Context& C, std::istream& In) {\n  MessageType Message;\n  Message.ParseFromIstream(&In);\n  auto S = Symbol::fromProtobuf(C, Message);\n  if (S)\n    return *S;\n  return nullptr;\n}\n"
  },
  {
    "path": "src/SymbolicExpression.cpp",
    "content": "//===- SymbolicExpression.cpp -----------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"SymbolicExpression.hpp\"\n#include \"Serialization.hpp\"\n#include <gtirb/Context.hpp>\n#include <gtirb/Symbol.hpp>\n#include <gtirb/proto/SymbolicExpression.pb.h>\n#include <variant>\n\nnamespace gtirb {\n\nstatic void symAttributeSetToProtobuf(const SymAttributeSet& SASet,\n                                      proto::SymbolicExpression* Message) {\n  for (auto Attr : SASet) {\n    Message->add_attribute_flags(static_cast<proto::SymAttribute>(Attr));\n  }\n}\n\nstatic SymAttributeSet\nsymAttributeSetFromProtobuf(const proto::SymbolicExpression& Message) {\n  SymAttributeSet SASet;\n  for (int I = 0, E = Message.attribute_flags_size(); I != E; ++I) {\n    SASet.insert(static_cast<SymAttribute>(Message.attribute_flags(I)));\n  }\n  return SASet;\n}\n\nclass SymbolicVisitor {\npublic:\n  proto::SymbolicExpression* Message;\n\n  SymbolicVisitor(proto::SymbolicExpression* M) : Message(M) {}\n\n  void operator()(const SymAddrConst& Val) const {\n    auto M = Message->mutable_addr_const();\n    M->set_offset(Val.Offset);\n    if (Val.Sym) {\n      uuidToBytes(Val.Sym->getUUID(), *M->mutable_symbol_uuid());\n    }\n    symAttributeSetToProtobuf(Val.Attributes, Message);\n  }\n\n  void operator()(const SymAddrAddr& Val) const {\n    auto M = Message->mutable_addr_addr();\n    M->set_scale(Val.Scale);\n    M->set_offset(Val.Offset);\n    if (Val.Sym1) {\n      uuidToBytes(Val.Sym1->getUUID(), *M->mutable_symbol1_uuid());\n    }\n    if (Val.Sym2) {\n      uuidToBytes(Val.Sym2->getUUID(), *M->mutable_symbol2_uuid());\n    }\n    symAttributeSetToProtobuf(Val.Attributes, Message);\n  }\n};\n\nproto::SymbolicExpression toProtobuf(const SymbolicExpression& Value) {\n  proto::SymbolicExpression Message;\n  std::visit(SymbolicVisitor(&Message), Value);\n  return Message;\n}\n\nnamespace {\nSymbol* symbolFromProto(Context& C, const std::string& Bytes) {\n  if (UUID Id; !Bytes.empty() && uuidFromBytes(Bytes, Id))\n    return dyn_cast_or_null<Symbol>(Node::getByUUID(C, Id));\n  return nullptr;\n}\n} // namespace\n\nbool fromProtobuf(Context& C, SymbolicExpression& Result,\n                  const proto::SymbolicExpression& Message) {\n  switch (Message.value_case()) {\n  case proto::SymbolicExpression::kAddrConst: {\n    const auto& Val = Message.addr_const();\n    Result = SymAddrConst{Val.offset(), symbolFromProto(C, Val.symbol_uuid()),\n                          symAttributeSetFromProtobuf(Message)};\n    return std::get<SymAddrConst>(Result).Sym != nullptr;\n  }\n  case proto::SymbolicExpression::kAddrAddr: {\n    const auto& Val = Message.addr_addr();\n    Result = SymAddrAddr{Val.scale(), Val.offset(),\n                         symbolFromProto(C, Val.symbol1_uuid()),\n                         symbolFromProto(C, Val.symbol2_uuid()),\n                         symAttributeSetFromProtobuf(Message)};\n    return std::get<SymAddrAddr>(Result).Sym1 != nullptr &&\n           std::get<SymAddrAddr>(Result).Sym2 != nullptr;\n  }\n  case proto::SymbolicExpression::VALUE_NOT_SET:\n    assert(false && \"unknown symbolic expression kind\");\n  }\n  return false;\n}\n\n// This function is defined here w/ GTIRB_EXPORT_API to provide a\n// means for test code to directly invoke serialization routines on a\n// CFG. This is a capability not supported for GTIRB clients, but must\n// be made available to the testing system.\nvoid GTIRB_EXPORT_API symbolicExpressionSave(const SymbolicExpression& SE,\n                                             std::ostream& Out) {\n  proto::SymbolicExpression Message = toProtobuf(SE);\n  Message.SerializeToOstream(&Out);\n}\n\n// This function is defined here w/ GTIRB_EXPORT_API to provide a\n// means for test code to directly invoke serialization routines on a\n// CFG. This is a capability not supported for GTIRB clients, but must\n// be made available to the testing system.\nvoid GTIRB_EXPORT_API symbolicExpressionLoad(Context& C,\n                                             SymbolicExpression& Result,\n                                             std::istream& In) {\n  proto::SymbolicExpression Message;\n  Message.ParseFromIstream(&In);\n  fromProtobuf(C, Result, Message);\n}\n\n} // namespace gtirb\n"
  },
  {
    "path": "src/SymbolicExpressionSerialization.hpp",
    "content": "//===- SymbolicExpressionSerialization.hpp ----------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n\n#ifndef GTIRB_SYMBOLIC_EXPRESSION_SERIALIZATION_HPP\n#define GTIRB_SYMBOLIC_EXPRESSION_SERIALIZATION_HPP\n\n#include <gtirb/SymbolicExpression.hpp>\n\nnamespace gtirb {\nnamespace proto {\nclass SymbolicExpression;\n}\nclass Context;\n\n/// @cond INTERNAL\n/// \\brief Initialize a SymbolicExpression from a protobuf message.\n///\n/// \\param      C        The Context in which the deserialized\n///                      SymbolicExpression will be held.\n/// \\param      Message  The protobuf message from which to deserialize.\n/// \\param[out] Result   The SymbolicExpression to initialize.\n///\n/// \\return true if the expression could be deserialized from protobuf, false\n/// otherwise.\nbool fromProtobuf(Context& C, SymbolicExpression& Result,\n                  const proto::SymbolicExpression& Message);\n\n/// \\brief Serialize a SymbolicExpression into a protobuf message.\n///\n/// \\param Value   The SymbolicExpression to serialize.\n///\n/// \\return A protobuf message representing the SymbolicExpression.\nproto::SymbolicExpression toProtobuf(const SymbolicExpression& Value);\n\n/// @endcond\n\n} // namespace gtirb\n\n#endif // GTIRB_SYMBOLIC_EXPRESSION_SERIALIZATION_HPP\n"
  },
  {
    "path": "src/Utility.cpp",
    "content": "#include \"Utility.hpp\"\n\n#include <gtirb/Casting.hpp>\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/DataBlock.hpp>\n\nusing namespace gtirb;\n\nstatic inline auto codeBlockSecondaryKey(const CodeBlock* B) {\n  return std::make_tuple(B->getSize(), B->getKind(), B->getDecodeMode(),\n                         B->getUUID());\n}\n\nstatic inline auto dataBlockSecondaryKey(const DataBlock* B) {\n  // Include a dummy \"decode mode\" to match the key type for CodeBlocks for\n  // blockKey().\n  return std::make_tuple(B->getSize(), B->getKind(), DecodeMode::Default,\n                         B->getUUID());\n}\n\ninline auto blockSecondaryKey(const Node* N) {\n  if (const auto* CB = dyn_cast<CodeBlock>(N)) {\n    return codeBlockSecondaryKey(CB);\n  } else {\n    auto* DB = cast<DataBlock>(N);\n    return dataBlockSecondaryKey(DB);\n  }\n}\n\nstatic inline auto codeBlockAddressKey(const CodeBlock* B) {\n  return std::make_tuple(B->getAddress(), codeBlockSecondaryKey(B));\n}\n\nstatic inline auto dataBlockAddressKey(const DataBlock* B) {\n  return std::make_tuple(B->getAddress(), dataBlockSecondaryKey(B));\n}\n\nstatic inline auto blockAddressKey(const Node* N) {\n  if (const auto* CB = dyn_cast<CodeBlock>(N)) {\n    return codeBlockAddressKey(CB);\n  } else {\n    auto* DB = cast<DataBlock>(N);\n    return dataBlockAddressKey(DB);\n  }\n}\n\ntemplate <>\nbool AddressLess::operator()<CodeBlock>(const CodeBlock* B1,\n                                        const CodeBlock* B2) const {\n  return codeBlockAddressKey(B1) < codeBlockAddressKey(B2);\n}\n\ntemplate <>\nbool AddressLess::operator()<DataBlock>(const DataBlock* B1,\n                                        const DataBlock* B2) const {\n  return dataBlockAddressKey(B1) < dataBlockAddressKey(B2);\n}\n\nbool BlockAddressLess::operator()(const Node* N1, const Node* N2) const {\n  return blockAddressKey(N1) < blockAddressKey(N2);\n}\n\nbool BlockOffsetPairLess::operator()(\n    std::pair<uint64_t, const Node*> B1,\n    std::pair<uint64_t, const Node*> B2) const {\n  return std::make_tuple(B1.first, blockSecondaryKey(B1.second)) <\n         std::make_tuple(B2.first, blockSecondaryKey(B2.second));\n}\n"
  },
  {
    "path": "src/gtirb/proto/CMakeLists.txt",
    "content": "if(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)\n  add_compile_options(-wd4146) # unary minus operator applied to unsigned type,\n                               # result still unsigned\n  add_compile_options(-wd4125) # decimal digit terminates octal escape sequence\n  add_compile_options(-wd4456) # declaration of 'decl' hides previous local\n                               # declaration\n  add_compile_options(-wd4100) # unreferenced formal parameter\n  add_compile_options(-wd4267) # conversion from 'type1' to 'type2', possible\n                               # loss of data\n  add_compile_options(-wd4244) # possible loss of data in conversion\n  add_compile_options(-wd4127) # conditional expression is constant\n  add_compile_options(\n    -wd4251\n  ) # 'identifier' : class 'type' needs to have dll- interface to be used by\n    # clients of class 'type2'\n  add_compile_options(-wd4275) # Non-dll interface base classes.\n  add_compile_options(\"/FI${CMAKE_SOURCE_DIR}/include/gtirb/Export.hpp\")\nelse()\n  add_compile_options(-Wno-shadow)\n  add_compile_options(-Wno-unused-parameter)\n  add_compile_options(-include \"${CMAKE_SOURCE_DIR}/include/gtirb/Export.hpp\")\nendif()\n\nprotobuf_generate_cpp(PROTO_CPP_SOURCES PROTO_CPP_HEADERS ${GTIRB_PROTO_FILES})\n\n# Copy headers to the right place\nadd_custom_command(\n  OUTPUT \"${CMAKE_BINARY_DIR}/include/gtirb/proto\"\n  COMMAND \"${CMAKE_COMMAND}\" -E make_directory\n          \"${CMAKE_BINARY_DIR}/include/gtirb/proto\"\n)\n\nforeach(PROTO_H ${PROTO_CPP_HEADERS})\n  get_filename_component(PROTO_H_NAME \"${PROTO_H}\" NAME)\n  set(COPIED_PROTO_H \"${CMAKE_BINARY_DIR}/include/gtirb/proto/${PROTO_H_NAME}\")\n  list(APPEND PROTO_COPIED_HEADERS \"${COPIED_PROTO_H}\")\n\n  add_custom_command(\n    DEPENDS \"${PROTO_H}\"\n    OUTPUT \"${COPIED_PROTO_H}\"\n    COMMAND \"${CMAKE_COMMAND}\" -E copy \"${PROTO_H}\" \"${COPIED_PROTO_H}\"\n  )\nendforeach(PROTO_H)\n\n# Add proto library target\nadd_library(gtirb_proto STATIC ${PROTO_CPP_SOURCES} ${PROTO_COPIED_HEADERS})\n\ntarget_link_libraries(gtirb_proto ${Boost_LIBRARIES} ${Protobuf_LIBRARIES})\n\ntarget_compile_definitions(gtirb_proto PRIVATE GTIRB_${PROJECT_NAME}_EXPORTS)\n\ninclude_directories(SYSTEM \"${PROTOBUF_INCLUDE_DIRS}\")\ntarget_include_directories(\n  gtirb_proto PUBLIC $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/include>\n)\n\ninstall(\n  TARGETS gtirb_proto\n  COMPONENT proto_library\n  EXPORT gtirbTargets\n  ARCHIVE DESTINATION lib\n  LIBRARY DESTINATION lib\n)\n"
  },
  {
    "path": "src/test/Addr.test.cpp",
    "content": "//===- Addr.test.cpp --------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include <gtirb/Addr.hpp>\n#include <gtirb/ByteInterval.hpp>\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/Context.hpp>\n#include <gtirb/Section.hpp>\n#include <gtest/gtest.h>\n#include <sstream>\n\nusing namespace gtirb;\n\nstatic Context Ctx;\n\nTEST(Unit_Addr, ctor_0) { EXPECT_EQ(Addr(), Addr()); }\n\nTEST(Unit_Addr, ctor_1) {\n  auto Ea = Addr(2112);\n  EXPECT_EQ(2112, uint64_t(Ea));\n}\n\nTEST(Unit_Addr, fromIntegers) {\n  uint64_t U64 = 1;\n  Addr U64Addr(U64);\n  EXPECT_EQ(uint64_t(U64Addr), U64);\n\n  int64_t S64 = 2;\n  Addr S64Addr(S64);\n  EXPECT_EQ(uint64_t(S64Addr), S64);\n}\n\nTEST(Unit_Addr, toIntegers) {\n  Addr Ea(1);\n  EXPECT_EQ(static_cast<uint64_t>(Ea), static_cast<uint64_t>(1));\n  EXPECT_EQ(static_cast<uint64_t>(Ea), static_cast<int64_t>(1));\n}\n\nTEST(Unit_Addr, comparison) {\n  Addr Ea1(2112), Ea2(1221), Ea3(1000), Ea4(1000);\n\n  EXPECT_EQ(Ea3, Ea4);\n  EXPECT_TRUE(Ea3 == Ea4);\n  EXPECT_FALSE(Ea3 != Ea4);\n\n  EXPECT_NE(Ea1, Ea2);\n  EXPECT_TRUE(Ea1 != Ea2);\n  EXPECT_FALSE(Ea1 == Ea2);\n\n  EXPECT_LT(Ea2, Ea1);\n  EXPECT_TRUE(Ea2 < Ea1);\n  EXPECT_FALSE(Ea2 > Ea1);\n\n  EXPECT_GT(Ea1, Ea2);\n  EXPECT_TRUE(Ea1 > Ea2);\n  EXPECT_FALSE(Ea1 < Ea2);\n\n  EXPECT_LE(Ea3, Ea4);\n  EXPECT_TRUE(Ea3 <= Ea4);\n  EXPECT_FALSE(Ea3 > Ea4);\n\n  EXPECT_GE(Ea3, Ea4);\n  EXPECT_TRUE(Ea3 >= Ea4);\n  EXPECT_FALSE(Ea3 < Ea4);\n}\n\nTEST(Unit_Addr, arithmetic) {\n  Addr Ea(10);\n\n  EXPECT_EQ(Ea + 5, Addr(15));\n  EXPECT_EQ(Ea - Addr(5), 5);\n  EXPECT_EQ(Ea - 5, Addr(5));\n\n  EXPECT_EQ(++Ea, Addr(11));\n  EXPECT_EQ(--Ea, Addr(10));\n\n  EXPECT_EQ(Ea++, Addr(10));\n  EXPECT_EQ(Ea, Addr(11));\n\n  EXPECT_EQ(Ea--, Addr(11));\n  EXPECT_EQ(Ea, Addr(10));\n\n  EXPECT_EQ(Ea += 5, Addr(15));\n  EXPECT_EQ(Ea -= 5, Addr(10));\n}\n\nTEST(Unit_Addr, ostream) {\n  std::ostringstream Os;\n\n  Os << 123 << \" 0x\" << std::hex << static_cast<uint64_t>(Addr(456)) << std::dec\n     << \" 789\";\n  EXPECT_EQ(Os.str(), \"123 0x1c8 789\");\n\n  Os.str({});\n  Os << 987 << \" \" << Addr(654) << \" 321\";\n  EXPECT_EQ(Os.str(), \"987 0x28e 321\");\n}\n\nTEST(Unit_Addr, Constexpr) {\n  // Test constexpr equality.\n  static_assert(Addr(10) == Addr(10));\n  static_assert(noexcept(Addr(10) == Addr(10)));\n  static_assert(Addr(10) != Addr(1));\n  static_assert(noexcept(Addr(10) != Addr(1)));\n\n  // Test constexpr conversion to int.\n  static_assert((uint64_t)Addr(10) == 10);\n  static_assert(noexcept((uint64_t)Addr(10)));\n\n  // Test constexpr comparisons.\n  static_assert(Addr(1) < Addr(10));\n  static_assert(noexcept(Addr(1) < Addr(10)));\n  static_assert(Addr(10) > Addr(1));\n  static_assert(noexcept(Addr(10) > Addr(1)));\n  static_assert(Addr(2) <= Addr(2));\n  static_assert(noexcept(Addr(2) <= Addr(2)));\n  static_assert(Addr(2) >= Addr(2));\n  static_assert(noexcept(Addr(2) >= Addr(2)));\n\n  // Test constexpr increment and decrement.\n  static_assert(++Addr(2) == Addr(3));\n  static_assert(noexcept(++Addr(2)));\n  static_assert(--Addr(2) == Addr(1));\n  static_assert(noexcept(--Addr(2)));\n  static_assert(Addr(2)++ == Addr(2));\n  static_assert(noexcept(Addr(2)++));\n  static_assert(Addr(2)-- == Addr(2));\n  static_assert(noexcept(Addr(2)--));\n\n  // Test unary operators.\n  static_assert(+Addr(12) == Addr(12));\n  static_assert(noexcept(+Addr(12)));\n  static_assert(~Addr(0) == Addr(std::numeric_limits<Addr::value_type>::max()));\n  static_assert(noexcept(~Addr(0)));\n\n  // Test arithmetic operators.\n  static_assert(Addr(10) + 1 == Addr(11));\n  static_assert(noexcept(Addr(10) + 1));\n  static_assert(1 + Addr(10) == Addr(11));\n  static_assert(noexcept(1 + Addr(10)));\n  static_assert(Addr(10) - 1 == Addr(9));\n  static_assert(noexcept(Addr(10) - 1));\n  static_assert(Addr(10) - Addr(9) == 1);\n  static_assert(noexcept(Addr(10) - Addr(9)));\n\n  // Test arithmetic compound assignment operators.\n  static_assert((Addr(10) += 1) == Addr(11));\n  static_assert(noexcept(Addr(10) += 1));\n  static_assert((Addr(10) -= 1) == Addr(9));\n  static_assert(noexcept(Addr(10) -= 1));\n\n  // Ensure that wrapping happens at compile time, in either direction, without\n  // triggering undefined behavior. Note, this explicitly disables compiler\n  // diagnostics about overflow as those may be warned on even with well-defined\n  // semantics.\n#if defined(_MSC_VER)\n#pragma warning(push)\n#pragma warning(disable : 4307) // '+': integral constant overflow\n#endif\n  static_assert(Addr(0) - 1 ==\n                Addr(std::numeric_limits<Addr::value_type>::max()));\n  static_assert(noexcept(Addr(0) - 1));\n  static_assert(Addr(std::numeric_limits<Addr::value_type>::max()) + 1 ==\n                Addr(0));\n  static_assert(\n      noexcept(Addr(std::numeric_limits<Addr::value_type>::max()) + 1));\n#if defined(_MSC_VER)\n#pragma warning(pop)\n#endif\n}\n\nTEST(Unit_Addr, addressLimit) {\n  auto* BI = ByteInterval::Create(Ctx, 10);\n  EXPECT_EQ(addressLimit(*BI), std::nullopt);\n\n  BI->setAddress(Addr(0));\n  auto* CB = BI->addBlock<CodeBlock>(Ctx, 0, 5);\n\n  EXPECT_EQ(addressLimit(*BI), Addr(10));\n  EXPECT_EQ(addressLimit(*CB), Addr(5));\n\n  auto* S = Section::Create(Ctx, \"\");\n  EXPECT_EQ(addressLimit(*S), std::nullopt);\n\n  S->addByteInterval(BI);\n  EXPECT_EQ(addressLimit(*S), Addr(10));\n}\n\nTEST(Unit_Addr, hash) {\n  std::unordered_set<Addr> Addrs{Addr(0), Addr(10), Addr(10)};\n  EXPECT_EQ(Addrs.size(), 2);\n}\n"
  },
  {
    "path": "src/test/Allocator.test.cpp",
    "content": "//===- Allocator.test.cpp ---------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n\n#include <gtirb/Allocator.hpp>\n#include <array>\n#include <gtest/gtest.h>\n\nclass AllocTest {\npublic:\n  static size_t CtorCount;\n  static size_t DtorCount;\n\n  AllocTest() { CtorCount++; }\n  ~AllocTest() { DtorCount++; }\n\n  std::array<char, 7> Data; // Take up some space\n};\nsize_t AllocTest::CtorCount = 0;\nsize_t AllocTest::DtorCount = 0;\n\nusing namespace ::gtirb;\nusing Allocator = SpecificBumpPtrAllocator<AllocTest>;\n\ninline void* operator new(size_t, Allocator& A) { return A.Allocate(); }\ninline void operator delete(void*, Allocator&) {}\n\nTEST(Unit_Allocator, allocate) {\n  AllocTest::CtorCount = AllocTest::DtorCount = 0;\n  Allocator A;\n  EXPECT_NE(new (A) AllocTest, nullptr);\n  EXPECT_NE(new (A) AllocTest, nullptr);\n  EXPECT_NE(new (A) AllocTest, nullptr);\n  EXPECT_EQ(AllocTest::CtorCount, 3);\n}\n\nTEST(Unit_Allocator, deallocate) {\n  // For varying numbers of allocations, ensure that destructors are called.\n  for (int AllocCount = 0; AllocCount < 100; AllocCount++) {\n    AllocTest::CtorCount = AllocTest::DtorCount = 0;\n    {\n      Allocator A;\n      EXPECT_NE(new (A) AllocTest, nullptr);\n      EXPECT_NE(new (A) AllocTest, nullptr);\n      EXPECT_NE(new (A) AllocTest, nullptr);\n      EXPECT_EQ(AllocTest::DtorCount, 0);\n    }\n    // All objects destroyed when allocator goes out of scope\n    EXPECT_EQ(AllocTest::DtorCount, AllocTest::CtorCount);\n  }\n}\n"
  },
  {
    "path": "src/test/AuxData.test.cpp",
    "content": "//===- AuxData.test.cpp ----------------------------------------*- C++-*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"SerializationTestHarness.hpp\"\n#include <gtirb/AuxData.hpp>\n#include <gtirb/Context.hpp>\n#include <gtirb/proto/AuxData.pb.h>\n#include <gtest/gtest.h>\n#include <memory>\n#include <sstream>\n\nstruct MoveTest;\n\nnamespace gtirb {\nnamespace schema {\n\nstruct MapAddrToString {\n  static constexpr const char* Name = \"std::map<Addr, std::string>\";\n  typedef std::map<Addr, std::string> Type;\n};\n\nstruct MapInt64ToString {\n  static constexpr const char* Name = \"std::map<int64_t, std::string>\";\n  typedef std::map<int64_t, std::string> Type;\n};\n\nstruct MapStringToString {\n  static constexpr const char* Name = \"std::map<std::string, std::string>\";\n  typedef std::map<std::string, std::string> Type;\n};\n\nstruct MapUUIDToString {\n  static constexpr const char* Name = \"std::map<UUID, std::string>\";\n  typedef std::map<UUID, std::string> Type;\n};\n\nstruct VectorMapStringToInt {\n  static constexpr const char* Name = \"std::vector<std::map<std::string, int>>\";\n  typedef std::vector<std::map<std::string, int>> Type;\n};\n\nstruct VectorAddr {\n  static constexpr const char* Name = \"std::vector<Addr>\";\n  typedef std::vector<Addr> Type;\n};\n\nstruct VectorInt64 {\n  static constexpr const char* Name = \"std::vector<int64_t>\";\n  typedef std::vector<int64_t> Type;\n};\n\nstruct VectorString {\n  static constexpr const char* Name = \"std::vector<std::string>\";\n  typedef std::vector<std::string> Type;\n};\n\nstruct VectorUUID {\n  static constexpr const char* Name = \"std::vector<UUID>\";\n  typedef std::vector<UUID> Type;\n};\n\nstruct SetUUID {\n  static constexpr const char* Name = \"std::unordered_set<UUID>\";\n  typedef std::unordered_set<UUID> Type;\n};\n\nstruct AString {\n  static constexpr const char* Name = \"A string type\";\n  typedef std::string Type;\n};\n\nstruct AnAddr {\n  static constexpr const char* Name = \"Addr\";\n  typedef Addr Type;\n};\n\nstruct MapCharToInt64 {\n  static constexpr const char* Name = \"std::map<char, int64_t>\";\n  typedef std::map<char, int64_t> Type;\n};\n\nstruct SetOfInt {\n  static constexpr const char* Name = \"Set of int\";\n  typedef std::set<int> Type;\n};\n\nstruct TupleOfCharAndInt64 {\n  static constexpr const char* Name = \"Tuple of char and int64\";\n  typedef std::tuple<char, int64_t> Type;\n};\n\nstruct TupleOfCharOrAddr {\n  static constexpr const char* Name = \"3-Tuple of variant<Addr,char>\";\n  typedef std::variant<Addr, char> VarT;\n  typedef std::tuple<VarT, VarT, VarT> Type;\n};\n\nstruct PairOfCharAndInt64 {\n  static constexpr const char* Name = \"Pair of char and int64\";\n  typedef std::pair<char, int64_t> Type;\n};\n\nstruct AnInt64 {\n  static constexpr const char* Name = \"A 64-bit integer\";\n  typedef int64_t Type;\n};\n\nstruct AnInt32 {\n  static constexpr const char* Name = \"A 32-bit integer\";\n  typedef int32_t Type;\n};\n\nstruct AnDouble {\n  static constexpr const char* Name = \"A 64-bit float\";\n  typedef double Type;\n};\n\nstruct AnFloat {\n  static constexpr const char* Name = \"A 32-bit float\";\n  typedef float Type;\n};\n\nstruct ListInt64 {\n  static constexpr const char* Name = \"A list of 64-bit integers\";\n  typedef std::list<int64_t> Type;\n};\n\nstruct AUUID {\n  static constexpr const char* Name = \"A UUID\";\n  typedef UUID Type;\n};\n\nstruct AChar {\n  static constexpr const char* Name = \"A char\";\n  typedef char Type;\n};\n\nstruct AUint64 {\n  static constexpr const char* Name = \"A 64-bit unsigned integer\";\n  typedef uint64_t Type;\n};\n\nstruct AUint8 {\n  static constexpr const char* Name = \"An 8-bit unsigned integer\";\n  typedef uint8_t Type;\n};\n\nstruct AnInt {\n  static constexpr const char* Name = \"A plain int\";\n  typedef int Type;\n};\n\nstruct AnUnsigned {\n  static constexpr const char* Name = \"A plain unsigned\";\n  typedef unsigned Type;\n};\n\nstruct ABool {\n  static constexpr const char* Name = \"A bool\";\n  typedef bool Type;\n};\n\nstruct AByte {\n  static constexpr const char* Name = \"A byte\";\n  typedef std::byte Type;\n};\n\nstruct AnOffset {\n  static constexpr const char* Name = \"An offset\";\n  typedef Offset Type;\n};\n\nstruct VectorOfMapOfTuple {\n  static constexpr const char* Name = \"A complex data structure\";\n  typedef std::vector<std::map<char, std::tuple<int64_t, uint64_t>>> Type;\n};\n\nstruct MapOfVector {\n  static constexpr const char* Name = \"Another complex data structure\";\n  typedef std::map<std::string, std::vector<int64_t>> Type;\n};\n\nstruct TupleOfVector {\n  static constexpr const char* Name = \"And another complex data structure\";\n  typedef std::tuple<std::string, std::vector<int64_t>> Type;\n};\n\nstruct AMoveTest {\n  static constexpr const char* Name = \"A MoveTest\";\n  typedef MoveTest Type;\n};\n\nstruct SimpleVariant {\n  static constexpr const char* Name =\n      \"Simple variant of uint8_t, int32_t and Addr\";\n  typedef std::variant<uint8_t, int32_t, Addr> Type;\n};\n\nstruct OtherSimpleVariant {\n  static constexpr const char* Name = \"another simple variant\";\n  typedef std::variant<Addr, char> Type;\n};\n\nstruct ComplexVariant {\n  using Map = std::map<std::string, std::vector<int64_t>>;\n  static constexpr const char* Name =\n      \"Complex variant of uint8_t, int32_t and complex map\";\n  typedef std::variant<uint8_t, int32_t, Map> Type;\n};\n\nstruct DuplicateVariant {\n  static constexpr const char* Name =\n      \"Variant with fields distinguished by position only\";\n  typedef std::variant<uint16_t, int16_t, uint16_t> Type;\n};\n\nstruct MapCharToVariant {\n  static constexpr const char* Name = \"std::map<char,std::variant<Addr,char>>\";\n  typedef std::map<char, std::variant<Addr, char>> Type;\n};\n\nstruct VecOfVariants {\n  static constexpr const char* Name = \"std::vector<std::variant<Addr, char>>\";\n  typedef std::vector<std::variant<Addr, char>> Type;\n};\n\n} // namespace schema\n} // namespace gtirb\n\nusing namespace gtirb;\nusing namespace gtirb::schema;\n\nstatic Context Ctx;\n\nTEST(Unit_AuxData, eaMapProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  using MapT = std::map<Addr, std::string>;\n  AuxDataImpl<MapAddrToString> Original =\n      MapT({{Addr(1), {\"a\"}}, {Addr(2), {\"b\"}}});\n\n  std::stringstream ss;\n  STH::save(Original, ss);\n  auto Intermediate = STH::load<AuxDataImpl<MapAddrToString>>(Ctx, ss);\n  // Test that deserialized data can be reserialized again.\n  std::stringstream ss2;\n  STH::save(*Intermediate, ss2);\n  auto Result = STH::load<AuxDataImpl<MapAddrToString>>(Ctx, ss2);\n\n  const MapT* M = Result->get();\n  EXPECT_TRUE(M);\n  EXPECT_EQ(M->size(), 2);\n  EXPECT_EQ(M->at(Addr(1)), \"a\");\n  EXPECT_EQ(M->at(Addr(2)), \"b\");\n}\n\nTEST(Unit_AuxData, intMapProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  using MapT = std::map<int64_t, std::string>;\n  AuxDataImpl<MapInt64ToString> Original = MapT({{1, {\"a\"}}, {2, {\"b\"}}});\n\n  std::stringstream ss;\n  STH::save(Original, ss);\n  auto Result = STH::load<AuxDataImpl<MapInt64ToString>>(Ctx, ss);\n\n  MapT M = *Result->get();\n  EXPECT_EQ(M.size(), 2);\n  EXPECT_EQ(M[1], \"a\");\n  EXPECT_EQ(M[2], \"b\");\n}\n\nTEST(Unit_AuxData, stringMapProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  using MapT = std::map<std::string, std::string>;\n  AuxDataImpl<MapStringToString> Original = MapT({{\"1\", {\"a\"}}, {\"2\", {\"b\"}}});\n\n  std::stringstream ss;\n  STH::save(Original, ss);\n  auto Result = STH::load<AuxDataImpl<MapStringToString>>(Ctx, ss);\n\n  MapT M = *Result->get();\n  EXPECT_EQ(M.size(), 2);\n  EXPECT_EQ(M[\"1\"], \"a\");\n  EXPECT_EQ(M[\"2\"], \"b\");\n}\n\nTEST(Unit_AuxData, uuidMapProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  using MapT = std::map<UUID, std::string>;\n  UUID Id1 = Node::Create(Ctx)->getUUID();\n  UUID Id2 = Node::Create(Ctx)->getUUID();\n  AuxDataImpl<MapUUIDToString> Original = MapT({{Id1, {\"a\"}}, {Id2, {\"b\"}}});\n\n  std::stringstream ss;\n  STH::save(Original, ss);\n  auto Result = STH::load<AuxDataImpl<MapUUIDToString>>(Ctx, ss);\n\n  MapT M = *Result->get();\n  EXPECT_EQ(M.size(), 2);\n  EXPECT_EQ(M[Id1], \"a\");\n  EXPECT_EQ(M[Id2], \"b\");\n}\n\nTEST(Unit_AuxData, mapVectorProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  auto Val = std::vector<std::map<std::string, int>>{{{\"key\", {1}}}};\n  auto ValOrig = Val;\n\n  AuxDataImpl<VectorMapStringToInt> Original(std::move(Val));\n  std::stringstream ss;\n  STH::save(Original, ss);\n  auto Result = STH::load<AuxDataImpl<VectorMapStringToInt>>(Ctx, ss);\n\n  auto New = *Result->get();\n  EXPECT_EQ(New, ValOrig);\n}\n\nTEST(Unit_AuxData, eaVectorProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  AuxDataImpl<VectorAddr> Original =\n      std::vector<Addr>({Addr(1), Addr(2), Addr(3)});\n\n  std::stringstream ss;\n  STH::save(Original, ss);\n  auto Result = STH::load<AuxDataImpl<VectorAddr>>(Ctx, ss);\n\n  EXPECT_EQ(*Result->get(), std::vector<Addr>({Addr(1), Addr(2), Addr(3)}));\n}\n\nTEST(Unit_AuxData, intVectorProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  AuxDataImpl<VectorInt64> Original = std::vector<int64_t>({1, 2, 3});\n\n  std::stringstream ss;\n  STH::save(Original, ss);\n  auto Result = STH::load<AuxDataImpl<VectorInt64>>(Ctx, ss);\n\n  EXPECT_EQ(*Result->get(), std::vector<int64_t>({1, 2, 3}));\n}\n\nTEST(Unit_AuxData, stringVectorProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  AuxDataImpl<VectorString> Original =\n      std::vector<std::string>({\"1\", \"2\", \"3\"});\n\n  std::stringstream ss;\n  STH::save(Original, ss);\n  auto Result = STH::load<AuxDataImpl<VectorString>>(Ctx, ss);\n\n  EXPECT_EQ(*Result->get(), std::vector<std::string>({\"1\", \"2\", \"3\"}));\n}\n\nTEST(Unit_AuxData, uuidVectorProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  UUID Id1 = Node::Create(Ctx)->getUUID(), Id2 = Node::Create(Ctx)->getUUID(),\n       Id3 = Node::Create(Ctx)->getUUID();\n  AuxDataImpl<VectorUUID> Original = std::vector<UUID>({Id1, Id2, Id3});\n\n  std::stringstream ss;\n  STH::save(Original, ss);\n  auto Result = STH::load<AuxDataImpl<VectorUUID>>(Ctx, ss);\n\n  EXPECT_EQ(*Result->get(), std::vector<UUID>({Id1, Id2, Id3}));\n}\n\nTEST(Unit_AuxData, uuidSetProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  UUID Id1 = Node::Create(Ctx)->getUUID(), Id2 = Node::Create(Ctx)->getUUID(),\n       Id3 = Node::Create(Ctx)->getUUID();\n  AuxDataImpl<SetUUID> Original = std::unordered_set<UUID>({Id1, Id2, Id3});\n\n  std::stringstream ss;\n  STH::save(Original, ss);\n  auto Result = STH::load<AuxDataImpl<SetUUID>>(Ctx, ss);\n\n  EXPECT_EQ(*Result->get(), std::unordered_set<UUID>({Id1, Id2, Id3}));\n  EXPECT_EQ(Result->rawData().ProtobufType, \"set<UUID>\");\n}\n\nTEST(Unit_AuxData, simpleVariantProtobufFirst) {\n  using STH = gtirb::SerializationTestHarness;\n  uint8_t ui = 1;\n  std::variant<uint8_t, int32_t, Addr> Val(ui);\n  auto ValOrig = Val;\n\n  AuxDataImpl<SimpleVariant> Original(std::move(Val));\n  std::stringstream ss;\n  STH::save(Original, ss);\n\n  auto Result = STH::load<AuxDataImpl<SimpleVariant>>(Ctx, ss);\n  auto New = *Result->get();\n\n  EXPECT_EQ(New, ValOrig);\n\n  EXPECT_EQ(Result->rawData().ProtobufType, \"variant<uint8_t,int32_t,Addr>\");\n}\n\nTEST(Unit_AuxData, simpleVariantProtobufSecond) {\n  using STH = gtirb::SerializationTestHarness;\n  int32_t i = -1000;\n  std::variant<uint8_t, int32_t, Addr> Val(i);\n  auto ValOrig = Val;\n\n  AuxDataImpl<SimpleVariant> Original(std::move(Val));\n  std::stringstream ss;\n  STH::save(Original, ss);\n\n  auto Result = STH::load<AuxDataImpl<SimpleVariant>>(Ctx, ss);\n  auto New = *Result->get();\n\n  EXPECT_EQ(New, ValOrig);\n\n  EXPECT_EQ(Result->rawData().ProtobufType, \"variant<uint8_t,int32_t,Addr>\");\n}\n\nTEST(Unit_AuxData, simpleVariantProtobufThird) {\n  using STH = gtirb::SerializationTestHarness;\n  Addr addr(0x1234);\n  std::variant<uint8_t, int32_t, Addr> Val(addr);\n  auto ValOrig = Val;\n\n  AuxDataImpl<SimpleVariant> Original(std::move(Val));\n  std::stringstream ss;\n  STH::save(Original, ss);\n\n  auto Result = STH::load<AuxDataImpl<SimpleVariant>>(Ctx, ss);\n  auto New = *Result->get();\n\n  EXPECT_EQ(New, ValOrig);\n\n  EXPECT_EQ(Result->rawData().ProtobufType, \"variant<uint8_t,int32_t,Addr>\");\n}\n\nTEST(Unit_AuxData, complexVariantProtobufThird) {\n  using STH = gtirb::SerializationTestHarness;\n  using Map = std::map<std::string, std::vector<int64_t>>;\n  Map M{{\"a\", {1, 2, 3}}};\n  std::variant<uint8_t, int32_t, Map> Val(M);\n  auto ValOrig = Val;\n\n  AuxDataImpl<ComplexVariant> Original(std::move(Val));\n  std::stringstream ss;\n  STH::save(Original, ss);\n\n  auto Result = STH::load<AuxDataImpl<ComplexVariant>>(Ctx, ss);\n  auto New = *Result->get();\n\n  EXPECT_EQ(New, ValOrig);\n\n  EXPECT_EQ(Result->rawData().ProtobufType,\n            \"variant<uint8_t,int32_t,mapping<string,sequence<int64_t>>>\");\n}\n\nTEST(Unit_AuxData, duplicateVariantProtobufFirst) {\n  using STH = gtirb::SerializationTestHarness;\n  std::variant<uint16_t, int16_t, uint16_t> Val{std::in_place_index<2>, 5};\n  auto ValOrig = Val;\n  AuxDataImpl<DuplicateVariant> Original(std::move(Val));\n  std::stringstream ss;\n  STH::save(Original, ss);\n\n  auto Result = STH::load<AuxDataImpl<DuplicateVariant>>(Ctx, ss);\n  auto New = *Result->get();\n  EXPECT_EQ(New, ValOrig);\n  EXPECT_EQ(New.index(), 2);\n  EXPECT_EQ(Result->rawData().ProtobufType,\n            \"variant<uint16_t,int16_t,uint16_t>\");\n}\n\nTEST(Unit_AuxData, TupleofVariants) {\n  using VarT = std::variant<Addr, char>;\n  using STH = gtirb::SerializationTestHarness;\n  AuxDataImpl<TupleOfCharOrAddr> Original =\n      std::tuple<VarT, VarT, VarT>{Addr(0xc0ffee), 'z', '\\x1'};\n  std::stringstream ss;\n  STH::save(Original, ss);\n  auto Result = STH::load<AuxDataImpl<TupleOfCharOrAddr>>(Ctx, ss);\n  auto T = *Result->get();\n  EXPECT_EQ(std::get<0>(T), VarT{Addr(0xc0ffee)});\n  EXPECT_EQ(std::get<1>(T), VarT{'z'});\n}\n\nTEST(Unit_AuxData, VecOfVariants2) {\n  using STH = gtirb::SerializationTestHarness;\n  using VariantT = std::variant<Addr, char>;\n  AuxDataImpl<VecOfVariants> Original = std::vector<VariantT>{Addr(0xc0ffee)};\n  std::stringstream ss;\n  STH::save(Original, ss);\n  auto Result = STH::load<AuxDataImpl<VecOfVariants>>(Ctx, ss);\n\n  auto V = *Result->get();\n  EXPECT_EQ(V.size(), 1);\n  EXPECT_EQ(V[0], VariantT(Addr(0xc0ffee)));\n}\n\nTEST(Unit_AuxData, VecOfVariants) {\n  using STH = gtirb::SerializationTestHarness;\n  using VariantT = std::variant<Addr, char>;\n  AuxDataImpl<VecOfVariants> Original =\n      std::vector<VariantT>{Addr(0xc0ffee), 'z', 'y', Addr(0xfeefaa)};\n  std::stringstream ss;\n  STH::save(Original, ss);\n  auto Result = STH::load<AuxDataImpl<VecOfVariants>>(Ctx, ss);\n\n  auto V = *Result->get();\n  EXPECT_EQ(V.size(), 4);\n  EXPECT_EQ(V[0], VariantT(Addr(0xc0ffee)));\n  EXPECT_EQ(V[2], VariantT('y'));\n}\n\nTEST(Unit_AuxData, MapCharToVariant) {\n  using STH = gtirb::SerializationTestHarness;\n  using VariantT = std::variant<Addr, char>;\n  using MapT = std::map<char, VariantT>;\n\n  AuxDataImpl<MapCharToVariant> Original =\n      MapT({{'a', Addr(0x1111)}, {'b', 'x'}, {'z', Addr(0xdeadbeef)}});\n\n  std::stringstream ss;\n  STH::save(Original, ss);\n  auto Result = STH::load<AuxDataImpl<MapCharToVariant>>(Ctx, ss);\n\n  MapT M = *Result->get();\n  EXPECT_EQ(M.size(), 3);\n  EXPECT_EQ(M['a'], VariantT{Addr(0x1111)});\n  EXPECT_EQ(M['b'], VariantT{'x'});\n  EXPECT_EQ(M['z'], VariantT{Addr(0xdeadbeef)});\n}\n\nTEST(Unit_AuxData, auxdata_traits_type_name) {\n  EXPECT_EQ(auxdata_traits<uint64_t>().type_name(), \"uint64_t\");\n  EXPECT_EQ(auxdata_traits<std::vector<uint64_t>>().type_name(),\n            \"sequence<uint64_t>\");\n  std::string X = auxdata_traits<std::map<int64_t, uint64_t>>().type_name();\n  EXPECT_EQ(X, \"mapping<int64_t,uint64_t>\");\n\n  X = auxdata_traits<std::map<int64_t, std::vector<uint64_t>>>().type_name();\n  EXPECT_EQ(X, \"mapping<int64_t,sequence<uint64_t>>\");\n\n  X = auxdata_traits<std::vector<std::map<int64_t, uint64_t>>>().type_name();\n  EXPECT_EQ(X, \"sequence<mapping<int64_t,uint64_t>>\");\n\n  X = auxdata_traits<std::vector<std::tuple<int64_t, uint64_t>>>().type_name();\n  EXPECT_EQ(X, \"sequence<tuple<int64_t,uint64_t>>\");\n\n  X = auxdata_traits<std::set<int32_t>>().type_name();\n  EXPECT_EQ(X, \"set<int32_t>\");\n\n  X = auxdata_traits<std::variant<uint8_t, int32_t, Addr>>().type_name();\n  EXPECT_EQ(X, \"variant<uint8_t,int32_t,Addr>\");\n\n  using Map = std::map<std::string, std::vector<int64_t>>;\n  X = auxdata_traits<std::variant<uint8_t, int32_t, Map>>().type_name();\n  EXPECT_EQ(X, \"variant<uint8_t,int32_t,mapping<string,sequence<int64_t>>>\");\n}\n\nTEST(Unit_AuxData, getPrimitiveTypes) {\n  AuxDataImpl<AChar> A = char('a');\n  EXPECT_EQ(*A.get(), 'a');\n\n  AuxDataImpl<AUint64> UI64 = uint64_t(123);\n  EXPECT_EQ(*UI64.get(), 123);\n\n  AuxDataImpl<AnInt64> SI64 = int64_t(-123);\n  EXPECT_EQ(*SI64.get(), -123);\n\n  AuxDataImpl<AnFloat> F32 = float(0.4000000059604645);\n  EXPECT_EQ(*F32.get(), 0.4000000059604645);\n\n  AuxDataImpl<AnDouble> F64 = float(1.0);\n  EXPECT_EQ(*F64.get(), 1.0);\n\n  AuxDataImpl<AUint8> UI8 = uint8_t(123);\n  EXPECT_EQ(*UI8.get(), 123);\n\n  AuxDataImpl<AnInt> SI = int(-123);\n  EXPECT_EQ(*SI.get(), -123);\n\n  AuxDataImpl<AnUnsigned> UI = unsigned(123);\n  EXPECT_EQ(*UI.get(), 123);\n\n  AuxDataImpl<ABool> Bo = bool(true);\n  EXPECT_EQ(*Bo.get(), true);\n\n  AuxDataImpl<AByte> B = std::byte(123);\n  EXPECT_EQ(*B.get(), std::byte(123));\n}\n\nTEST(Unit_AuxData, getVector) {\n  std::vector<int64_t> Orig({1, 2, 3});\n  auto Copy = Orig;\n  AuxDataImpl<VectorInt64> P(std::move(Copy));\n\n  auto& result = *P.get();\n  EXPECT_EQ(result, Orig);\n}\n\nTEST(Unit_AuxData, getString) {\n  std::string Orig(\"abcd\");\n  AuxDataImpl<AString> P(std::move(Orig));\n\n  EXPECT_EQ(*P.get(), \"abcd\");\n}\n\nTEST(Unit_AuxData, getAddr) {\n  Addr Orig(0x1234);\n  AuxDataImpl<AnAddr> P(std::move(Orig));\n\n  EXPECT_EQ(*P.get(), Addr(0x1234));\n}\n\nTEST(Unit_AuxData, getMap) {\n  std::map<char, int64_t> Orig({{'a', 1}, {'b', 2}, {'c', 3}});\n  auto Copy = Orig;\n  AuxDataImpl<MapCharToInt64> P(std::move(Copy));\n\n  auto& Result = *P.get();\n  EXPECT_EQ(Result, Orig);\n}\n\nTEST(Unit_AuxData, getSet) {\n  std::set<int> Orig({1, 2, 3});\n  auto Copy = Orig;\n  AuxDataImpl<SetOfInt> P(std::move(Copy));\n\n  auto& Result = *P.get();\n  EXPECT_EQ(Result, Orig);\n}\n\nTEST(Unit_AuxData, getTuple) {\n  std::tuple<char, int64_t> Orig('a', 1);\n  auto Copy = Orig;\n  AuxDataImpl<TupleOfCharAndInt64> P(std::move(Copy));\n\n  auto& Result = *P.get();\n  EXPECT_EQ(Result, Orig);\n}\n\nTEST(Unit_AuxData, protobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  int64_t A = 123;\n  auto Copy = A;\n  AuxDataImpl<AnInt64> P(std::move(Copy));\n\n  std::stringstream ss;\n  STH::save(P, ss);\n  auto Result = STH::load<AuxDataImpl<AnInt64>>(Ctx, ss);\n\n  EXPECT_EQ(A, *Result->get());\n}\n\nTEST(Unit_AuxData, vectorProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  std::vector<int64_t> V({1, 2, 3});\n  auto Copy = V;\n  AuxDataImpl<VectorInt64> P(std::move(Copy));\n\n  std::stringstream ss;\n  STH::save(P, ss);\n  auto Result = STH::load<AuxDataImpl<VectorInt64>>(Ctx, ss);\n\n  EXPECT_EQ(*Result->get(), V);\n}\n\nTEST(Unit_AuxData, listProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  std::list<int64_t> V({1, 2, 3});\n  auto Copy = V;\n  AuxDataImpl<ListInt64> P(std::move(Copy));\n\n  std::stringstream ss;\n  STH::save(P, ss);\n  auto Result = STH::load<AuxDataImpl<ListInt64>>(Ctx, ss);\n\n  EXPECT_EQ(*Result->get(), V);\n}\n\nTEST(Unit_AuxData, stringProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  std::string S(\"abcd\");\n  auto Copy = S;\n  AuxDataImpl<AString> P(std::move(Copy));\n\n  std::stringstream ss;\n  STH::save(P, ss);\n  auto Result = STH::load<AuxDataImpl<AString>>(Ctx, ss);\n\n  EXPECT_EQ(*Result->get(), S);\n}\n\nTEST(Unit_AuxData, addrProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  Addr A(0x1234);\n  auto Copy = A;\n  AuxDataImpl<AnAddr> P(std::move(Copy));\n\n  std::stringstream ss;\n  STH::save(P, ss);\n  auto Result = STH::load<AuxDataImpl<AnAddr>>(Ctx, ss);\n\n  EXPECT_EQ(*Result->get(), A);\n}\n\nTEST(Unit_AuxData, mapProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  std::map<char, int64_t> M({{'a', 1}, {'b', 2}, {'c', 3}});\n  auto Copy = M;\n  AuxDataImpl<MapCharToInt64> P(std::move(Copy));\n\n  std::stringstream ss;\n  STH::save(P, ss);\n  auto Result = STH::load<AuxDataImpl<MapCharToInt64>>(Ctx, ss);\n\n  EXPECT_EQ(*Result->get(), M);\n}\n\nTEST(Unit_AuxData, tupleProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  std::tuple<char, int64_t> T('a', 1);\n  auto Copy = T;\n  AuxDataImpl<TupleOfCharAndInt64> P(std::move(Copy));\n\n  std::stringstream ss;\n  STH::save(P, ss);\n  auto Result = STH::load<AuxDataImpl<TupleOfCharAndInt64>>(Ctx, ss);\n\n  EXPECT_EQ(*Result->get(), T);\n}\n\nTEST(Unit_AuxData, pairProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  std::pair<char, int64_t> Peer('a', 1);\n  auto Copy = Peer;\n  AuxDataImpl<PairOfCharAndInt64> P(std::move(Copy));\n\n  std::stringstream ss;\n  STH::save(P, ss);\n  auto Result = STH::load<AuxDataImpl<PairOfCharAndInt64>>(Ctx, ss);\n\n  EXPECT_EQ(*Result->get(), Peer);\n}\n\nTEST(Unit_AuxData, uuidProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  UUID Val = Node::Create(Ctx)->getUUID();\n  auto Copy = Val;\n  AuxDataImpl<AUUID> P(std::move(Copy));\n\n  std::stringstream ss;\n  STH::save(P, ss);\n  auto Result = STH::load<AuxDataImpl<AUUID>>(Ctx, ss);\n\n  EXPECT_EQ(*Result->get(), Val);\n}\n\nTEST(Unit_AuxData, OffsetProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  Offset Val{Node::Create(Ctx)->getUUID(), 123};\n  auto Copy = Val;\n  AuxDataImpl<AnOffset> P(std::move(Copy));\n\n  std::stringstream ss;\n  STH::save(P, ss);\n  auto Result = STH::load<AuxDataImpl<AnOffset>>(Ctx, ss);\n\n  auto NewVal = *Result->get();\n  EXPECT_EQ(NewVal.ElementId, Val.ElementId);\n  EXPECT_EQ(NewVal.Displacement, Val.Displacement);\n}\n\nTEST(Unit_AuxData, nestedProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n\n  // Outer vector\n  std::stringstream ss1;\n  std::vector<std::map<char, std::tuple<int64_t, uint64_t>>> N1;\n  N1.push_back({{'a', {0, 1}}, {'b', {2, 3}}});\n  N1.push_back({{'c', {4, 5}}, {'d', {6, 7}}});\n  auto Copy1 = N1;\n  AuxDataImpl<VectorOfMapOfTuple> Original1 = std::move(Copy1);\n  STH::save(Original1, ss1);\n  auto Result1 = STH::load<AuxDataImpl<VectorOfMapOfTuple>>(Ctx, ss1);\n\n  EXPECT_EQ(*Result1->get(), N1);\n\n  // Outer map\n  std::stringstream ss2;\n  std::map<std::string, std::vector<int64_t>> N2{{\"a\", {1, 2, 3}}};\n  auto Copy2 = N2;\n  AuxDataImpl<MapOfVector> Original2 = std::move(Copy2);\n  STH::save(Original2, ss2);\n  auto Result2 = STH::load<AuxDataImpl<MapOfVector>>(Ctx, ss2);\n\n  EXPECT_EQ(*Result2->get(), N2);\n\n  // Outer tuple\n  std::stringstream ss3;\n  std::tuple<std::string, std::vector<int64_t>> N3{\"a\", {1, 2, 3}};\n  auto Copy3 = N3;\n  AuxDataImpl<TupleOfVector> Original3 = std::move(Copy3);\n  STH::save(Original3, ss3);\n  auto Result3 = STH::load<AuxDataImpl<TupleOfVector>>(Ctx, ss3);\n\n  EXPECT_EQ(*Result3->get(), N3);\n}\n\nTEST(Unit_AuxData, wrongTypeAfterProtobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  AuxDataImpl<AnInt32> Original(1234);\n\n  std::stringstream ss;\n  STH::save(Original, ss);\n  EXPECT_EQ(STH::load<AuxDataImpl<AString>>(Ctx, ss), nullptr);\n}\n\nstruct MoveTest {\n  MoveTest() = default;\n  MoveTest(int X) : Val(X) {}\n  MoveTest(const MoveTest& other) : Val(other.Val) { CopyCount++; };\n  MoveTest(MoveTest&& other) : Val(std::move(other.Val)) { MoveCount++; }\n  static int CopyCount;\n  static int MoveCount;\n  int Val{0};\n};\nint MoveTest::CopyCount;\nint MoveTest::MoveCount;\n\ntemplate <>\nstruct gtirb::auxdata_traits<MoveTest> : default_serialization<MoveTest> {\n  static std::string type_name() { return \"MoveTest\"; }\n};\n\nTEST(Unit_AuxData, movesAndCopies) {\n  MoveTest::CopyCount = 0;\n  MoveTest::MoveCount = 0;\n\n  MoveTest M(123);\n  EXPECT_EQ(MoveTest::CopyCount, 0);\n  EXPECT_EQ(MoveTest::MoveCount, 0);\n\n  AuxDataImpl<AMoveTest> AD(std::move(M));\n  EXPECT_EQ(AD.get()->Val, 123);\n  EXPECT_EQ(MoveTest::CopyCount, 0);\n  EXPECT_EQ(MoveTest::MoveCount, 1);\n}\n"
  },
  {
    "path": "src/test/AuxDataContainer.test.cpp",
    "content": "//===- AuxDataContainer.test.cpp --------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"AuxDataContainerSchema.hpp\"\n#include \"Main.test.hpp\"\n#include \"PrepDeathTest.hpp\"\n#include \"SerializationTestHarness.hpp\"\n#include <gtirb/AuxDataContainer.hpp>\n#include <gtirb/Context.hpp>\n#include <gtirb/IR.hpp>\n#include <gtest/gtest.h>\n#include <memory>\n#include <sstream>\n\n// Note: Some things are not tested here, since they really need\n// multiple processes to test correctly. In particular, it's difficult\n// to test how the various methods are supposed to behave when an\n// AuxData type is not registered even though a container has\n// instances of the type (e.g. from some other process that did have\n// those types registered.)\n\nusing namespace gtirb;\nusing namespace gtirb::schema;\n\nContext Ctx;\n\nvoid registerAuxDataContainerTestAuxDataTypes() {\n  AuxDataContainer::registerAuxDataType<RegisteredType>();\n  AuxDataContainer::registerAuxDataType<BadDeSerializationType>();\n}\n\n#ifndef NDEBUG\nTEST(Unit_AuxDataContainerDeathTest, registerSchemaTooLate) {\n  // Guarantee that the AuxData TypeMap is locked.\n  [[maybe_unused]] auto* Ir = IR::Create(Ctx);\n\n  // It should now be illegal to attempt to add a new AuxData schema.\n  {\n    [[maybe_unused]] PrepDeathTest PDT;\n    EXPECT_DEATH(AuxDataContainer::registerAuxDataType<UnRegisteredType>(),\n                 \"New AuxData types cannot be added at this point.\");\n  }\n}\n#endif\n\nTEST(Unit_AuxDataContainer, addAuxDataRegistered) {\n  using STH = gtirb::SerializationTestHarness;\n  auto* Ir = IR::Create(Ctx);\n  Ir->addAuxData<RegisteredType>(5);\n\n  // Access it immediately?\n  {\n    const auto* CV =\n        static_cast<const gtirb::IR*>(Ir)->getAuxData<RegisteredType>();\n    EXPECT_NE(CV, nullptr);\n    EXPECT_EQ(*CV, 5);\n    auto* V = Ir->getAuxData<RegisteredType>();\n    EXPECT_NE(V, nullptr);\n    EXPECT_EQ(*V, 5);\n  }\n\n  std::stringstream ss;\n  STH::save(*Ir, ss);\n  Context ResultCtx;\n  auto* Result = STH::load<IR>(ResultCtx, ss);\n  ASSERT_TRUE(Result);\n\n  // Access it after serialization?\n  {\n    const auto* CV = Result->getAuxData<RegisteredType>();\n    ASSERT_NE(CV, nullptr);\n    EXPECT_EQ(*CV, 5);\n    auto* V = Result->getAuxData<RegisteredType>();\n    ASSERT_NE(V, nullptr);\n    EXPECT_EQ(*V, 5);\n  }\n}\n\n// Test that GTIRB correctly triggers an assertion failure when the client fails\n// to register an AuxData schema.\n#ifndef NDEBUG\nTEST(Unit_AuxDataContainerDeathTest, addAuxDataUnregistered) {\n  auto* Ir = IR::Create(Ctx);\n  {\n    [[maybe_unused]] PrepDeathTest PDT;\n    EXPECT_DEATH(\n        Ir->addAuxData<UnRegisteredType>(5),\n        \"Attempting to add AuxData with unregistered or incorrect type.\");\n  }\n}\n#endif\n\n// Test that GTIRB correctly triggers an assertion failure when the client tries\n// to use a schema that has the same name as a registered schema, but is\n// actually a different type.\n#ifndef NDEBUG\nTEST(Unit_AuxDataContainerDeathTest, addAuxDataDuplicateName) {\n  auto* Ir = IR::Create(Ctx);\n  {\n    [[maybe_unused]] PrepDeathTest PDT;\n    EXPECT_DEATH(\n        Ir->addAuxData<DuplicateNameType>(5),\n        \"Attempting to add AuxData with unregistered or incorrect type.\");\n  }\n}\n#endif\n\n// Test that GTIRB correctly returns null when attempting to fetch\n// AuxData that fails to unserialize.\nTEST(Unit_AuxDataContainer, addAuxDataBadUnserialize) {\n  using STH = gtirb::SerializationTestHarness;\n  auto* Ir = IR::Create(Ctx);\n  Ir->addAuxData<BadDeSerializationType>({5, 10});\n\n  std::stringstream ss;\n  STH::save(*Ir, ss);\n  Context ResultCtx;\n  auto* Result = STH::load<IR>(ResultCtx, ss);\n\n  // Access it after serialization?\n  {\n    const auto* CV = Result->getAuxData<RegisteredType>();\n    EXPECT_EQ(CV, nullptr);\n  }\n\n  // Should still be present as raw data\n  EXPECT_EQ(Result->getAuxDataSize(), 1);\n  auto It = Result->aux_data_begin();\n  const auto& Raw = *It;\n  EXPECT_STREQ(Raw.Key.c_str(), BadDeSerializationType::Name);\n  EXPECT_EQ(Raw.ProtobufType,\n            auxdata_traits<schema::BadDeSerializationType::Type>::type_name());\n  std::string ExpectedBytes = {0x5, 0x0, 0x0, 0x0, 0xA, 0x0, 0x0, 0x0};\n  ASSERT_EQ(Raw.RawBytes.size(), ExpectedBytes.size());\n  EXPECT_EQ(Raw.RawBytes, ExpectedBytes);\n}\n\n// AuxData not present\nTEST(Unit_AuxDataContainer, getAuxDataNotPresent) {\n  auto* Ir = IR::Create(Ctx);\n  EXPECT_EQ(Ir->getAuxData<RegisteredType>(), nullptr);\n}\n\n// AuxData present, but accessed w/ incompatible schema\n#ifndef NDEBUG\nTEST(Unit_AuxDataContainerDeathTest, getAuxDataIncompatibleSchema) {\n  auto* Ir = IR::Create(Ctx);\n  Ir->addAuxData<RegisteredType>(5);\n  {\n    [[maybe_unused]] PrepDeathTest PDT;\n    EXPECT_DEATH(Ir->getAuxData<DuplicateNameType>(),\n                 \"Attempting to retrieve AuxData with incorrect type.\");\n  }\n}\n#endif\n\n// AuxData present, but accessed w/ unregistered schema\n#ifndef NDEBUG\nTEST(Unit_AuxDataContainerDeathTest, getAuxDataUnregisteredType) {\n  const auto* Ir = getTestIr();\n  ASSERT_NE(Ir, nullptr);\n  {\n    [[maybe_unused]] PrepDeathTest PDT;\n    EXPECT_DEATH(Ir->getAuxData<UnRegisteredType>(),\n                 \"Attempting to retrieve AuxData with an unregistered type.\");\n  }\n}\n#endif\n\n// Removing AuxData by schema\nTEST(Unit_AuxDataContainer, removeAuxDataBySchema) {\n  auto* Ir = IR::Create(Ctx);\n  Ir->addAuxData<RegisteredType>(5);\n  const auto* CV = Ir->getAuxData<RegisteredType>();\n  ASSERT_NE(CV, nullptr);\n  EXPECT_EQ(*CV, 5);\n  EXPECT_TRUE(Ir->removeAuxData<RegisteredType>());\n  EXPECT_EQ(Ir->getAuxData<RegisteredType>(), nullptr);\n  EXPECT_FALSE(Ir->removeAuxData<RegisteredType>());\n}\n\n// Removing AuxData by name\nTEST(Unit_AuxDataContainer, removeAuxDataByName) {\n  auto* Ir = IR::Create(Ctx);\n  Ir->addAuxData<RegisteredType>(5);\n  const auto* CV = Ir->getAuxData<RegisteredType>();\n  ASSERT_NE(CV, nullptr);\n  EXPECT_EQ(*CV, 5);\n  EXPECT_TRUE(Ir->removeAuxData(\"registered type\"));\n  EXPECT_EQ(Ir->getAuxData<RegisteredType>(), nullptr);\n  EXPECT_FALSE(Ir->removeAuxData(\"registered type\"));\n}\n\n// Removing unregistered AuxData\n#ifndef NDEBUG\nTEST(Unit_AuxDataContainerDeathTest, removeAuxDataUnregistered) {\n  auto* Ir = IR::Create(Ctx);\n  {\n    [[maybe_unused]] PrepDeathTest PDT;\n    EXPECT_DEATH(Ir->removeAuxData<UnRegisteredType>(),\n                 \"Attempting to remove AuxData with an unregistered type.\");\n  }\n}\n#endif\n\n// Iteration and container size\nTEST(Unit_AuxDataContainer, iteration) {\n  auto* Ir = IR::Create(Ctx);\n\n  EXPECT_TRUE(Ir->getAuxDataEmpty());\n  EXPECT_EQ(Ir->getAuxDataSize(), 0);\n\n  Ir->addAuxData<RegisteredType>(5);\n  Ir->addAuxData<BadDeSerializationType>({10, 20});\n\n  EXPECT_FALSE(Ir->getAuxDataEmpty());\n  EXPECT_EQ(Ir->getAuxDataSize(), 2);\n\n  // begin/end\n  bool SawRegistered = false;\n  bool SawBad = false;\n  for (auto It = Ir->aux_data_begin(); It != Ir->aux_data_end(); ++It) {\n    if (It->Key == RegisteredType::Name) {\n      SawRegistered = true;\n    } else if (It->Key == BadDeSerializationType::Name) {\n      SawBad = true;\n    } else {\n      EXPECT_TRUE(false);\n    }\n  }\n  EXPECT_TRUE(SawRegistered);\n  EXPECT_TRUE(SawBad);\n\n  // Check that the range version gives us the same start and end\n  // points.\n  EXPECT_EQ(Ir->aux_data_begin(), Ir->aux_data().begin());\n  EXPECT_EQ(Ir->aux_data_end(), Ir->aux_data().end());\n\n  // Remove everything.\n  Ir->clearAuxData();\n  EXPECT_TRUE(Ir->getAuxDataEmpty());\n  EXPECT_EQ(Ir->getAuxDataSize(), 0);\n  EXPECT_EQ(Ir->aux_data_begin(), Ir->aux_data_end());\n  EXPECT_TRUE(Ir->aux_data().empty());\n}\n"
  },
  {
    "path": "src/test/AuxDataContainerSchema.hpp",
    "content": "#ifndef AUX_DATA_CONTAINER_SCHEMA_HPP\n#define AUX_DATA_CONTAINER_SCHEMA_HPP\n\n#include <gtirb/AuxData.hpp>\n#include <cstdint>\n\n// Schema for AuxDataContainer's unit tests\n\nnamespace gtirb {\nnamespace schema {\n\nstruct RegisteredType {\n  static constexpr const char* Name = \"registered type\";\n  typedef int64_t Type;\n};\n\nstruct UnRegisteredType {\n  static constexpr const char* Name = \"unregistered type\";\n  typedef int64_t Type;\n};\n\nstruct DuplicateNameType {\n  static constexpr const char* Name = \"registered type\";\n  typedef int32_t Type;\n};\n\nstruct BadDeSerializationType {\n  static constexpr const char* Name = \"bad deserialization type\";\n  typedef struct {\n    int32_t x;\n    int32_t y;\n  } Type;\n};\n\n} // namespace schema\n\n// The BadDeSerializationType schema will serialize but will fail to\n// deserialize. This models several situations that a client of\n// GTIRB might be in:\n//\n// 1) They incorrectly implement their custom auxdata_traits<> for\n// their custom schema.\n//\n// 2) They are processing a GTIRB file generated by a different\n// client that used an incompatible schema. In which case, when they\n// attempt to unserialize the AuxData, it will fail to unserialize\n// even though they have a schema registered for it.\n//\n// 3) They are processing a GTIRB file that's just outright corrupted.\ntemplate <> struct auxdata_traits<schema::BadDeSerializationType::Type> {\n  using T = schema::BadDeSerializationType::Type;\n  static void toBytes(const T& Object, ToByteRange& TBR) {\n    // Store as little-endian.\n    T reversed = boost::endian::conditional_reverse<\n        boost::endian::order::little, boost::endian::order::native>(Object);\n    auto srcBytes_begin = reinterpret_cast<std::byte*>(&reversed);\n    auto srcBytes_end = reinterpret_cast<std::byte*>(&reversed + 1);\n    std::for_each(srcBytes_begin, srcBytes_end, [&](auto b) { TBR.write(b); });\n  }\n\n  static bool fromBytes(T& Object [[maybe_unused]],\n                        FromByteRange& FBR [[maybe_unused]]) {\n    // Fail to deserialize.\n    return false;\n  }\n\n  static std::string type_name() { return \"badbadbad\"; }\n};\n\n} // namespace gtirb\n\n#endif // AUX_DATA_CONTAINER_SCHEMA_HPP\n"
  },
  {
    "path": "src/test/AuxDataSchemaRegistration.test.cpp",
    "content": "// Note: this file tests schema registration for AuxData. It is\n// purposely built as a separate test program so that we can keep the\n// type map unlocked. This means, one can write tests that register\n// schema, but one should *not* write tests that actually involve\n// constructing GTIRB IR.\n\n// Note also: Because schema registration is global, keeping this file\n// to a single unit test explicitly guarantees ordering in the state\n// of the registration.\n\n#include \"AuxDataContainerSchema.hpp\"\n#include \"PrepDeathTest.hpp\"\n#include <gtirb/AuxDataContainer.hpp>\n#include <gtest/gtest.h>\n\nusing namespace gtirb;\nusing namespace schema;\n\n#ifndef NDEBUG\nTEST(Unit_AuxDataContainerDeathTest, SchemaRegistration) {\n  AuxDataContainer::registerAuxDataType<RegisteredType>();\n\n  // Able to re-register the same schema with no error.\n  AuxDataContainer::registerAuxDataType<RegisteredType>();\n\n  // Assertion if registering a second schema w/ duplicate name but\n  // incompatibable type.\n  {\n    [[maybe_unused]] PrepDeathTest PDT;\n    EXPECT_DEATH(AuxDataContainer::registerAuxDataType<DuplicateNameType>(),\n                 \"Different types registered for the same AuxData name.\");\n  }\n}\n#endif\n"
  },
  {
    "path": "src/test/ByteInterval.test.cpp",
    "content": "//===- Block.test.cpp -------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"SerializationTestHarness.hpp\"\n#include \"TestHelpers.hpp\"\n#include <gtirb/ByteInterval.hpp>\n#include <gtirb/Context.hpp>\n#include <gtirb/IR.hpp>\n#include <gtirb/Symbol.hpp>\n#include <gtirb/proto/ByteInterval.pb.h>\n#include <gtest/gtest.h>\n#include <sstream>\n\nusing namespace gtirb;\n\nstatic Context Ctx;\n\nTEST(Unit_ByteInterval, compilationIteratorTypes) {\n  static_assert(std::is_same_v<ByteInterval::block_iterator::reference, Node&>);\n  static_assert(std::is_same_v<ByteInterval::const_block_iterator::reference,\n                               const Node&>);\n  static_assert(\n      std::is_same_v<ByteInterval::block_subrange::iterator::reference, Node&>);\n  static_assert(\n      std::is_same_v<ByteInterval::const_block_subrange::iterator::reference,\n                     const Node&>);\n\n  {\n    ByteInterval::block_iterator BIt;\n    ByteInterval::const_block_iterator CBIt(BIt);\n    CBIt = BIt;\n\n    ByteInterval::block_range BRng;\n    ByteInterval::const_block_range CBRng(BRng);\n    CBRng = BRng;\n\n    ByteInterval::block_subrange BSubRng;\n    ByteInterval::const_block_subrange CBSubRng(BSubRng);\n    CBSubRng = BSubRng;\n  }\n  static_assert(!std::is_convertible_v<ByteInterval::const_block_iterator,\n                                       ByteInterval::block_iterator>);\n  static_assert(!std::is_convertible_v<ByteInterval::const_block_range,\n                                       ByteInterval::block_range>);\n  static_assert(!std::is_convertible_v<ByteInterval::const_block_subrange,\n                                       ByteInterval::block_subrange>);\n}\n\nTEST(Unit_ByteInterval, noCopyMoveConstructors) {\n  EXPECT_FALSE(std::is_copy_constructible_v<ByteInterval>);\n  EXPECT_FALSE(std::is_move_constructible_v<ByteInterval>);\n  EXPECT_FALSE(std::is_copy_assignable_v<ByteInterval>);\n  EXPECT_FALSE(std::is_move_assignable_v<ByteInterval>);\n}\n\nTEST(Unit_ByteInterval, ctor) {\n  EXPECT_NE(ByteInterval::Create(Ctx, Addr(1), 100), nullptr);\n}\n\nTEST(Unit_ByteInterval, gettersSetters) {\n  auto* BI = ByteInterval::Create(Ctx, std::optional<Addr>(), 2);\n  EXPECT_EQ(std::optional<Addr>(), BI->getAddress());\n  EXPECT_EQ(2, BI->getSize());\n  EXPECT_EQ(2, BI->getInitializedSize());\n  EXPECT_EQ(BI->getSection(), nullptr);\n\n  BI->setAddress(Addr(1));\n  EXPECT_EQ(std::optional<Addr>(1), BI->getAddress());\n  EXPECT_EQ(2, BI->getSize());\n  EXPECT_EQ(2, BI->getInitializedSize());\n  EXPECT_EQ(BI->getSection(), nullptr);\n\n  BI->setSize(10);\n  EXPECT_EQ(std::optional<Addr>(1), BI->getAddress());\n  EXPECT_EQ(10, BI->getSize());\n  EXPECT_EQ(2, BI->getInitializedSize());\n  EXPECT_EQ(BI->getSection(), nullptr);\n\n  BI->setInitializedSize(5);\n  EXPECT_EQ(std::optional<Addr>(1), BI->getAddress());\n  EXPECT_EQ(10, BI->getSize());\n  EXPECT_EQ(5, BI->getInitializedSize());\n  EXPECT_EQ(BI->getSection(), nullptr);\n\n  BI->setSize(1);\n  EXPECT_EQ(std::optional<Addr>(1), BI->getAddress());\n  EXPECT_EQ(1, BI->getSize());\n  EXPECT_EQ(1, BI->getInitializedSize());\n  EXPECT_EQ(BI->getSection(), nullptr);\n\n  BI->setInitializedSize(20);\n  EXPECT_EQ(std::optional<Addr>(1), BI->getAddress());\n  EXPECT_EQ(20, BI->getSize());\n  EXPECT_EQ(20, BI->getInitializedSize());\n  EXPECT_EQ(BI->getSection(), nullptr);\n}\n\nTEST(Unit_ByteInterval, protobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  // Test with fixed address.\n  {\n    std::stringstream ss;\n    {\n      Context InnerCtx;\n      auto* Original = ByteInterval::Create(InnerCtx, Addr(1), 2);\n      STH::save(*Original, ss);\n    }\n    auto* Result = STH::load<ByteInterval>(Ctx, ss);\n\n    EXPECT_EQ(Result->getAddress(), std::optional<Addr>(1));\n    EXPECT_EQ(Result->getSize(), 2);\n    EXPECT_EQ(Result->getSection(), nullptr);\n  }\n\n  // Test without fixed address.\n  {\n    std::stringstream ss;\n    {\n      Context InnerCtx;\n      auto* Original = ByteInterval::Create(InnerCtx, std::optional<Addr>(), 2);\n      STH::save(*Original, ss);\n    }\n    auto* Result = STH::load<ByteInterval>(Ctx, ss);\n\n    EXPECT_EQ(Result->getAddress(), std::optional<Addr>());\n    EXPECT_EQ(Result->getSize(), 2);\n    EXPECT_EQ(Result->getSection(), nullptr);\n  }\n\n  // Test with bytes.\n  {\n    std::stringstream ss;\n    {\n      Context InnerCtx;\n      std::string Contents = \"abcd\";\n      auto* Original = ByteInterval::Create(InnerCtx, std::optional<Addr>(),\n                                            Contents.begin(), Contents.end());\n      STH::save(*Original, ss);\n    }\n    auto* Result = STH::load<ByteInterval>(Ctx, ss);\n\n    EXPECT_EQ(Result->getAddress(), std::optional<Addr>());\n    EXPECT_EQ(Result->getSize(), 4);\n    EXPECT_EQ(Result->getInitializedSize(), 4);\n    EXPECT_EQ(Result->getSection(), nullptr);\n\n    {\n      std::string ResultBytes;\n      auto It = Result->bytes_begin<char>();\n      std::copy(It, It + Result->getSize(), std::back_inserter(ResultBytes));\n      EXPECT_EQ(ResultBytes, \"abcd\");\n    }\n    // Try with different endianness.\n    // For fetching bytes this should not matter, but a bug in boost 1.67\n    // broke this for <char> and endian::order::big, prior to 2021-03 fix.\n    {\n      std::string ResultBytes;\n      auto It = Result->bytes_begin<char>(boost::endian::order::little);\n      std::copy(It, It + Result->getSize(), std::back_inserter(ResultBytes));\n      EXPECT_EQ(ResultBytes, \"abcd\");\n    }\n    {\n      std::string ResultBytes;\n      auto It = Result->bytes_begin<char>(boost::endian::order::big);\n      std::copy(It, It + Result->getSize(), std::back_inserter(ResultBytes));\n      EXPECT_EQ(ResultBytes, \"abcd\");\n    }\n    {\n      std::string ResultBytes;\n      auto It = Result->bytes_begin<signed char>(boost::endian::order::big);\n      std::copy(It, It + Result->getSize(), std::back_inserter(ResultBytes));\n      EXPECT_EQ(ResultBytes, \"abcd\");\n    }\n    {\n      std::string ResultBytes;\n      auto It = Result->bytes_begin<unsigned char>(boost::endian::order::big);\n      std::copy(It, It + Result->getSize(), std::back_inserter(ResultBytes));\n      EXPECT_EQ(ResultBytes, \"abcd\");\n    }\n    {\n      std::string ResultBytes;\n      auto It = Result->bytes_begin<int8_t>(boost::endian::order::big);\n      std::copy(It, It + Result->getSize(), std::back_inserter(ResultBytes));\n      EXPECT_EQ(ResultBytes, \"abcd\");\n    }\n    {\n      std::string ResultBytes;\n      auto It = Result->bytes_begin<uint8_t>(boost::endian::order::big);\n      std::copy(It, It + Result->getSize(), std::back_inserter(ResultBytes));\n      EXPECT_EQ(ResultBytes, \"abcd\");\n    }\n    // vector<byte>\n    {\n      std::vector<std::byte> ResultBytes;\n      auto It = Result->bytes_begin<std::byte>(boost::endian::order::little);\n      std::copy(It, It + Result->getSize(), std::back_inserter(ResultBytes));\n      EXPECT_EQ(ResultBytes.at(0), std::byte{'a'});\n      EXPECT_EQ(ResultBytes.at(1), std::byte{'b'});\n      EXPECT_EQ(ResultBytes.at(2), std::byte{'c'});\n      EXPECT_EQ(ResultBytes.at(3), std::byte{'d'});\n    }\n    {\n      std::vector<std::byte> ResultBytes;\n      auto It = Result->bytes_begin<std::byte>(boost::endian::order::big);\n      std::copy(It, It + Result->getSize(), std::back_inserter(ResultBytes));\n      EXPECT_EQ(ResultBytes.at(0), std::byte{'a'});\n      EXPECT_EQ(ResultBytes.at(1), std::byte{'b'});\n      EXPECT_EQ(ResultBytes.at(2), std::byte{'c'});\n      EXPECT_EQ(ResultBytes.at(3), std::byte{'d'});\n    }\n\n    // Try fetching shorts, assumed to be 16-bit, with different endianness.\n    // These were added to confirm that the boost bug for <char> above did not\n    // affect shorts and int16s.\n    assert(sizeof(short) == sizeof(int16_t));\n    {\n      std::vector<int16_t> ResultShorts;\n      auto It = Result->bytes_begin<int16_t>(boost::endian::order::little);\n      std::copy(It, It + Result->getSize() / sizeof(int16_t),\n                std::back_inserter(ResultShorts));\n      EXPECT_EQ(ResultShorts.at(0), 0x6261); // 'b','a'\n      EXPECT_EQ(ResultShorts.at(1), 0x6463); // 'd','c'\n    }\n    {\n      std::vector<uint16_t> ResultShorts;\n      auto It = Result->bytes_begin<uint16_t>(boost::endian::order::little);\n      std::copy(It, It + Result->getSize() / sizeof(uint16_t),\n                std::back_inserter(ResultShorts));\n      EXPECT_EQ(ResultShorts.at(0), 0x6261); // 'b','a'\n      EXPECT_EQ(ResultShorts.at(1), 0x6463); // 'd','c'\n    }\n    {\n      std::vector<short> ResultShorts;\n      auto It = Result->bytes_begin<short>(boost::endian::order::little);\n      std::copy(It, It + Result->getSize() / sizeof(short),\n                std::back_inserter(ResultShorts));\n      EXPECT_EQ(ResultShorts.at(0), 0x6261); // 'b','a'\n      EXPECT_EQ(ResultShorts.at(1), 0x6463); // 'd','c'\n    }\n    {\n      std::vector<signed short> ResultShorts;\n      auto It = Result->bytes_begin<signed short>(boost::endian::order::little);\n      std::copy(It, It + Result->getSize() / sizeof(signed short),\n                std::back_inserter(ResultShorts));\n      EXPECT_EQ(ResultShorts.at(0), 0x6261); // 'b','a'\n      EXPECT_EQ(ResultShorts.at(1), 0x6463); // 'd','c'\n    }\n    {\n      std::vector<unsigned short> ResultShorts;\n      auto It =\n          Result->bytes_begin<unsigned short>(boost::endian::order::little);\n      std::copy(It, It + Result->getSize() / sizeof(unsigned short),\n                std::back_inserter(ResultShorts));\n      EXPECT_EQ(ResultShorts.at(0), 0x6261); // 'b','a'\n      EXPECT_EQ(ResultShorts.at(1), 0x6463); // 'd','c'\n    }\n    {\n      std::vector<int16_t> ResultShorts;\n      auto It = Result->bytes_begin<int16_t>(boost::endian::order::big);\n      std::copy(It, It + Result->getSize() / sizeof(int16_t),\n                std::back_inserter(ResultShorts));\n      EXPECT_EQ(ResultShorts.at(0), 0x6162); // 'a','b'\n      EXPECT_EQ(ResultShorts.at(1), 0x6364); // 'c','d'\n    }\n    {\n      std::vector<uint16_t> ResultShorts;\n      auto It = Result->bytes_begin<uint16_t>(boost::endian::order::big);\n      std::copy(It, It + Result->getSize() / sizeof(uint16_t),\n                std::back_inserter(ResultShorts));\n      EXPECT_EQ(ResultShorts.at(0), 0x6162); // 'a','b'\n      EXPECT_EQ(ResultShorts.at(1), 0x6364); // 'c','d'\n    }\n    {\n      std::vector<short> ResultShorts;\n      auto It = Result->bytes_begin<short>(boost::endian::order::big);\n      std::copy(It, It + Result->getSize() / sizeof(short),\n                std::back_inserter(ResultShorts));\n      EXPECT_EQ(ResultShorts.at(0), 0x6162); // 'a','b'\n      EXPECT_EQ(ResultShorts.at(1), 0x6364); // 'c','d'\n    }\n    {\n      std::vector<signed short> ResultShorts;\n      auto It = Result->bytes_begin<signed short>(boost::endian::order::big);\n      std::copy(It, It + Result->getSize() / sizeof(signed short),\n                std::back_inserter(ResultShorts));\n      EXPECT_EQ(ResultShorts.at(0), 0x6162); // 'a','b'\n      EXPECT_EQ(ResultShorts.at(1), 0x6364); // 'c','d'\n    }\n    {\n      std::vector<unsigned short> ResultShorts;\n      auto It = Result->bytes_begin<unsigned short>(boost::endian::order::big);\n      std::copy(It, It + Result->getSize() / sizeof(unsigned short),\n                std::back_inserter(ResultShorts));\n      EXPECT_EQ(ResultShorts.at(0), 0x6162); // 'a','b'\n      EXPECT_EQ(ResultShorts.at(1), 0x6364); // 'c','d'\n    }\n  }\n\n  // Test truncating of unallocated bytes.\n  {\n    std::stringstream ss;\n    {\n      Context InnerCtx;\n      std::string Contents = \"abcd\";\n      auto* Original =\n          ByteInterval::Create(InnerCtx, std::optional<Addr>(),\n                               Contents.begin(), Contents.end(), 4, 2);\n      STH::save(*Original, ss);\n    }\n    auto* Result = STH::load<ByteInterval>(Ctx, ss);\n\n    EXPECT_EQ(Result->getAddress(), std::optional<Addr>());\n    EXPECT_EQ(Result->getSize(), 4);\n    EXPECT_EQ(Result->getInitializedSize(), 2);\n    EXPECT_EQ(Result->getSection(), nullptr);\n\n    std::string ResultBytes;\n    std::copy(Result->bytes_begin<char>(), Result->bytes_end<char>(),\n              std::back_inserter(ResultBytes));\n    // Explode the string comparison, because the default one for std::string\n    // does not like embedded NULs whatsoever.\n    ASSERT_EQ(ResultBytes.size(), 4);\n    ASSERT_EQ(ResultBytes[0], 'a');\n    ASSERT_EQ(ResultBytes[1], 'b');\n    ASSERT_EQ(ResultBytes[2], '\\0');\n    ASSERT_EQ(ResultBytes[3], '\\0');\n  }\n\n  // Test with subobjects.\n  {\n    auto* Sym = Symbol::Create(Ctx, \"test\");\n\n    std::stringstream ss;\n    {\n      Context InnerCtx;\n      auto* Original = ByteInterval::Create(InnerCtx, Addr(0), 10);\n      Original->addBlock<CodeBlock>(InnerCtx, 3, 1);\n      Original->addBlock<CodeBlock>(InnerCtx, 6, 1);\n      Original->addBlock<DataBlock>(InnerCtx, 6, 1);\n      Original->addSymbolicExpression<SymAddrConst>(5, 8, Sym);\n      STH::save(*Original, ss);\n    }\n    // Copy the stream so we can read from it a second time to do the\n    // symbolic expressions.\n    std::stringstream ss2;\n    ss2 << ss.str();\n    auto* Result = STH::load<ByteInterval>(Ctx, ss);\n\n    EXPECT_EQ(std::distance(Result->blocks_begin(), Result->blocks_end()), 3);\n    EXPECT_EQ(\n        std::distance(Result->code_blocks_begin(), Result->code_blocks_end()),\n        2);\n    EXPECT_EQ(\n        std::distance(Result->data_blocks_begin(), Result->data_blocks_end()),\n        1);\n    // Only after symbolicExpressionsFromProtobuf will sym exprs be populated.\n    EXPECT_EQ(std::distance(Result->symbolic_expressions_begin(),\n                            Result->symbolic_expressions_end()),\n              0);\n\n    constexpr auto getOffset = [](const Node& N) -> uint64_t {\n      if (auto* B = dyn_cast_or_null<CodeBlock>(&N)) {\n        return B->getOffset();\n      }\n      if (auto* D = dyn_cast_or_null<DataBlock>(&N)) {\n        return D->getOffset();\n      }\n      assert(!\"Found a non-block in a byte interval!\");\n      return 0;\n    };\n\n    EXPECT_EQ(getOffset(*Result->blocks_begin()), 3);\n    EXPECT_EQ(getOffset(*std::next(Result->blocks_begin())), 6);\n    EXPECT_EQ(getOffset(*std::next(std::next(Result->blocks_begin()))), 6);\n\n    EXPECT_EQ(Result->code_blocks_begin()->getOffset(), 3);\n    EXPECT_EQ(std::next(Result->code_blocks_begin())->getOffset(), 6);\n\n    EXPECT_EQ(Result->data_blocks_begin()->getOffset(), 6);\n\n    // Populate the sym exprs now.\n    EXPECT_TRUE(STH::byteIntervalLoadSymbolicExpressions(Ctx, *Result, ss2));\n    EXPECT_EQ(std::distance(Result->symbolic_expressions_begin(),\n                            Result->symbolic_expressions_end()),\n              1);\n\n    EXPECT_EQ(Result->symbolic_expressions_begin()->getByteInterval(), Result);\n    EXPECT_EQ(Result->symbolic_expressions_begin()->getOffset(), 5);\n    EXPECT_TRUE(std::holds_alternative<SymAddrConst>(\n        Result->symbolic_expressions_begin()->getSymbolicExpression()));\n    EXPECT_EQ(std::get<SymAddrConst>(\n                  Result->symbolic_expressions_begin()->getSymbolicExpression())\n                  .Offset,\n              8);\n    EXPECT_EQ(std::get<SymAddrConst>(\n                  Result->symbolic_expressions_begin()->getSymbolicExpression())\n                  .Sym,\n              Sym);\n  }\n}\n\nTEST(Unit_ByteInterval, byteVector) {\n  std::string Contents = \"hello, world!\";\n\n  // Test all allocated bytes.\n  {\n    auto* BI = ByteInterval::Create(Ctx, std::optional<Addr>(),\n                                    Contents.begin(), Contents.end());\n    EXPECT_EQ(BI->getSize(), Contents.size());\n\n    auto OriginalIt = Contents.begin();\n    auto NewIt = BI->bytes_begin<char>();\n    auto OriginalEnd = Contents.end();\n    auto NewEnd = BI->bytes_end<char>();\n\n    while (OriginalIt != OriginalEnd && NewIt != NewEnd) {\n      EXPECT_EQ(*OriginalIt, *NewIt);\n      ++OriginalIt;\n      ++NewIt;\n    }\n    EXPECT_EQ(OriginalIt, OriginalEnd);\n    EXPECT_EQ(NewIt, NewEnd);\n  }\n\n  // Test some unallocated bytes.\n  {\n    auto* BI = ByteInterval::Create(Ctx, std::optional<Addr>(),\n                                    Contents.begin(), Contents.end(), 100);\n    EXPECT_EQ(BI->getSize(), 100);\n\n    auto OriginalIt = Contents.begin();\n    auto NewIt = BI->bytes_begin<char>();\n    auto OriginalEnd = Contents.end();\n    auto NewEnd = BI->bytes_end<char>();\n\n    while (OriginalIt != OriginalEnd && NewIt != NewEnd) {\n      EXPECT_EQ(*OriginalIt, *NewIt);\n      ++OriginalIt;\n      ++NewIt;\n    }\n    EXPECT_EQ(OriginalIt, OriginalEnd);\n    EXPECT_NE(NewIt, NewEnd);\n\n    while (NewIt != NewEnd) {\n      EXPECT_EQ(*NewIt, '\\0');\n      ++NewIt;\n    }\n    EXPECT_EQ(std::distance(BI->bytes_begin<char>(), NewIt), 100);\n  }\n}\n\ntemplate <typename T> static T str2(const char* S) {\n  // TODO: is an endian conversion needed here?\n  return *(const T*)S;\n}\n\nTEST(Unit_ByteInterval, byteVectorInts) {\n  std::string Contents = \"hello, world!!??\";\n  auto* BI = ByteInterval::Create(Ctx, std::optional<Addr>(), Contents.begin(),\n                                  Contents.end());\n  EXPECT_EQ(Contents.size(), 16);\n\n  // 16 bits\n  {\n    std::vector<uint16_t> CompareTo = {\n        str2<uint16_t>(\"he\"), str2<uint16_t>(\"ll\"), str2<uint16_t>(\"o,\"),\n        str2<uint16_t>(\" w\"), str2<uint16_t>(\"or\"), str2<uint16_t>(\"ld\"),\n        str2<uint16_t>(\"!!\"), str2<uint16_t>(\"??\")};\n\n    auto OriginalIt = CompareTo.begin();\n    auto NewIt = BI->bytes_begin<uint16_t>();\n    auto OriginalEnd = CompareTo.end();\n    auto NewEnd = BI->bytes_end<uint16_t>();\n\n    EXPECT_EQ(std::distance(NewIt, NewEnd), 8);\n    while (OriginalIt != OriginalEnd && NewIt != NewEnd) {\n      EXPECT_EQ(*OriginalIt, *NewIt);\n      ++OriginalIt;\n      ++NewIt;\n    }\n    EXPECT_EQ(OriginalIt, OriginalEnd);\n    EXPECT_EQ(NewIt, NewEnd);\n  }\n\n  // 32 bits\n  {\n    std::vector<uint32_t> CompareTo = {\n        str2<uint32_t>(\"hell\"), str2<uint32_t>(\"o, w\"), str2<uint32_t>(\"orld\"),\n        str2<uint32_t>(\"!!??\")};\n\n    auto OriginalIt = CompareTo.begin();\n    auto NewIt = BI->bytes_begin<uint32_t>();\n    auto OriginalEnd = CompareTo.end();\n    auto NewEnd = BI->bytes_end<uint32_t>();\n\n    EXPECT_EQ(std::distance(NewIt, NewEnd), 4);\n    while (OriginalIt != OriginalEnd && NewIt != NewEnd) {\n      EXPECT_EQ(*OriginalIt, *NewIt);\n      ++OriginalIt;\n      ++NewIt;\n    }\n    EXPECT_EQ(OriginalIt, OriginalEnd);\n    EXPECT_EQ(NewIt, NewEnd);\n  }\n\n  // 64 bits\n  {\n    std::vector<uint64_t> CompareTo = {str2<uint64_t>(\"hello, w\"),\n                                       str2<uint64_t>(\"orld!!??\")};\n\n    auto OriginalIt = CompareTo.begin();\n    auto NewIt = BI->bytes_begin<uint64_t>();\n    auto OriginalEnd = CompareTo.end();\n    auto NewEnd = BI->bytes_end<uint64_t>();\n\n    EXPECT_EQ(std::distance(NewIt, NewEnd), 2);\n    while (OriginalIt != OriginalEnd && NewIt != NewEnd) {\n      EXPECT_EQ(*OriginalIt, *NewIt);\n      ++OriginalIt;\n      ++NewIt;\n    }\n    EXPECT_EQ(OriginalIt, OriginalEnd);\n    EXPECT_EQ(NewIt, NewEnd);\n  }\n}\n\nTEST(Unit_ByteInterval, byteVectorEndian) {\n  std::string Contents = \"hello, world!!??\";\n  auto* BI = ByteInterval::Create(Ctx, std::optional<Addr>(), Contents.begin(),\n                                  Contents.end());\n  EXPECT_EQ(Contents.size(), 16);\n\n  // Test using little endian.\n  {\n    std::vector<uint16_t> CompareTo = {\n        str2<uint16_t>(\"he\"), str2<uint16_t>(\"ll\"), str2<uint16_t>(\"o,\"),\n        str2<uint16_t>(\" w\"), str2<uint16_t>(\"or\"), str2<uint16_t>(\"ld\"),\n        str2<uint16_t>(\"!!\"), str2<uint16_t>(\"??\")};\n\n    auto OriginalIt = CompareTo.begin();\n    auto NewIt = BI->bytes_begin<uint16_t>(boost::endian::order::little);\n    auto OriginalEnd = CompareTo.end();\n    auto NewEnd = BI->bytes_end<uint16_t>(boost::endian::order::little);\n\n    EXPECT_EQ(std::distance(NewIt, NewEnd), 8);\n    while (OriginalIt != OriginalEnd && NewIt != NewEnd) {\n      EXPECT_EQ(*OriginalIt, *NewIt);\n      ++OriginalIt;\n      ++NewIt;\n    }\n    EXPECT_EQ(OriginalIt, OriginalEnd);\n    EXPECT_EQ(NewIt, NewEnd);\n  }\n\n  // Test using big endian.\n  {\n    std::vector<uint16_t> CompareTo = {\n        str2<uint16_t>(\"eh\"), str2<uint16_t>(\"ll\"), str2<uint16_t>(\",o\"),\n        str2<uint16_t>(\"w \"), str2<uint16_t>(\"ro\"), str2<uint16_t>(\"dl\"),\n        str2<uint16_t>(\"!!\"), str2<uint16_t>(\"??\")};\n\n    auto OriginalIt = CompareTo.begin();\n    auto NewIt = BI->bytes_begin<uint16_t>(boost::endian::order::big);\n    auto OriginalEnd = CompareTo.end();\n    auto NewEnd = BI->bytes_end<uint16_t>(boost::endian::order::big);\n\n    EXPECT_EQ(std::distance(NewIt, NewEnd), 8);\n    while (OriginalIt != OriginalEnd && NewIt != NewEnd) {\n      EXPECT_EQ(*OriginalIt, *NewIt);\n      ++OriginalIt;\n      ++NewIt;\n    }\n    EXPECT_EQ(OriginalIt, OriginalEnd);\n    EXPECT_EQ(NewIt, NewEnd);\n  }\n}\n\nTEST(Unit_ByteInterval, byteVectorInsert) {\n  std::string Contents = \"0123456789\";\n  auto* BI = ByteInterval::Create(Ctx, std::optional<Addr>(), Contents.begin(),\n                                  Contents.end());\n  {\n    char charInsert = 'd';\n    BI->insertBytes<char>(BI->bytes_begin<char>(), charInsert);\n    const gtirb::ByteInterval& CBI(*BI);\n    BI->insertBytes(CBI.bytes_begin<char>(), charInsert);\n    std::string toInsert = \"abc\";\n    BI->insertBytes<char>(BI->bytes_begin<char>(), toInsert.begin(),\n                          toInsert.end());\n    std::string Result;\n    std::copy(BI->bytes_begin<char>(), BI->bytes_end<char>(),\n              std::back_inserter(Result));\n    ASSERT_EQ(Result, \"abcdd0123456789\");\n  }\n\n  {\n    std::string toInsert = \"efg\";\n    BI->insertBytes<char>(BI->bytes_begin<char>() + 7, toInsert.begin(),\n                          toInsert.end());\n    std::string Result;\n    std::copy(BI->bytes_begin<char>(), BI->bytes_end<char>(),\n              std::back_inserter(Result));\n    ASSERT_EQ(Result, \"abcdd01efg23456789\");\n  }\n\n  {\n    std::string toInsert = \"hi\";\n    BI->insertBytes<char>(BI->bytes_end<char>(), toInsert.begin(),\n                          toInsert.end());\n    std::string Result;\n    std::copy(BI->bytes_begin<char>(), BI->bytes_end<char>(),\n              std::back_inserter(Result));\n    ASSERT_EQ(Result, \"abcdd01efg23456789hi\");\n  }\n\n  // Test with larger, non-char values.\n  {\n    std::vector<uint32_t> toInsert = {str2<uint32_t>(\"(hel\"),\n                                      str2<uint32_t>(\"lo.)\")};\n    BI->insertBytes<uint32_t>(BI->bytes_begin<uint32_t>() + 1, toInsert.begin(),\n                              toInsert.end());\n    std::string Result;\n    std::copy(BI->bytes_begin<char>(), BI->bytes_end<char>(),\n              std::back_inserter(Result));\n    ASSERT_EQ(Result, \"abcd(hello.)d01efg23456789hi\");\n  }\n}\n\nTEST(Unit_ByteInterval, byteVectorErase) {\n  std::string Contents = \"0123456789\";\n  auto* BI = ByteInterval::Create(Ctx, std::optional<Addr>(), Contents.begin(),\n                                  Contents.end());\n\n  {\n    BI->eraseBytes<char>(BI->bytes_begin<char>(), BI->bytes_begin<char>() + 2);\n    std::string Result;\n    std::copy(BI->bytes_begin<char>(), BI->bytes_end<char>(),\n              std::back_inserter(Result));\n    ASSERT_EQ(Result, \"23456789\");\n  }\n\n  {\n    BI->eraseBytes<char>(BI->bytes_begin<char>() + 4,\n                         BI->bytes_begin<char>() + 5);\n    std::string Result;\n    std::copy(BI->bytes_begin<char>(), BI->bytes_end<char>(),\n              std::back_inserter(Result));\n    ASSERT_EQ(Result, \"2345789\");\n  }\n\n  {\n    BI->eraseBytes<char>(BI->bytes_begin<char>() + 6, BI->bytes_end<char>());\n    std::string Result;\n    std::copy(BI->bytes_begin<char>(), BI->bytes_end<char>(),\n              std::back_inserter(Result));\n    ASSERT_EQ(Result, \"234578\");\n  }\n\n  // Test larger value types.\n  {\n    BI->eraseBytes<uint16_t>(BI->bytes_begin<uint16_t>() + 1,\n                             BI->bytes_begin<uint16_t>() + 2);\n    std::string Result;\n    std::copy(BI->bytes_begin<char>(), BI->bytes_end<char>(),\n              std::back_inserter(Result));\n    ASSERT_EQ(Result, \"2378\");\n  }\n\n  // Test clearing the bytes.\n  {\n    BI->eraseBytes<uint32_t>(BI->bytes_begin<uint32_t>(),\n                             BI->bytes_end<uint32_t>());\n    std::string Result;\n    std::copy(BI->bytes_begin<char>(), BI->bytes_end<char>(),\n              std::back_inserter(Result));\n    ASSERT_EQ(Result, \"\");\n  }\n}\n\nTEST(Unit_ByteInterval, removeBlock) {\n  auto* BI = ByteInterval::Create(Ctx, Addr(0), 10);\n\n  auto* B1 = BI->addBlock<CodeBlock>(Ctx, 0, 1);\n  auto* B2 = BI->addBlock<DataBlock>(Ctx, 1, 1);\n  auto* B3 = BI->addBlock<CodeBlock>(Ctx, 2, 1);\n  auto* B4 = BI->addBlock<DataBlock>(Ctx, 3, 1);\n\n  {\n    auto Begin = BI->code_blocks_begin(), End = BI->code_blocks_end();\n    ASSERT_EQ(std::distance(Begin, End), 2);\n    ASSERT_NE(std::find_if(Begin, End, [&](const auto& N) { return B1 == &N; }),\n              End);\n    ASSERT_NE(std::find_if(Begin, End, [&](const auto& N) { return B3 == &N; }),\n              End);\n  }\n\n  {\n    auto Begin = BI->data_blocks_begin(), End = BI->data_blocks_end();\n    ASSERT_EQ(std::distance(Begin, End), 2);\n    ASSERT_NE(std::find_if(Begin, End, [&](const auto& N) { return B2 == &N; }),\n              End);\n    ASSERT_NE(std::find_if(Begin, End, [&](const auto& N) { return B4 == &N; }),\n              End);\n  }\n\n  BI->removeBlock(B1);\n\n  {\n    auto Begin = BI->code_blocks_begin(), End = BI->code_blocks_end();\n    ASSERT_EQ(std::distance(Begin, End), 1);\n    ASSERT_NE(std::find_if(Begin, End, [&](const auto& N) { return B3 == &N; }),\n              End);\n  }\n\n  {\n    auto Begin = BI->data_blocks_begin(), End = BI->data_blocks_end();\n    ASSERT_EQ(std::distance(Begin, End), 2);\n    ASSERT_NE(std::find_if(Begin, End, [&](const auto& N) { return B2 == &N; }),\n              End);\n    ASSERT_NE(std::find_if(Begin, End, [&](const auto& N) { return B4 == &N; }),\n              End);\n  }\n\n  BI->removeBlock(B2);\n\n  {\n    auto Begin = BI->code_blocks_begin(), End = BI->code_blocks_end();\n    ASSERT_EQ(std::distance(Begin, End), 1);\n    ASSERT_NE(std::find_if(Begin, End, [&](const auto& N) { return B3 == &N; }),\n              End);\n  }\n\n  {\n    auto Begin = BI->data_blocks_begin(), End = BI->data_blocks_end();\n    ASSERT_EQ(std::distance(Begin, End), 1);\n    ASSERT_NE(std::find_if(Begin, End, [&](const auto& N) { return B4 == &N; }),\n              End);\n  }\n}\n\nTEST(Unit_ByteInterval, addSymbolicExpression) {\n  auto* BI = ByteInterval::Create(Ctx, std::optional<Addr>(), 10);\n  auto* S = Symbol::Create(Ctx, \"test\");\n\n  {\n    auto& SE = BI->addSymbolicExpression(0, SymAddrConst{1, S});\n    ASSERT_TRUE(std::holds_alternative<SymAddrConst>(SE));\n    ASSERT_EQ(std::get<SymAddrConst>(SE).Offset, 1);\n    ASSERT_EQ(std::get<SymAddrConst>(SE).Sym, S);\n  }\n\n  {\n    auto& SE = BI->addSymbolicExpression(1, SymAddrAddr{3, 4, S, S});\n    ASSERT_TRUE(std::holds_alternative<SymAddrAddr>(SE));\n    ASSERT_EQ(std::get<SymAddrAddr>(SE).Scale, 3);\n    ASSERT_EQ(std::get<SymAddrAddr>(SE).Offset, 4);\n    ASSERT_EQ(std::get<SymAddrAddr>(SE).Sym1, S);\n    ASSERT_EQ(std::get<SymAddrAddr>(SE).Sym2, S);\n  }\n\n  {\n    auto& SE = BI->addSymbolicExpression(2, SymAddrConst{4, S});\n    ASSERT_TRUE(std::holds_alternative<SymAddrConst>(SE));\n    ASSERT_EQ(std::get<SymAddrConst>(SE).Offset, 4);\n    ASSERT_EQ(std::get<SymAddrConst>(SE).Sym, S);\n  }\n\n  {\n    auto& SE = BI->addSymbolicExpression(3, SymAddrAddr{6, 7, S, S});\n    ASSERT_TRUE(std::holds_alternative<SymAddrAddr>(SE));\n    ASSERT_EQ(std::get<SymAddrAddr>(SE).Scale, 6);\n    ASSERT_EQ(std::get<SymAddrAddr>(SE).Offset, 7);\n    ASSERT_EQ(std::get<SymAddrAddr>(SE).Sym1, S);\n    ASSERT_EQ(std::get<SymAddrAddr>(SE).Sym2, S);\n  }\n\n  {\n    auto Range = BI->symbolic_expressions();\n    ASSERT_EQ(std::distance(Range.begin(), Range.end()), 4);\n    for (uint64_t i = 0; i < 4; ++i)\n      EXPECT_EQ(std::next(Range.begin(), i)->getOffset(), i);\n  }\n}\n\nTEST(Unit_ByteInterval, updateSymbolicExpression) {\n  auto* BI = ByteInterval::Create(Ctx, std::optional<Addr>(), 10);\n  auto* S = Symbol::Create(Ctx, \"test\");\n  BI->addSymbolicExpression(0, SymAddrConst{1, S});\n\n  auto& SE = BI->addSymbolicExpression(0, SymAddrConst{2, S});\n  ASSERT_TRUE(std::holds_alternative<SymAddrConst>(SE));\n  ASSERT_EQ(std::get<SymAddrConst>(SE).Offset, 2);\n}\n\nTEST(Unit_ByteInterval, findSymbolicExpressionsAtOffset) {\n  auto* BI = ByteInterval::Create(Ctx, 10);\n  auto* S1 = Symbol::Create(Ctx, \"A\");\n  BI->addSymbolicExpression(2, SymAddrConst{0, S1});\n\n  auto Range = BI->findSymbolicExpressionsAtOffset(2);\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 1);\n\n  auto FoundSymbolicExpressionElement = Range.front();\n  const SymbolicExpression* SE =\n      &FoundSymbolicExpressionElement.getSymbolicExpression();\n  ASSERT_TRUE(std::holds_alternative<SymAddrConst>(*SE));\n  EXPECT_EQ(std::get<SymAddrConst>(*SE).Offset, 0);\n  EXPECT_EQ(std::get<SymAddrConst>(*SE).Sym, S1);\n\n  Range = BI->findSymbolicExpressionsAtOffset(4);\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 0);\n\n  Range = BI->findSymbolicExpressionsAtOffset(6);\n  ASSERT_TRUE(Range.empty());\n\n  Range = BI->findSymbolicExpressionsAtOffset(0, 10);\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 1);\n\n  FoundSymbolicExpressionElement = Range.front();\n  SE = &FoundSymbolicExpressionElement.getSymbolicExpression();\n  ASSERT_TRUE(std::holds_alternative<SymAddrConst>(*SE));\n  EXPECT_EQ(std::get<SymAddrConst>(*SE).Sym, S1);\n}\n\nTEST(Unit_ByteInterval, removeSymbolicExpression) {\n  auto* BI = ByteInterval::Create(Ctx, 10);\n  auto* S = Symbol::Create(Ctx, \"test\");\n  BI->addSymbolicExpression(5, SymAddrConst{0, S});\n\n  ASSERT_FALSE(BI->symbolic_expressions().empty());\n\n  BI->removeSymbolicExpression(5);\n\n  EXPECT_TRUE(BI->symbolic_expressions().empty());\n}\n\nTEST(Unit_ByteInterval, findBlocksOn) {\n  auto* BI = ByteInterval::Create(Ctx, 10);\n  auto* B1 = BI->addBlock<CodeBlock>(Ctx, 0, 2);\n  auto* B2 = BI->addBlock<CodeBlock>(Ctx, 5, 3);\n  const ByteInterval* CBI = BI;\n\n  // Querying an out-of-bounds offset produces an empty range.\n\n  auto BlockOffsetRange = BI->findBlocksOnOffset(10);\n  EXPECT_TRUE(BlockOffsetRange.empty());\n\n  auto ConstBlockOffsetRange = CBI->findBlocksOnOffset(10);\n  EXPECT_TRUE(ConstBlockOffsetRange.empty());\n\n  // Querying an in-bounds offset returns the appropriate block.\n\n  BlockOffsetRange = BI->findBlocksOnOffset(6);\n  ASSERT_EQ(std::distance(BlockOffsetRange.begin(), BlockOffsetRange.end()), 1);\n  EXPECT_EQ(&*BlockOffsetRange.begin(), B2);\n\n  ConstBlockOffsetRange = CBI->findBlocksOnOffset(6);\n  ASSERT_EQ(\n      std::distance(ConstBlockOffsetRange.begin(), ConstBlockOffsetRange.end()),\n      1);\n  EXPECT_EQ(&*ConstBlockOffsetRange.begin(), B2);\n\n  // Address queries produce empty ranges if the ByteInterval has no address.\n\n  auto BlockAddrRange = BI->findBlocksOn(Addr(6));\n  EXPECT_TRUE(BlockAddrRange.empty());\n\n  auto ConstBlockAddrRange = CBI->findBlocksOn(Addr(6));\n  EXPECT_TRUE(ConstBlockAddrRange.empty());\n\n  // Once the ByteInterval has an address, address queries are non-empty.\n\n  BI->setAddress(Addr(0));\n  BlockAddrRange = BI->findBlocksOn(Addr(6));\n  ASSERT_EQ(std::distance(BlockAddrRange.begin(), BlockAddrRange.end()), 1);\n  EXPECT_EQ(&*BlockAddrRange.begin(), B2);\n\n  ConstBlockAddrRange = CBI->findBlocksOn(Addr(6));\n  ASSERT_EQ(\n      std::distance(ConstBlockAddrRange.begin(), ConstBlockAddrRange.end()), 1);\n  EXPECT_EQ(&*ConstBlockAddrRange.begin(), B2);\n\n  // If the address changes, the returned blocks may change.\n\n  BI->setAddress(Addr(5));\n  BlockAddrRange = BI->findBlocksOn(Addr(6));\n  ASSERT_EQ(std::distance(BlockAddrRange.begin(), BlockAddrRange.end()), 1);\n  EXPECT_EQ(&*BlockAddrRange.begin(), B1);\n\n  ConstBlockAddrRange = CBI->findBlocksOn(Addr(6));\n  ASSERT_EQ(\n      std::distance(ConstBlockAddrRange.begin(), ConstBlockAddrRange.end()), 1);\n  EXPECT_EQ(&*ConstBlockAddrRange.begin(), B1);\n\n  // Querying offsets is not affected by address changes.\n\n  BlockOffsetRange = BI->findBlocksOnOffset(6);\n  ASSERT_EQ(std::distance(BlockOffsetRange.begin(), BlockOffsetRange.end()), 1);\n  EXPECT_EQ(&*BlockOffsetRange.begin(), B2);\n\n  ConstBlockOffsetRange = CBI->findBlocksOnOffset(6);\n  ASSERT_EQ(\n      std::distance(ConstBlockOffsetRange.begin(), ConstBlockOffsetRange.end()),\n      1);\n  EXPECT_EQ(&*ConstBlockOffsetRange.begin(), B2);\n\n  // If the block size changes, queries will be affected.\n\n  B1->setSize(10);\n\n  BlockOffsetRange = BI->findBlocksOnOffset(6);\n  ASSERT_EQ(std::distance(BlockOffsetRange.begin(), BlockOffsetRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockOffsetRange.begin(), 0), B1);\n  EXPECT_EQ(&*std::next(BlockOffsetRange.begin(), 1), B2);\n\n  ConstBlockOffsetRange = CBI->findBlocksOnOffset(6);\n  ASSERT_EQ(\n      std::distance(ConstBlockOffsetRange.begin(), ConstBlockOffsetRange.end()),\n      2);\n  EXPECT_EQ(&*std::next(ConstBlockOffsetRange.begin(), 0), B1);\n  EXPECT_EQ(&*std::next(ConstBlockOffsetRange.begin(), 1), B2);\n}\n\nTEST(Unit_ByteInterval, findCodeBlocksOn) {\n  auto* BI = ByteInterval::Create(Ctx, 10);\n  auto* B1 = BI->addBlock<CodeBlock>(Ctx, 0, 2);\n  auto* B2 = BI->addBlock<CodeBlock>(Ctx, 5, 3);\n  const ByteInterval* CBI = BI;\n\n  // Querying an out-of-bounds offset produces an empty range.\n\n  auto BlockOffsetRange = BI->findCodeBlocksOnOffset(10);\n  EXPECT_TRUE(BlockOffsetRange.empty());\n\n  auto ConstBlockOffsetRange = CBI->findCodeBlocksOnOffset(10);\n  EXPECT_TRUE(ConstBlockOffsetRange.empty());\n\n  // Querying an in-bounds offset returns the appropriate block.\n\n  BlockOffsetRange = BI->findCodeBlocksOnOffset(6);\n  ASSERT_EQ(std::distance(BlockOffsetRange.begin(), BlockOffsetRange.end()), 1);\n  EXPECT_EQ(&*BlockOffsetRange.begin(), B2);\n\n  ConstBlockOffsetRange = CBI->findCodeBlocksOnOffset(6);\n  ASSERT_EQ(\n      std::distance(ConstBlockOffsetRange.begin(), ConstBlockOffsetRange.end()),\n      1);\n  EXPECT_EQ(&*ConstBlockOffsetRange.begin(), B2);\n\n  // Address queries produce empty ranges if the ByteInterval has no address.\n\n  auto BlockAddrRange = BI->findCodeBlocksOn(Addr(6));\n  EXPECT_TRUE(BlockAddrRange.empty());\n\n  auto ConstBlockAddrRange = CBI->findCodeBlocksOn(Addr(6));\n  EXPECT_TRUE(ConstBlockAddrRange.empty());\n\n  // Once the ByteInterval has an address, address queries are non-empty.\n\n  BI->setAddress(Addr(0));\n  BlockAddrRange = BI->findCodeBlocksOn(Addr(6));\n  ASSERT_EQ(std::distance(BlockAddrRange.begin(), BlockAddrRange.end()), 1);\n  EXPECT_EQ(&*BlockAddrRange.begin(), B2);\n\n  ConstBlockAddrRange = CBI->findCodeBlocksOn(Addr(6));\n  ASSERT_EQ(\n      std::distance(ConstBlockAddrRange.begin(), ConstBlockAddrRange.end()), 1);\n  EXPECT_EQ(&*ConstBlockAddrRange.begin(), B2);\n\n  // If the address changes, the returned blocks may change.\n\n  BI->setAddress(Addr(5));\n  BlockAddrRange = BI->findCodeBlocksOn(Addr(6));\n  ASSERT_EQ(std::distance(BlockAddrRange.begin(), BlockAddrRange.end()), 1);\n  EXPECT_EQ(&*BlockAddrRange.begin(), B1);\n\n  ConstBlockAddrRange = CBI->findCodeBlocksOn(Addr(6));\n  ASSERT_EQ(\n      std::distance(ConstBlockAddrRange.begin(), ConstBlockAddrRange.end()), 1);\n  EXPECT_EQ(&*ConstBlockAddrRange.begin(), B1);\n\n  // Querying offsets is not affected by address changes.\n\n  BlockOffsetRange = BI->findCodeBlocksOnOffset(6);\n  ASSERT_EQ(std::distance(BlockOffsetRange.begin(), BlockOffsetRange.end()), 1);\n  EXPECT_EQ(&*BlockOffsetRange.begin(), B2);\n\n  ConstBlockOffsetRange = CBI->findCodeBlocksOnOffset(6);\n  ASSERT_EQ(\n      std::distance(ConstBlockOffsetRange.begin(), ConstBlockOffsetRange.end()),\n      1);\n  EXPECT_EQ(&*ConstBlockOffsetRange.begin(), B2);\n\n  // If the block size changes, queries will be affected.\n\n  B1->setSize(10);\n\n  BlockOffsetRange = BI->findCodeBlocksOnOffset(6);\n  ASSERT_EQ(std::distance(BlockOffsetRange.begin(), BlockOffsetRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockOffsetRange.begin(), 0), B1);\n  EXPECT_EQ(&*std::next(BlockOffsetRange.begin(), 1), B2);\n\n  ConstBlockOffsetRange = CBI->findCodeBlocksOnOffset(6);\n  ASSERT_EQ(\n      std::distance(ConstBlockOffsetRange.begin(), ConstBlockOffsetRange.end()),\n      2);\n  EXPECT_EQ(&*std::next(ConstBlockOffsetRange.begin(), 0), B1);\n  EXPECT_EQ(&*std::next(ConstBlockOffsetRange.begin(), 1), B2);\n}\n\nTEST(Unit_ByteInterval, findDataBlocksOn) {\n  auto* BI = ByteInterval::Create(Ctx, 10);\n  auto* B1 = BI->addBlock<DataBlock>(Ctx, 0, 2);\n  auto* B2 = BI->addBlock<DataBlock>(Ctx, 5, 3);\n  const ByteInterval* CBI = BI;\n\n  // Querying an out-of-bounds offset produces an empty range.\n\n  auto BlockOffsetRange = BI->findDataBlocksOnOffset(10);\n  EXPECT_TRUE(BlockOffsetRange.empty());\n\n  auto ConstBlockOffsetRange = CBI->findDataBlocksOnOffset(10);\n  EXPECT_TRUE(ConstBlockOffsetRange.empty());\n\n  // Querying an in-bounds offset returns the appropriate block.\n\n  BlockOffsetRange = BI->findDataBlocksOnOffset(6);\n  ASSERT_EQ(std::distance(BlockOffsetRange.begin(), BlockOffsetRange.end()), 1);\n  EXPECT_EQ(&*BlockOffsetRange.begin(), B2);\n\n  ConstBlockOffsetRange = CBI->findDataBlocksOnOffset(6);\n  ASSERT_EQ(\n      std::distance(ConstBlockOffsetRange.begin(), ConstBlockOffsetRange.end()),\n      1);\n  EXPECT_EQ(&*ConstBlockOffsetRange.begin(), B2);\n\n  // Address queries produce empty ranges if the ByteInterval has no address.\n\n  auto BlockAddrRange = BI->findDataBlocksOn(Addr(6));\n  EXPECT_TRUE(BlockAddrRange.empty());\n\n  auto ConstBlockAddrRange = CBI->findDataBlocksOn(Addr(6));\n  EXPECT_TRUE(ConstBlockAddrRange.empty());\n\n  // Once the ByteInterval has an address, address queries are non-empty.\n\n  BI->setAddress(Addr(0));\n  BlockAddrRange = BI->findDataBlocksOn(Addr(6));\n  ASSERT_EQ(std::distance(BlockAddrRange.begin(), BlockAddrRange.end()), 1);\n  EXPECT_EQ(&*BlockAddrRange.begin(), B2);\n\n  ConstBlockAddrRange = CBI->findDataBlocksOn(Addr(6));\n  ASSERT_EQ(\n      std::distance(ConstBlockAddrRange.begin(), ConstBlockAddrRange.end()), 1);\n  EXPECT_EQ(&*ConstBlockAddrRange.begin(), B2);\n\n  // If the address changes, the returned blocks may change.\n\n  BI->setAddress(Addr(5));\n  BlockAddrRange = BI->findDataBlocksOn(Addr(6));\n  ASSERT_EQ(std::distance(BlockAddrRange.begin(), BlockAddrRange.end()), 1);\n  EXPECT_EQ(&*BlockAddrRange.begin(), B1);\n\n  ConstBlockAddrRange = CBI->findDataBlocksOn(Addr(6));\n  ASSERT_EQ(\n      std::distance(ConstBlockAddrRange.begin(), ConstBlockAddrRange.end()), 1);\n  EXPECT_EQ(&*ConstBlockAddrRange.begin(), B1);\n\n  // Querying offsets is not affected by address changes.\n\n  BlockOffsetRange = BI->findDataBlocksOnOffset(6);\n  ASSERT_EQ(std::distance(BlockOffsetRange.begin(), BlockOffsetRange.end()), 1);\n  EXPECT_EQ(&*BlockOffsetRange.begin(), B2);\n\n  ConstBlockOffsetRange = CBI->findDataBlocksOnOffset(6);\n  ASSERT_EQ(\n      std::distance(ConstBlockOffsetRange.begin(), ConstBlockOffsetRange.end()),\n      1);\n  EXPECT_EQ(&*ConstBlockOffsetRange.begin(), B2);\n\n  // If the block size changes, queries will be affected.\n\n  B1->setSize(10);\n\n  BlockOffsetRange = BI->findDataBlocksOnOffset(6);\n  ASSERT_EQ(std::distance(BlockOffsetRange.begin(), BlockOffsetRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockOffsetRange.begin(), 0), B1);\n  EXPECT_EQ(&*std::next(BlockOffsetRange.begin(), 1), B2);\n\n  ConstBlockOffsetRange = CBI->findDataBlocksOnOffset(6);\n  ASSERT_EQ(\n      std::distance(ConstBlockOffsetRange.begin(), ConstBlockOffsetRange.end()),\n      2);\n  EXPECT_EQ(&*std::next(ConstBlockOffsetRange.begin(), 0), B1);\n  EXPECT_EQ(&*std::next(ConstBlockOffsetRange.begin(), 1), B2);\n}\n\nTEST(Unit_ByteInterval, findBlocksAt) {\n  auto* BI = ByteInterval::Create(Ctx, 10);\n  auto* B1 = BI->addBlock<CodeBlock>(Ctx, 0, 2);\n  auto* B2 = BI->addBlock<CodeBlock>(Ctx, 5, 3);\n  const ByteInterval* CBI = BI;\n\n  // Methods return empty ranges if ByteInterval has no address.\n\n  auto BlockRange = BI->findBlocksAt(Addr(0));\n  EXPECT_TRUE(BlockRange.empty());\n\n  auto ConstBlockRange = CBI->findBlocksAt(Addr(0));\n  EXPECT_TRUE(ConstBlockRange.empty());\n\n  BlockRange =\n      BI->findBlocksAt(Addr(0), Addr(static_cast<Addr::value_type>(-1)));\n  EXPECT_TRUE(BlockRange.empty());\n\n  ConstBlockRange =\n      CBI->findBlocksAt(Addr(0), Addr(static_cast<Addr::value_type>(-1)));\n  EXPECT_TRUE(BlockRange.empty());\n\n  // Once the address is set, the ranges are no longer empty.\n\n  BI->setAddress(Addr(0));\n  BlockRange = BI->findBlocksAt(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 1);\n  EXPECT_EQ(&*BlockRange.begin(), B2);\n\n  ConstBlockRange = CBI->findBlocksAt(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 1);\n  EXPECT_EQ(&*ConstBlockRange.begin(), B2);\n\n  // Changing the ByteInterval address changes which blocks are found.\n\n  BI->setAddress(Addr(5));\n  BlockRange = BI->findBlocksAt(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 1);\n  EXPECT_EQ(&*BlockRange.begin(), B1);\n\n  ConstBlockRange = CBI->findBlocksAt(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 1);\n  EXPECT_EQ(&*ConstBlockRange.begin(), B1);\n\n  // Method returns empty range if no block starts at address.\n\n  EXPECT_TRUE(BI->findBlocksAt(Addr(0)).empty());\n  EXPECT_TRUE(BI->findBlocksAt(Addr(7)).empty());\n  EXPECT_TRUE(BI->findBlocksAt(Addr(15)).empty());\n\n  EXPECT_TRUE(CBI->findBlocksAt(Addr(0)).empty());\n  EXPECT_TRUE(CBI->findBlocksAt(Addr(7)).empty());\n  EXPECT_TRUE(CBI->findBlocksAt(Addr(15)).empty());\n\n  // Querying a range of addreses that start before and/or ends after the\n  // ByteInterval is equivalent to querying the ByteInterval's bounds.\n\n  BlockRange = BI->findBlocksAt(Addr(0), Addr(20));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(pointers(BlockRange),\n            pointers(BI->findBlocksAt(*BI->getAddress(),\n                                      *BI->getAddress() + BI->getSize())));\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), B1);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), B2);\n\n  ConstBlockRange = CBI->findBlocksAt(Addr(0), Addr(20));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(pointers(ConstBlockRange),\n            pointers(CBI->findBlocksAt(*BI->getAddress(),\n                                       *BI->getAddress() + BI->getSize())));\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), B1);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), B2);\n\n  // Order matters: querying an empty range produces an empty result.\n\n  BlockRange = BI->findBlocksAt(Addr(20), Addr(0));\n  EXPECT_TRUE(BlockRange.empty());\n\n  ConstBlockRange = CBI->findBlocksAt(Addr(20), Addr(0));\n  EXPECT_TRUE(ConstBlockRange.empty());\n}\n\nTEST(Unit_ByteInterval, findCodeBlocksAt) {\n  auto* BI = ByteInterval::Create(Ctx, 10);\n  auto* B1 = BI->addBlock<CodeBlock>(Ctx, 0, 2);\n  auto* B2 = BI->addBlock<CodeBlock>(Ctx, 5, 3);\n  const ByteInterval* CBI = BI;\n\n  // Methods return empty ranges if ByteInterval has no address.\n\n  auto BlockRange = BI->findCodeBlocksAt(Addr(0));\n  EXPECT_TRUE(BlockRange.empty());\n\n  auto ConstBlockRange = CBI->findCodeBlocksAt(Addr(0));\n  EXPECT_TRUE(ConstBlockRange.empty());\n\n  BlockRange =\n      BI->findCodeBlocksAt(Addr(0), Addr(static_cast<Addr::value_type>(-1)));\n  EXPECT_TRUE(BlockRange.empty());\n\n  ConstBlockRange =\n      CBI->findCodeBlocksAt(Addr(0), Addr(static_cast<Addr::value_type>(-1)));\n  EXPECT_TRUE(BlockRange.empty());\n\n  // Once the address is set, the ranges are no longer empty.\n\n  BI->setAddress(Addr(0));\n  BlockRange = BI->findCodeBlocksAt(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 1);\n  EXPECT_EQ(&*BlockRange.begin(), B2);\n\n  ConstBlockRange = CBI->findCodeBlocksAt(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 1);\n  EXPECT_EQ(&*ConstBlockRange.begin(), B2);\n\n  // Changing the ByteInterval address changes which blocks are found.\n\n  BI->setAddress(Addr(5));\n  BlockRange = BI->findCodeBlocksAt(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 1);\n  EXPECT_EQ(&*BlockRange.begin(), B1);\n\n  ConstBlockRange = CBI->findCodeBlocksAt(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 1);\n  EXPECT_EQ(&*ConstBlockRange.begin(), B1);\n\n  // Method returns empty range if no block starts at address.\n\n  EXPECT_TRUE(BI->findCodeBlocksAt(Addr(0)).empty());\n  EXPECT_TRUE(BI->findCodeBlocksAt(Addr(7)).empty());\n  EXPECT_TRUE(BI->findCodeBlocksAt(Addr(15)).empty());\n\n  EXPECT_TRUE(CBI->findCodeBlocksAt(Addr(0)).empty());\n  EXPECT_TRUE(CBI->findCodeBlocksAt(Addr(7)).empty());\n  EXPECT_TRUE(CBI->findCodeBlocksAt(Addr(15)).empty());\n\n  // Querying a range of addreses that start before and/or ends after the\n  // ByteInterval is equivalent to querying the ByteInterval's bounds.\n\n  BlockRange = BI->findCodeBlocksAt(Addr(0), Addr(20));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(pointers(BlockRange),\n            pointers(BI->findCodeBlocksAt(*BI->getAddress(),\n                                          *BI->getAddress() + BI->getSize())));\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), B1);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), B2);\n\n  ConstBlockRange = CBI->findCodeBlocksAt(Addr(0), Addr(20));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(pointers(ConstBlockRange),\n            pointers(CBI->findCodeBlocksAt(*BI->getAddress(),\n                                           *BI->getAddress() + BI->getSize())));\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), B1);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), B2);\n\n  // Order matters: querying an empty range produces an empty result.\n\n  BlockRange = BI->findCodeBlocksAt(Addr(20), Addr(0));\n  EXPECT_TRUE(BlockRange.empty());\n\n  ConstBlockRange = CBI->findCodeBlocksAt(Addr(20), Addr(0));\n  EXPECT_TRUE(ConstBlockRange.empty());\n}\n\nTEST(Unit_ByteInterval, findDataBlocksAt) {\n  auto* BI = ByteInterval::Create(Ctx, 10);\n  auto* B1 = BI->addBlock<DataBlock>(Ctx, 0, 2);\n  auto* B2 = BI->addBlock<DataBlock>(Ctx, 5, 3);\n  const ByteInterval* CBI = BI;\n\n  // Methods return empty ranges if ByteInterval has no address.\n\n  auto BlockRange = BI->findDataBlocksAt(Addr(0));\n  EXPECT_TRUE(BlockRange.empty());\n\n  auto ConstBlockRange = CBI->findDataBlocksAt(Addr(0));\n  EXPECT_TRUE(ConstBlockRange.empty());\n\n  BlockRange =\n      BI->findDataBlocksAt(Addr(0), Addr(static_cast<Addr::value_type>(-1)));\n  EXPECT_TRUE(BlockRange.empty());\n\n  ConstBlockRange =\n      CBI->findDataBlocksAt(Addr(0), Addr(static_cast<Addr::value_type>(-1)));\n  EXPECT_TRUE(BlockRange.empty());\n\n  // Once the address is set, the ranges are no longer empty.\n\n  BI->setAddress(Addr(0));\n  BlockRange = BI->findDataBlocksAt(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 1);\n  EXPECT_EQ(&*BlockRange.begin(), B2);\n\n  ConstBlockRange = CBI->findDataBlocksAt(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 1);\n  EXPECT_EQ(&*ConstBlockRange.begin(), B2);\n\n  // Changing the ByteInterval address changes which blocks are found.\n\n  BI->setAddress(Addr(5));\n  BlockRange = BI->findDataBlocksAt(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 1);\n  EXPECT_EQ(&*BlockRange.begin(), B1);\n\n  ConstBlockRange = CBI->findDataBlocksAt(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 1);\n  EXPECT_EQ(&*ConstBlockRange.begin(), B1);\n\n  // Method returns empty range if no block starts at address.\n\n  EXPECT_TRUE(BI->findDataBlocksAt(Addr(0)).empty());\n  EXPECT_TRUE(BI->findDataBlocksAt(Addr(7)).empty());\n  EXPECT_TRUE(BI->findDataBlocksAt(Addr(15)).empty());\n\n  EXPECT_TRUE(CBI->findDataBlocksAt(Addr(0)).empty());\n  EXPECT_TRUE(CBI->findDataBlocksAt(Addr(7)).empty());\n  EXPECT_TRUE(CBI->findDataBlocksAt(Addr(15)).empty());\n\n  // Querying a range of addreses that start before and/or ends after the\n  // ByteInterval is equivalent to querying the ByteInterval's bounds.\n\n  BlockRange = BI->findDataBlocksAt(Addr(0), Addr(20));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(pointers(BlockRange),\n            pointers(BI->findDataBlocksAt(*BI->getAddress(),\n                                          *BI->getAddress() + BI->getSize())));\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), B1);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), B2);\n\n  ConstBlockRange = CBI->findDataBlocksAt(Addr(0), Addr(20));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(pointers(ConstBlockRange),\n            pointers(CBI->findDataBlocksAt(*BI->getAddress(),\n                                           *BI->getAddress() + BI->getSize())));\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), B1);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), B2);\n\n  // Order matters: querying an empty range produces an empty result.\n\n  BlockRange = BI->findDataBlocksAt(Addr(20), Addr(0));\n  EXPECT_TRUE(BlockRange.empty());\n\n  ConstBlockRange = CBI->findDataBlocksAt(Addr(20), Addr(0));\n  EXPECT_TRUE(ConstBlockRange.empty());\n}\n\nTEST(Unit_ByteInterval, moveBlock) {\n  auto* I = IR::Create(Ctx);\n  auto* M = I->addModule(Ctx, \"test\");\n  auto* PB = M->addProxyBlock(Ctx);\n  auto* S = M->addSection(Ctx, \".text\");\n  auto* BI = S->addByteInterval(Ctx, 10);\n  auto* CB = BI->addBlock<CodeBlock>(Ctx, 0, 2);\n  auto* DB = BI->addBlock<DataBlock>(Ctx, 0, 2);\n\n  addEdge(CB, PB, I->getCFG());\n  EXPECT_EQ(boost::num_edges(I->getCFG()), 1);\n\n  EXPECT_EQ(CB->getOffset(), 0);\n  EXPECT_EQ(BI->addBlock(5, CB), ChangeStatus::Accepted);\n  EXPECT_EQ(CB->getOffset(), 5);\n\n  EXPECT_EQ(DB->getOffset(), 0);\n  EXPECT_EQ(BI->addBlock(5, DB), ChangeStatus::Accepted);\n  EXPECT_EQ(DB->getOffset(), 5);\n\n  EXPECT_EQ(BI->addBlock(5, CB), ChangeStatus::NoChange);\n  EXPECT_EQ(BI->addBlock(5, DB), ChangeStatus::NoChange);\n\n  EXPECT_EQ(boost::num_edges(I->getCFG()), 1);\n}\n\nTEST(Unit_ByteInterval, moveBlockIndices) {\n  auto* BI = ByteInterval::Create(Ctx, Addr{0}, 10);\n  auto* CB = BI->addBlock<CodeBlock>(Ctx, 0, 2);\n  auto* DB = BI->addBlock<DataBlock>(Ctx, 0, 2);\n\n  {\n    auto Range = BI->findBlocksOn(Addr{0});\n    EXPECT_EQ(std::distance(Range.begin(), Range.end()), 2);\n  }\n\n  {\n    auto Range = BI->findBlocksOn(Addr{5});\n    EXPECT_EQ(std::distance(Range.begin(), Range.end()), 0);\n  }\n\n  EXPECT_EQ(BI->addBlock(5, CB), ChangeStatus::Accepted);\n  EXPECT_EQ(BI->addBlock(5, DB), ChangeStatus::Accepted);\n\n  {\n    auto Range = BI->findBlocksOn(Addr{0});\n    EXPECT_EQ(std::distance(Range.begin(), Range.end()), 0);\n  }\n\n  {\n    auto Range = BI->findBlocksOn(Addr{5});\n    EXPECT_EQ(std::distance(Range.begin(), Range.end()), 2);\n  }\n}\n\nTEST(Unit_ByteInterval, iterationOrder) {\n  auto* BI = ByteInterval::Create(Ctx, Addr{0}, 10);\n  auto* B1Or2A = BI->addBlock<CodeBlock>(Ctx, 0, 0, DecodeMode::Default);\n  auto* B1Or2B = BI->addBlock<CodeBlock>(Ctx, 0, 0, DecodeMode::Default);\n  auto* B3 = BI->addBlock<CodeBlock>(Ctx, 0, 0, DecodeMode::Thumb);\n  auto* B4 = BI->addBlock<DataBlock>(Ctx, 0, 0);\n  auto* B5 = BI->addBlock<CodeBlock>(Ctx, 0, 1);\n\n  // We can't control what UUID the blocks are given, but they are part of the\n  // sort key. Pick an expectation dynamically based on how they compare.\n  if (B1Or2A->getUUID() < B1Or2B->getUUID()) {\n    std::vector<Node*> ExpectedOrder = {B1Or2A, B1Or2B, B3, B4, B5};\n    EXPECT_EQ(pointers(BI->blocks()), ExpectedOrder);\n  } else {\n    std::vector<Node*> ExpectedOrder = {B1Or2B, B1Or2A, B3, B4, B5};\n    EXPECT_EQ(pointers(BI->blocks()), ExpectedOrder);\n  }\n}\n\nTEST(Unit_ByteInterval, iterationOrderMoveBlock) {\n  auto* BI = ByteInterval::Create(Ctx, Addr{0}, 10);\n  auto* B1 = BI->addBlock<DataBlock>(Ctx, 0, 2);\n  auto* B2 = BI->addBlock<CodeBlock>(Ctx, 2, 0);\n  {\n    std::vector<Node*> ExpectedOrder = {B1, B2};\n    EXPECT_EQ(pointers(BI->blocks()), ExpectedOrder);\n  }\n\n  BI->addBlock(0, B2);\n  {\n    std::vector<Node*> ExpectedOrder = {B2, B1};\n    EXPECT_EQ(pointers(BI->blocks()), ExpectedOrder);\n  }\n}\n\nTEST(Unit_ByteInterval, iterationOrderSetSize) {\n  auto* BI = ByteInterval::Create(Ctx, Addr{0}, 10);\n  auto* B1 = BI->addBlock<DataBlock>(Ctx, 0, 0);\n  auto* B2 = BI->addBlock<CodeBlock>(Ctx, 0, 2);\n  {\n    std::vector<Node*> ExpectedOrder = {B1, B2};\n    EXPECT_EQ(pointers(BI->blocks()), ExpectedOrder);\n  }\n\n  B1->setSize(50);\n  {\n    std::vector<Node*> ExpectedOrder = {B2, B1};\n    EXPECT_EQ(pointers(BI->blocks()), ExpectedOrder);\n  }\n}\n\nTEST(Unit_ByteInterval, iterationOrderSetDecodeMode) {\n  auto* BI = ByteInterval::Create(Ctx, Addr{0}, 10);\n  auto* B1 = BI->addBlock<CodeBlock>(Ctx, 0, 0, DecodeMode::Default);\n  auto* B2 = BI->addBlock<CodeBlock>(Ctx, 0, 0, DecodeMode::Thumb);\n  {\n    std::vector<Node*> ExpectedOrder = {B1, B2};\n    EXPECT_EQ(pointers(BI->blocks()), ExpectedOrder);\n  }\n\n  B1->setDecodeMode(DecodeMode::Thumb);\n  B2->setDecodeMode(DecodeMode::Default);\n  {\n    std::vector<Node*> ExpectedOrder = {B2, B1};\n    EXPECT_EQ(pointers(BI->blocks()), ExpectedOrder);\n  }\n}\n"
  },
  {
    "path": "src/test/CFG.test.cpp",
    "content": "//===- CFG.test.cpp ---------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2021 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"SerializationTestHarness.hpp\"\n#include <gtirb/CFG.hpp>\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/Context.hpp>\n#include <gtirb/ProxyBlock.hpp>\n#include <gtirb/proto/CFG.pb.h>\n#include <gtest/gtest.h>\n#include <map>\n#include <sstream>\n\nusing namespace gtirb;\n\nTEST(Unit_CFG, compilationIteratorTypes) {\n  static_assert(std::is_same_v<cfg_iterator::reference, CfgNode&>);\n  static_assert(std::is_same_v<const_cfg_iterator::reference, const CfgNode&>);\n  {\n    cfg_iterator it;\n    const_cfg_iterator cit(it);\n    cit = it;\n  }\n\n  static_assert(std::is_same_v<block_iterator::reference, CodeBlock&>);\n  static_assert(\n      std::is_same_v<const_block_iterator::reference, const CodeBlock&>);\n  {\n    block_iterator it;\n    const_block_iterator cit(it);\n    cit = it;\n  }\n\n  // Check const-convertibility of [const_]cfg_predecessors_range[::iterator]\n  static_assert(\n      std::is_same_v<cfg_predecessors_range::iterator::reference::first_type,\n                     CfgNode*>);\n  static_assert(std::is_same_v<\n                const_cfg_predecessors_range::iterator::reference::first_type,\n                const CfgNode*>);\n  static_assert(std::is_convertible_v<cfg_predecessors_range,\n                                      const_cfg_predecessors_range>);\n  static_assert(!std::is_convertible_v<const_cfg_predecessors_range,\n                                       cfg_predecessors_range>);\n  static_assert(std::is_convertible_v<cfg_predecessors_range::iterator,\n                                      const_cfg_predecessors_range::iterator>);\n  static_assert(!std::is_convertible_v<const_cfg_predecessors_range::iterator,\n                                       cfg_predecessors_range::iterator>);\n  // Repeat for ..._successors_...\n  static_assert(\n      std::is_same_v<cfg_successors_range::iterator::reference::first_type,\n                     CfgNode*>);\n  static_assert(std::is_same_v<\n                const_cfg_successors_range::iterator::reference::first_type,\n                const CfgNode*>);\n  // Const-convertibility of [const_]cfg_successors_range[::iterator]\n  static_assert(\n      std::is_convertible_v<cfg_successors_range, const_cfg_successors_range>);\n  static_assert(\n      !std::is_convertible_v<const_cfg_successors_range, cfg_successors_range>);\n  static_assert(std::is_convertible_v<cfg_successors_range::iterator,\n                                      const_cfg_successors_range::iterator>);\n  static_assert(!std::is_convertible_v<const_cfg_successors_range::iterator,\n                                       cfg_successors_range::iterator>);\n}\n\nstatic Context Ctx;\n\nTEST(Unit_CFG, addVertex) {\n  CFG Cfg;\n  auto* B = CodeBlock::Create(Ctx, 2);\n  auto [Descriptor1, Added1] = addVertex(B, Cfg);\n  EXPECT_TRUE(Added1);\n  EXPECT_EQ(Cfg[Descriptor1], B);\n  EXPECT_EQ(dyn_cast<CodeBlock>(Cfg[Descriptor1])->getSize(), 2);\n\n  // adding the same block again doesn't change the graph\n  auto [Descriptor2, Added2] = addVertex(B, Cfg);\n  EXPECT_FALSE(Added2);\n  EXPECT_EQ(Descriptor2, Descriptor1);\n  auto Vertices = vertices(Cfg);\n  EXPECT_EQ(std::distance(Vertices.first, Vertices.second), 1);\n\n  auto* P = ProxyBlock::Create(Ctx);\n  auto [Descriptor3, Added3] = addVertex(P, Cfg);\n  EXPECT_TRUE(Added3);\n  EXPECT_EQ(Cfg[Descriptor3], P);\n  auto [Descriptor4, Added4] = addVertex(P, Cfg);\n  EXPECT_FALSE(Added4);\n  EXPECT_EQ(Descriptor4, Descriptor3);\n  Vertices = vertices(Cfg);\n  EXPECT_EQ(std::distance(Vertices.first, Vertices.second), 2);\n}\n\nTEST(Unit_CFG, getVertex) {\n  CFG Cfg;\n  auto* B = CodeBlock::Create(Ctx, 2);\n  auto* P = ProxyBlock::Create(Ctx);\n  auto DescriptorB = addVertex(B, Cfg).first;\n  auto DescriptorP = addVertex(P, Cfg).first;\n  EXPECT_EQ(getVertex(B, Cfg), DescriptorB);\n  EXPECT_EQ(getVertex(P, Cfg), DescriptorP);\n}\n\nTEST(Unit_CFG, removeVertex) {\n  CFG Cfg;\n  CfgNode* B1 = CodeBlock::Create(Ctx, 0);\n  CfgNode* B2 = CodeBlock::Create(Ctx, 1);\n  addVertex(B1, Cfg);\n  addVertex(B2, Cfg);\n\n  {\n    auto [Begin, End] = vertices(Cfg);\n    ASSERT_EQ(std::distance(Begin, End), 2);\n    EXPECT_EQ((std::set<CfgNode*>{Cfg[*Begin], Cfg[*std::next(Begin)]}),\n              (std::set<CfgNode*>{B1, B2}));\n    ASSERT_TRUE(getVertex(B1, Cfg));\n    EXPECT_EQ(Cfg[*getVertex(B1, Cfg)], B1);\n    ASSERT_TRUE(getVertex(B2, Cfg));\n    EXPECT_EQ(Cfg[*getVertex(B2, Cfg)], B2);\n  }\n\n  removeVertex(B1, Cfg);\n\n  {\n    auto [Begin, End] = vertices(Cfg);\n    ASSERT_EQ(std::distance(Begin, End), 1);\n    EXPECT_EQ(Cfg[*Begin], B2);\n    ASSERT_TRUE(getVertex(B2, Cfg));\n    EXPECT_EQ(Cfg[*getVertex(B2, Cfg)], B2);\n  }\n\n  addVertex(B1, Cfg);\n\n  {\n    auto [Begin, End] = vertices(Cfg);\n    ASSERT_EQ(std::distance(Begin, End), 2);\n    EXPECT_EQ((std::set<CfgNode*>{Cfg[*Begin], Cfg[*std::next(Begin)]}),\n              (std::set<CfgNode*>{B1, B2}));\n\n    ASSERT_TRUE(getVertex(B1, Cfg));\n    EXPECT_EQ(Cfg[*getVertex(B1, Cfg)], B1);\n    ASSERT_TRUE(getVertex(B2, Cfg));\n    EXPECT_EQ(Cfg[*getVertex(B2, Cfg)], B2);\n  }\n}\n\nTEST(Unit_CFG, cfgIterator) {\n  CFG Cfg;\n  auto* B1 = CodeBlock::Create(Ctx, 2);\n  auto* P1 = ProxyBlock::Create(Ctx);\n  auto* B2 = CodeBlock::Create(Ctx, 2);\n  auto* P2 = ProxyBlock::Create(Ctx);\n  addVertex(B1, Cfg);\n  addVertex(P1, Cfg);\n  addVertex(B2, Cfg);\n  addVertex(P2, Cfg);\n\n  // Non-const graph produces a regular iterator\n  boost::iterator_range<cfg_iterator> NodeRange = nodes(Cfg);\n  EXPECT_EQ(std::distance(NodeRange.begin(), NodeRange.end()), 4);\n  auto It = NodeRange.begin();\n  EXPECT_EQ(&*It, B1);\n  ++It;\n  EXPECT_EQ(&*It, P1);\n  ++It;\n  EXPECT_EQ(&*It, B2);\n  ++It;\n  EXPECT_EQ(&*It, P2);\n  ++It;\n  EXPECT_EQ(It, NodeRange.end());\n\n  // Const graph produces a const iterator\n  const CFG& ConstCfg = Cfg;\n  boost::iterator_range<const_cfg_iterator> ConstRange = nodes(ConstCfg);\n  EXPECT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 4);\n  auto Cit = ConstRange.begin();\n  EXPECT_EQ(&*Cit, B1);\n  ++Cit;\n  EXPECT_EQ(&*Cit, P1);\n  ++Cit;\n  EXPECT_EQ(&*Cit, B2);\n  ++Cit;\n  EXPECT_EQ(&*Cit, P2);\n  ++Cit;\n  EXPECT_EQ(Cit, ConstRange.end());\n}\n\nTEST(Unit_CFG, blockIterator) {\n  CFG Cfg;\n  addVertex(CodeBlock::Create(Ctx, 1), Cfg);\n  addVertex(CodeBlock::Create(Ctx, 2), Cfg);\n  addVertex(CodeBlock::Create(Ctx, 3), Cfg);\n  addVertex(ProxyBlock::Create(Ctx), Cfg);\n\n  // Non-const graph produces a regular iterator\n  boost::iterator_range<block_iterator> BlockRange = blocks(Cfg);\n  EXPECT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  auto It = BlockRange.begin();\n  EXPECT_EQ(It->getSize(), 1);\n  ++It;\n  EXPECT_EQ(It->getSize(), 2);\n  ++It;\n  EXPECT_EQ(It->getSize(), 3);\n  ++It;\n  EXPECT_EQ(It, BlockRange.end());\n\n  // Const graph produces a const iterator\n  const CFG& ConstCfg = Cfg;\n  boost::iterator_range<const_block_iterator> ConstRange = blocks(ConstCfg);\n  EXPECT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 3);\n  auto Cit = ConstRange.begin();\n  EXPECT_EQ(Cit->getSize(), 1);\n  ++Cit;\n  EXPECT_EQ(Cit->getSize(), 2);\n  ++Cit;\n  EXPECT_EQ(Cit->getSize(), 3);\n  ++Cit;\n  EXPECT_EQ(Cit, ConstRange.end());\n}\n\n// Helper for validating cfgPredecessors and cfgSuccessors.\n// Uses a multimap to normalize (sort) values, even though the pointer-based\n// ordering may change between processes.\ntypedef std::multimap<const CfgNode*, EdgeLabel> NodeEdgeMMap;\ntemplate <typename ContainerT> NodeEdgeMMap toMultiMap(const ContainerT& C) {\n  // Note: this could be implemented with the following one-liner:\n  //    return NodeEdgeMMap(C.begin(), C.end());\n  // but instead we use the following loop construct, which is the expected\n  // common usage of the cfgPredecessors/cfgSuccessors interface.\n  NodeEdgeMMap Result;\n  for (auto [Node, Label] : C) {\n    Result.emplace(Node, Label);\n  }\n  return Result;\n}\n\nTEST(Unit_CFG, edges) {\n  CFG Cfg;\n  auto B1 = CodeBlock::Create(Ctx, 1);\n  auto B2 = CodeBlock::Create(Ctx, 2);\n  auto P1 = ProxyBlock::Create(Ctx);\n  addVertex(B1, Cfg);\n  addVertex(B2, Cfg);\n  addVertex(P1, Cfg);\n\n  auto E1 = addEdge(B1, P1, Cfg);\n  EXPECT_EQ(Cfg[source(*E1, Cfg)], B1);\n  EXPECT_EQ(Cfg[target(*E1, Cfg)], P1);\n\n  auto E2 = addEdge(B2, P1, Cfg);\n  EXPECT_EQ(Cfg[source(*E2, Cfg)], B2);\n  EXPECT_EQ(Cfg[target(*E2, Cfg)], P1);\n\n  auto E3 = addEdge(P1, B1, Cfg);\n  EXPECT_EQ(Cfg[source(*E3, Cfg)], P1);\n  EXPECT_EQ(Cfg[target(*E3, Cfg)], B1);\n\n  // Parallel edge\n  auto E4 = addEdge(B1, P1, Cfg);\n  EXPECT_EQ(Cfg[source(*E4, Cfg)], B1);\n  EXPECT_EQ(Cfg[target(*E4, Cfg)], P1);\n\n  // Successor edge iterator\n  EXPECT_EQ(toMultiMap(cfgSuccessors(Cfg, B1)),\n            (NodeEdgeMMap{{P1, std::nullopt}, {P1, std::nullopt}}));\n  EXPECT_EQ(toMultiMap(cfgSuccessors(Cfg, B2)),\n            (NodeEdgeMMap{{P1, std::nullopt}}));\n  EXPECT_EQ(toMultiMap(cfgSuccessors(Cfg, P1)),\n            (NodeEdgeMMap{{B1, std::nullopt}}));\n\n  // Predecessor edge iterator\n  EXPECT_EQ(toMultiMap(cfgPredecessors(Cfg, P1)),\n            (NodeEdgeMMap{\n                {B1, std::nullopt}, {B1, std::nullopt}, {B2, std::nullopt}}));\n  EXPECT_EQ(toMultiMap(cfgPredecessors(Cfg, B1)),\n            (NodeEdgeMMap{{P1, std::nullopt}}));\n  EXPECT_EQ(toMultiMap(cfgPredecessors(Cfg, B2)), (NodeEdgeMMap{}));\n\n  // Const vs. non-const edge iterator: check constness of referenced CfgNode.\n  static_assert(\n      std::is_same_v<gtirb::CfgNode*,\n                     decltype(cfgSuccessors(Cfg, B1).begin()->first)>);\n  static_assert(\n      std::is_same_v<\n          const gtirb::CfgNode*,\n          decltype(cfgSuccessors(std::as_const(Cfg), B1).begin()->first)>);\n  // Const vs. non-const edge iterator, in structured-binding context.\n  for (auto [Node, Label] : cfgSuccessors(Cfg, B1)) {\n    static_assert(std::is_same_v<gtirb::CfgNode*, decltype(Node)>);\n    (void)Label;\n  }\n  for (auto [Node, Label] : cfgSuccessors(std::as_const(Cfg), B1)) {\n    static_assert(std::is_same_v<const gtirb::CfgNode*, decltype(Node)>);\n    (void)Label;\n  }\n\n  // Remove edge part\n  {\n    auto [Begin, End] = edges(Cfg);\n    ASSERT_EQ(std::distance(Begin, End), 4);\n  }\n\n  // Remove one edge\n  removeEdge(B2, P1, Cfg);\n  {\n    auto [It, End] = edges(Cfg);\n    ASSERT_EQ(std::distance(It, End), 3);\n    EXPECT_EQ(Cfg[source(*It, Cfg)], B1);\n    EXPECT_EQ(Cfg[target(*It, Cfg)], P1);\n    ++It;\n    EXPECT_EQ(Cfg[source(*It, Cfg)], P1);\n    EXPECT_EQ(Cfg[target(*It, Cfg)], B1);\n    ++It;\n    EXPECT_EQ(Cfg[source(*It, Cfg)], B1);\n    EXPECT_EQ(Cfg[target(*It, Cfg)], P1);\n  }\n\n  // Remove parallel edges\n  removeEdge(B1, P1, Cfg);\n  {\n    auto [Begin, End] = edges(Cfg);\n    ASSERT_EQ(std::distance(Begin, End), 1);\n    EXPECT_EQ(Cfg[source(*Begin, Cfg)], P1);\n    EXPECT_EQ(Cfg[target(*Begin, Cfg)], B1);\n  }\n\n  // Remove not existing edge\n  auto B3 = CodeBlock::Create(Ctx, 3);\n  EXPECT_FALSE(removeEdge(B3, P1, Cfg));\n  EXPECT_FALSE(removeEdge(P1, B3, Cfg));\n}\n\nTEST(Unit_CFG, edgeLabelPrinting) {\n  std::stringstream LabelOutput;\n  gtirb::EdgeLabel Label;\n  LabelOutput << Label;\n  EXPECT_EQ(LabelOutput.str(), \"<No EdgeLabel>\");\n\n  Label.emplace(gtirb::ConditionalEdge::OnFalse, gtirb::DirectEdge::IsDirect,\n                gtirb::EdgeType::Fallthrough);\n  LabelOutput.str(std::string());\n  LabelOutput << Label;\n  EXPECT_EQ(LabelOutput.str(), \"(OnFalse, IsDirect, Fallthrough)\");\n}\n\nTEST(Unit_CFG, edgeLabels) {\n  CFG Cfg;\n  auto B1 = CodeBlock::Create(Ctx, 1);\n  auto B2 = CodeBlock::Create(Ctx, 2);\n  addVertex(B1, Cfg);\n  addVertex(B2, Cfg);\n\n  // Create an edge with no label\n  auto E = addEdge(B2, B1, Cfg);\n  EXPECT_FALSE(Cfg[*E]);\n\n  auto Conds = {ConditionalEdge::OnFalse, ConditionalEdge::OnTrue};\n  auto Dirs = {DirectEdge::IsDirect, DirectEdge::IsIndirect};\n  auto Types = {EdgeType::Branch, EdgeType::Call,    EdgeType::Fallthrough,\n                EdgeType::Return, EdgeType::Syscall, EdgeType::Sysret};\n\n  // Create a number of parallel edges with different labels.\n  std::vector<CFG::edge_descriptor> Descriptors;\n  NodeEdgeMMap EdgesToCheck;\n  for (ConditionalEdge Cond : Conds) {\n    for (DirectEdge Dir : Dirs) {\n      for (EdgeType Type : Types) {\n        E = addEdge(B1, B2, Cfg);\n        const EdgeLabel Label{std::in_place, Cond, Dir, Type};\n        Cfg[*E] = Label;\n        Descriptors.push_back(*E);\n        EdgesToCheck.emplace(B2, Label);\n      }\n    }\n  }\n\n  // Check that the edges have the properties we assigned.\n  auto It = Descriptors.begin();\n  for (ConditionalEdge Cond : Conds) {\n    for (DirectEdge Dir : Dirs) {\n      for (EdgeType Type : Types) {\n        EXPECT_TRUE(Cfg[*It]);\n        EXPECT_EQ(std::get<ConditionalEdge>(*Cfg[*It]), Cond);\n        EXPECT_EQ(std::get<DirectEdge>(*Cfg[*It]), Dir);\n        EXPECT_EQ(std::get<EdgeType>(*Cfg[*It]), Type);\n        ++It;\n      }\n    }\n  }\n  // Successor edge iterator check\n  EXPECT_EQ(toMultiMap(cfgSuccessors(Cfg, B1)), EdgesToCheck);\n\n  // Remove an edge with a label part\n  const EdgeLabel Label{std::in_place, ConditionalEdge::OnFalse,\n                        DirectEdge::IsDirect, EdgeType::Branch};\n  {\n    auto [Begin, End] = edges(Cfg);\n    ASSERT_EQ(std::distance(Begin, End), 25);\n  }\n  // Remove non existing edge\n  // There is B2 -> B1 edge without a label\n  removeEdge(B2, B1,\n             EdgeLabel{std::in_place, ConditionalEdge::OnTrue,\n                       DirectEdge::IsDirect, EdgeType::Fallthrough},\n             Cfg);\n  {\n    auto [Begin, End] = edges(Cfg);\n    ASSERT_EQ(std::distance(Begin, End), 25);\n  }\n  // Remove the given edge\n  removeEdge(B1, B2, Label, Cfg);\n  {\n    auto [Begin, End] = edges(Cfg);\n    ASSERT_EQ(std::distance(Begin, End), 24);\n  }\n  // Check that the correct edge removed\n  {\n    auto [ie, end] = edges(Cfg);\n    while (ie != end) {\n      if (Cfg[*ie]) {\n        if ((Cfg[source(*ie, Cfg)], B1) && (Cfg[target(*ie, Cfg)], B2) &&\n            (std::get<ConditionalEdge>(*Cfg[*ie]) ==\n             std::get<ConditionalEdge>(*Label)) &&\n            (std::get<DirectEdge>(*Cfg[*ie]) == std::get<DirectEdge>(*Label)) &&\n            (std::get<EdgeType>(*Cfg[*ie]) == std::get<EdgeType>(*Label))) {\n          EXPECT_FALSE(true);\n        }\n      }\n      ++ie;\n    }\n  }\n  // Check that 2 parallel edges with the same same label can be deleted\n  // Create 2 parallel edges\n  E = addEdge(B1, B2, Cfg);\n  Cfg[*E] = Label;\n  E = addEdge(B1, B2, Cfg);\n  Cfg[*E] = Label;\n  {\n    auto [Begin, End] = edges(Cfg);\n    ASSERT_EQ(std::distance(Begin, End), 26);\n  }\n  // Remove them\n  removeEdge(B1, B2, Label, Cfg);\n  {\n    auto [Begin, End] = edges(Cfg);\n    ASSERT_EQ(std::distance(Begin, End), 24);\n  }\n  // Create second paralle edge with no label\n  E = addEdge(B2, B1, Cfg);\n  EXPECT_FALSE(Cfg[*E]);\n  {\n    auto [Begin, End] = edges(Cfg);\n    ASSERT_EQ(std::distance(Begin, End), 25);\n  }\n  // Remove 2 parallel edges with no labels\n  removeEdge(B2, B1, std::nullopt, Cfg);\n  {\n    auto [Begin, End] = edges(Cfg);\n    ASSERT_EQ(std::distance(Begin, End), 23);\n  }\n  // Check that there are no edges without label\n  {\n    auto [ie, end] = edges(Cfg);\n    while (ie != end) {\n      EXPECT_TRUE(Cfg[*ie]);\n      ++ie;\n    }\n  }\n}\n\nTEST(Unit_CFG, protobufRoundTrip) {\n  CFG Result;\n  std::stringstream ss;\n\n  auto B1 = CodeBlock::Create(Ctx, 1, DecodeMode::Default);\n  auto B2 = CodeBlock::Create(Ctx, 3, DecodeMode::Thumb);\n  auto P1 = ProxyBlock::Create(Ctx);\n  {\n    CFG Original;\n    addVertex(B1, Original);\n    addVertex(B2, Original);\n    addVertex(P1, Original);\n\n    auto E1 = addEdge(B1, P1, Original);\n    auto E2 = addEdge(B2, P1, Original);\n    addEdge(P1, B1, Original);\n    Original[*E1] = std::make_tuple(ConditionalEdge::OnTrue,\n                                    DirectEdge::IsDirect, EdgeType::Branch);\n    Original[*E2] = std::make_tuple(ConditionalEdge::OnFalse,\n                                    DirectEdge::IsIndirect, EdgeType::Call);\n\n    cfgSave(Original, ss);\n  }\n  cfgLoad(Ctx, Result, ss);\n\n  auto Range = nodes(Result);\n  EXPECT_EQ(std::distance(Range.begin(), Range.end()), 3);\n  auto It = Range.begin();\n  EXPECT_EQ(It->getUUID(), B1->getUUID());\n  EXPECT_EQ(dyn_cast<CodeBlock>(&*It)->getSize(), 1);\n  EXPECT_EQ(dyn_cast<CodeBlock>(&*It)->getDecodeMode(), DecodeMode::Default);\n  ++It;\n  EXPECT_EQ(It->getUUID(), B2->getUUID());\n  EXPECT_EQ(dyn_cast<CodeBlock>(&*It)->getSize(), 3);\n  EXPECT_EQ(dyn_cast<CodeBlock>(&*It)->getDecodeMode(), DecodeMode::Thumb);\n  ++It;\n  EXPECT_EQ(It->getUUID(), P1->getUUID());\n\n  // Check edges\n  EXPECT_TRUE(\n      edge(*getVertex(B1, Result), *getVertex(P1, Result), Result).second);\n  EXPECT_TRUE(\n      edge(*getVertex(B2, Result), *getVertex(P1, Result), Result).second);\n  EXPECT_TRUE(\n      edge(*getVertex(P1, Result), *getVertex(B1, Result), Result).second);\n\n  // Check nonexistent edges\n  EXPECT_FALSE(\n      edge(*getVertex(B1, Result), *getVertex(B2, Result), Result).second);\n  EXPECT_FALSE(\n      edge(*getVertex(B2, Result), *getVertex(B1, Result), Result).second);\n  EXPECT_FALSE(\n      edge(*getVertex(P1, Result), *getVertex(B2, Result), Result).second);\n\n  // Check labels\n  auto E1 = edge(*getVertex(B1, Result), *getVertex(P1, Result), Result).first;\n  EXPECT_EQ(std::get<ConditionalEdge>(*Result[E1]), ConditionalEdge::OnTrue);\n  EXPECT_EQ(std::get<DirectEdge>(*Result[E1]), DirectEdge::IsDirect);\n  EXPECT_EQ(std::get<EdgeType>(*Result[E1]), EdgeType::Branch);\n\n  auto E2 = edge(*getVertex(B2, Result), *getVertex(P1, Result), Result).first;\n  EXPECT_EQ(std::get<ConditionalEdge>(*Result[E2]), ConditionalEdge::OnFalse);\n  EXPECT_EQ(std::get<DirectEdge>(*Result[E2]), DirectEdge::IsIndirect);\n  EXPECT_EQ(std::get<EdgeType>(*Result[E2]), EdgeType::Call);\n\n  auto E3 = edge(*getVertex(P1, Result), *getVertex(B1, Result), Result).first;\n  EXPECT_FALSE(Result[E3]);\n}\n"
  },
  {
    "path": "src/test/CMakeLists.txt",
    "content": "# TestGTIRB\n#\n# This is the main executable containing unit tests for the GTIRB C++ API.\nset(PROJECT_NAME TestGTIRB)\n\nenable_testing()\ninclude_directories(${GTEST_INCLUDE_DIRS})\ninclude_directories(${CMAKE_CURRENT_BINARY_DIR})\n\nadd_compile_options(-DDEBUG)\n\n# Required warning suppression (TODO: Remove!)\nif(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)\n  # add_compile_options(-wd4251)  # Non-exportable template classes.\n  add_compile_options(-wd4389) # signed/unsigned mismatch (in gtest headers)\nelseif(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU)\n  add_compile_options(-fpermissive)\n  add_compile_options(-mtune=generic)\n  add_compile_options(-pthread)\nelseif(${CMAKE_CXX_COMPILER_ID} STREQUAL Clang)\n  add_compile_options(-fpermissive)\n  add_compile_options(-mtune=generic)\n  add_compile_options(-pthread)\nendif()\n\n# Check for access to resource.h\ninclude(CheckIncludeFiles)\ncheck_include_files(sys/resource.h HAVE_RESOURCE_H)\nconfigure_file(\n  ${CMAKE_CURRENT_SOURCE_DIR}/config-test.h.in\n  ${CMAKE_CURRENT_BINARY_DIR}/config-test.h\n)\n\nset(${PROJECT_NAME}_H AuxDataContainerSchema.hpp Main.test.hpp\n                      PrepDeathTest.hpp\n)\n\nset(${PROJECT_NAME}_SRC\n    Addr.test.cpp\n    Allocator.test.cpp\n    AuxData.test.cpp\n    AuxDataContainer.test.cpp\n    ByteInterval.test.cpp\n    CFG.test.cpp\n    CodeBlock.test.cpp\n    DataBlock.test.cpp\n    IR.test.cpp\n    Main.test.cpp\n    MergeSortedIterator.test.cpp\n    Module.test.cpp\n    Node.test.cpp\n    Offset.test.cpp\n    ProxyBlock.test.cpp\n    Section.test.cpp\n    Symbol.test.cpp\n    SymbolicExpression.test.cpp\n    TypedNodeTest.cpp\n)\n\nif(UNIX AND NOT WIN32)\n  set(SYSLIBS dl)\nelse()\n  set(SYSLIBS)\nendif()\n\nadd_executable(${PROJECT_NAME} ${${PROJECT_NAME}_H} ${${PROJECT_NAME}_SRC})\nset_target_properties(${PROJECT_NAME} PROPERTIES FOLDER \"gtirb/test\")\ntarget_compile_definitions(\n  ${PROJECT_NAME} PRIVATE GTIRB_WRAP_UTILS_IN_NAMESPACE\n)\n\ntarget_link_libraries(\n  ${PROJECT_NAME} ${SYSLIBS} ${Boost_LIBRARIES} gtest gtest_main gtirb\n)\n\n# PrepTestGTIRB\n#\n# This binary's purpose is to construct a GTIRB IR file in one process that has\n# a certain set of AUxData schemas registered that is different from the set\n# registered in TestGTIRB, allowing tests in TestGTIRB to exercise functionality\n# that is specific to handling unregistered schemas.\nset(PROJECT_NAME PrepTestGTIRB)\n\nset(${PROJECT_NAME}_H AuxDataContainerSchema.hpp)\n\nset(${PROJECT_NAME}_SRC PrepTestGTIRB.cpp)\n\nadd_executable(${PROJECT_NAME} ${${PROJECT_NAME}_H} ${${PROJECT_NAME}_SRC})\nset_target_properties(${PROJECT_NAME} PROPERTIES FOLDER \"gtirb/test\")\ntarget_compile_definitions(\n  ${PROJECT_NAME} PRIVATE GTIRB_WRAP_UTILS_IN_NAMESPACE\n)\n\ntarget_link_libraries(${PROJECT_NAME} ${SYSLIBS} ${Boost_LIBRARIES} gtirb)\n\n# Add a single test that runs both the PrepTestGTIRB and TestGTIRB executables\n# in sequence, passing the output GTIRB file from the former to the latter.\nadd_test(\n  NAME testgtirbc++\n  COMMAND ${CMAKE_COMMAND} -DCMD1=$<TARGET_FILE:PrepTestGTIRB>\n          -DCMD2=$<TARGET_FILE:TestGTIRB> -P\n          ${CMAKE_CURRENT_SOURCE_DIR}/runtests.cmake\n)\n\n# testgtirb_schemac++\n#\n# This is a separate test executable setup explicitly to exercise AuxData schema\n# registration code that runs before the AuxData TypeMap gets locked. These\n# tests cannot be effectively executed in the main test executable above, which\n# locks the TypeMap before any of the tests are executed.\nset(PROJECT_NAME testgtirb_schemac++)\n\nset(${PROJECT_NAME}_H AuxDataContainerSchema.hpp PrepDeathTest.hpp)\n\nset(${PROJECT_NAME}_SRC AuxDataSchemaRegistration.test.cpp)\n\n# Add this test to ctest\ngtirb_add_executable_gtest()\ntarget_compile_definitions(\n  ${PROJECT_NAME} PRIVATE GTIRB_WRAP_UTILS_IN_NAMESPACE\n)\n\ntarget_link_libraries(\n  ${PROJECT_NAME} ${SYSLIBS} ${Boost_LIBRARIES} gtest gtest_main gtirb\n)\n\n# testgtirb_deprecated_utils\n#\n# This separate test executable does NOT define GTIRB_WRAP_UTILS_IN_NAMESPACE\nset(PROJECT_NAME testgtirb_deprecated_utils)\n\nset(${PROJECT_NAME}_SRC UtilsUsingGtirbNamespace.test.cpp\n                        UtilsDeprecatedGlobals.test.cpp\n)\n\ngtirb_add_executable_gtest()\n\nif((CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\") OR (${CMAKE_CXX_COMPILER_ID} STREQUAL\n                                              Clang)\n)\n  # Disable deprecation warnings\n  target_compile_options(${PROJECT_NAME} PRIVATE -Wno-deprecated-declarations)\nendif()\n\ntarget_link_libraries(\n  ${PROJECT_NAME} ${SYSLIBS} ${Boost_LIBRARIES} gtest gtest_main gtirb\n)\n\nadd_subdirectory(testInputBinary)\nadd_subdirectory(testInterop)\n"
  },
  {
    "path": "src/test/CodeBlock.test.cpp",
    "content": "//===- CodeBlock.test.cpp ---------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"SerializationTestHarness.hpp\"\n#include <gtirb/ByteInterval.hpp>\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/Context.hpp>\n#include <gtest/gtest.h>\n#include <sstream>\n\nusing namespace gtirb;\n\nstatic Context Ctx;\n\nTEST(Unit_CodeBlock, noCopyMoveConstructors) {\n  EXPECT_FALSE(std::is_copy_constructible_v<CodeBlock>);\n  EXPECT_FALSE(std::is_move_constructible_v<CodeBlock>);\n  EXPECT_FALSE(std::is_copy_assignable_v<CodeBlock>);\n  EXPECT_FALSE(std::is_move_assignable_v<CodeBlock>);\n}\n\nTEST(Unit_CodeBlock, ctor) { EXPECT_NE(CodeBlock::Create(Ctx, 0), nullptr); }\n\nTEST(Unit_CodeBlock, getters) {\n  auto* BI = ByteInterval::Create(Ctx, Addr(0), 2);\n  auto* B = BI->addBlock<CodeBlock>(Ctx, 0, 1, DecodeMode::Thumb);\n\n  EXPECT_EQ(Addr{0}, B->getAddress());\n  EXPECT_EQ(uint64_t{1}, B->getSize());\n  EXPECT_EQ(DecodeMode::Thumb, B->getDecodeMode());\n  EXPECT_EQ(BI, B->getByteInterval());\n}\n\nTEST(Unit_CodeBlock, getAddress) {\n  auto* BI = ByteInterval::Create(Ctx, Addr(10), 10);\n  auto* B1 = BI->addBlock<CodeBlock>(Ctx, 0, 0);\n  auto* B2 = BI->addBlock<CodeBlock>(Ctx, 1, 0);\n  auto* B3 = BI->addBlock<CodeBlock>(Ctx, 10, 0);\n\n  EXPECT_EQ(B1->getAddress(), Addr{10});\n  EXPECT_EQ(B2->getAddress(), Addr{11});\n  EXPECT_EQ(B3->getAddress(), Addr{20});\n\n  BI->setAddress({});\n  EXPECT_EQ(B1->getAddress(), std::optional<Addr>());\n  EXPECT_EQ(B2->getAddress(), std::optional<Addr>());\n  EXPECT_EQ(B3->getAddress(), std::optional<Addr>());\n}\n\nTEST(Unit_CodeBlock, byteVector) {\n  std::string Contents = \"hello, world!\";\n  auto* BI = ByteInterval::Create(Ctx, std::optional<Addr>(), Contents.begin(),\n                                  Contents.end());\n  auto* B = BI->addBlock<CodeBlock>(Ctx, 3, 4);\n\n  auto OriginalIt = Contents.begin() + 3;\n  auto NewIt = B->bytes_begin<char>();\n  auto OriginalEnd = OriginalIt + 4;\n  auto NewEnd = B->bytes_end<char>();\n\n  while (OriginalIt != OriginalEnd && NewIt != NewEnd) {\n    EXPECT_EQ(*OriginalIt, *NewIt);\n    ++OriginalIt;\n    ++NewIt;\n  }\n  EXPECT_EQ(OriginalIt, OriginalEnd);\n  EXPECT_EQ(NewIt, NewEnd);\n}\n\nTEST(Unit_CodeBlock, protobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  std::stringstream ss;\n  {\n    Context InnerCtx;\n    CodeBlock* Original = CodeBlock::Create(InnerCtx, 1234, DecodeMode::Thumb);\n    STH::save(*Original, ss);\n  }\n  CodeBlock* Result = STH::load<CodeBlock>(Ctx, ss);\n\n  EXPECT_EQ(Result->getSize(), 1234);\n  EXPECT_EQ(Result->getDecodeMode(), DecodeMode::Thumb);\n  EXPECT_EQ(Result->getByteInterval(), nullptr);\n}\n"
  },
  {
    "path": "src/test/DataBlock.test.cpp",
    "content": "//===- DataBlock.test.cpp --------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"SerializationTestHarness.hpp\"\n#include <gtirb/ByteInterval.hpp>\n#include <gtirb/Context.hpp>\n#include <gtirb/DataBlock.hpp>\n#include <gtirb/proto/DataBlock.pb.h>\n#include <gtest/gtest.h>\n#include <sstream>\n\nusing namespace gtirb;\n\nstatic Context Ctx;\n\nTEST(Unit_DataBlock, noCopyMoveConstructors) {\n  EXPECT_FALSE(std::is_copy_constructible_v<DataBlock>);\n  EXPECT_FALSE(std::is_move_constructible_v<DataBlock>);\n  EXPECT_FALSE(std::is_copy_assignable_v<DataBlock>);\n  EXPECT_FALSE(std::is_move_assignable_v<DataBlock>);\n}\n\nTEST(Unit_DataBlock, getters) {\n  auto* BI = ByteInterval::Create(Ctx, Addr(0), 2);\n  auto* B = BI->addBlock<DataBlock>(Ctx, 0, 1);\n\n  EXPECT_EQ(Addr{0}, B->getAddress());\n  EXPECT_EQ(uint64_t{1}, B->getSize());\n  EXPECT_EQ(BI, B->getByteInterval());\n}\n\nTEST(Unit_DataBlock, getAddress) {\n  auto* BI = ByteInterval::Create(Ctx, Addr(10), 10);\n  auto* B1 = BI->addBlock<DataBlock>(Ctx, 0, 0);\n  auto* B2 = BI->addBlock<DataBlock>(Ctx, 1, 0);\n  auto* B3 = BI->addBlock<DataBlock>(Ctx, 10, 0);\n\n  EXPECT_EQ(B1->getAddress(), Addr{10});\n  EXPECT_EQ(B2->getAddress(), Addr{11});\n  EXPECT_EQ(B3->getAddress(), Addr{20});\n\n  BI->setAddress({});\n  EXPECT_EQ(B1->getAddress(), std::optional<Addr>());\n  EXPECT_EQ(B2->getAddress(), std::optional<Addr>());\n  EXPECT_EQ(B3->getAddress(), std::optional<Addr>());\n}\n\nTEST(Unit_DataBlock, protobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  std::stringstream ss;\n  {\n    Context InnerCtx;\n    DataBlock* Original = DataBlock::Create(InnerCtx, 1234);\n    STH::save(*Original, ss);\n  }\n  DataBlock* Result = STH::load<DataBlock>(Ctx, ss);\n\n  EXPECT_EQ(Result->getSize(), 1234);\n  EXPECT_EQ(Result->getByteInterval(), nullptr);\n}\n\nTEST(Unit_DataBlock, byteVector) {\n  std::string Contents = \"hello, world!\";\n  auto* BI = ByteInterval::Create(Ctx, std::optional<Addr>(), Contents.begin(),\n                                  Contents.end());\n  auto* B = BI->addBlock<DataBlock>(Ctx, 3, 4);\n\n  auto OriginalIt = Contents.begin() + 3;\n  auto NewIt = B->bytes_begin<char>();\n  auto OriginalEnd = OriginalIt + 4;\n  auto NewEnd = B->bytes_end<char>();\n\n  while (OriginalIt != OriginalEnd && NewIt != NewEnd) {\n    EXPECT_EQ(*OriginalIt, *NewIt);\n    ++OriginalIt;\n    ++NewIt;\n  }\n  EXPECT_EQ(OriginalIt, OriginalEnd);\n  EXPECT_EQ(NewIt, NewEnd);\n}\n"
  },
  {
    "path": "src/test/IR.test.cpp",
    "content": "//===- IR.test.cpp ----------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2021 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"SerializationTestHarness.hpp\"\n#include <gtirb/AuxData.hpp>\n#include <gtirb/Context.hpp>\n#include <gtirb/DataBlock.hpp>\n#include <gtirb/IR.hpp>\n#include <gtirb/Module.hpp>\n#include <gtirb/Section.hpp>\n#include <gtirb/Symbol.hpp>\n#include <gtirb/SymbolicExpression.hpp>\n#include <gtirb/proto/IR.pb.h>\n#include <gtest/gtest.h>\n#include <sstream>\n\nnamespace gtirb {\nnamespace schema {\n\nstruct TestVectorInt64 {\n  static constexpr const char* Name = \"test vector<int64_t>\";\n  typedef std::vector<int64_t> Type;\n};\n\nstruct FooVectorInt64 {\n  static constexpr const char* Name = \"foo vector<int64_t>\";\n  typedef std::vector<int64_t> Type;\n};\n\nstruct AnAuxDataMap {\n  static constexpr const char* Name = \"AuxData map\";\n  typedef std::map<std::string, int64_t> Type;\n};\n\nstruct BarVectorChar {\n  static constexpr const char* Name = \"bar vector<char>\";\n  typedef std::vector<char> Type;\n};\n\nstruct TestInt32 {\n  static constexpr const char* Name = \"test int32\";\n  typedef int32_t Type;\n};\n\n} // namespace schema\n} // namespace gtirb\n\nusing namespace gtirb;\nusing namespace gtirb::schema;\n\nvoid registerIrTestAuxDataTypes() {\n  AuxDataContainer::registerAuxDataType<TestVectorInt64>();\n  AuxDataContainer::registerAuxDataType<FooVectorInt64>();\n  AuxDataContainer::registerAuxDataType<AnAuxDataMap>();\n  AuxDataContainer::registerAuxDataType<BarVectorChar>();\n  AuxDataContainer::registerAuxDataType<TestInt32>();\n}\n\nstatic bool hasPreferredAddr(const Module& M, Addr X) {\n  return M.getPreferredAddr() == X;\n}\n\nTEST(Unit_IR, compilationIteratorTypes) {\n  static_assert(std::is_same_v<IR::module_iterator::reference, Module&>);\n  static_assert(\n      std::is_same_v<IR::const_module_iterator::reference, const Module&>);\n  // Actually calling the constructor and assignment operator tends to produce\n  // more informative error messages than std::is_constructible and\n  // std::is_assignable.\n  IR::module_iterator It;\n  IR::const_module_iterator CIt(It);\n  CIt = It;\n}\n\nTEST(Unit_IR, noCopyMoveConstructors) {\n  EXPECT_FALSE(std::is_copy_constructible_v<IR>);\n  EXPECT_FALSE(std::is_move_constructible_v<IR>);\n  EXPECT_FALSE(std::is_copy_assignable_v<IR>);\n  EXPECT_FALSE(std::is_move_assignable_v<IR>);\n}\n\nstatic Context Ctx;\nTEST(Unit_IR, ctor_0) { EXPECT_NE(IR::Create(Ctx), nullptr); }\n\nTEST(Unit_IR, addRemoveXferModules) {\n  auto* I1 = IR::Create(Ctx);\n  auto* I2 = IR::Create(Ctx);\n  auto* M1 = Module::Create(Ctx, \"M1\");\n  auto* M2 = Module::Create(Ctx, \"M2\");\n\n  I1->addModule(M1);\n  ASSERT_EQ(std::distance(I1->modules_begin(), I1->modules_end()), 1);\n  EXPECT_EQ(&*I1->modules_begin(), M1);\n\n  I1->addModule(M2);\n  ASSERT_EQ(std::distance(I1->modules_begin(), I1->modules_end()), 2);\n  EXPECT_EQ((std::set<Module*>{&*std::next(I1->modules_begin(), 0),\n                               &*std::next(I1->modules_begin(), 1)}),\n            (std::set<Module*>{M1, M2}));\n\n  // Check addModule() removes the module from its former owner.\n\n  I2->addModule(M1);\n  ASSERT_EQ(std::distance(I1->modules_begin(), I1->modules_end()), 1);\n  EXPECT_EQ(&*I1->modules_begin(), M2);\n  ASSERT_EQ(std::distance(I2->modules_begin(), I2->modules_end()), 1);\n  EXPECT_EQ(&*I2->modules_begin(), M1);\n\n  // Check removeModule() does nothing if the IR does not own the Module.\n\n  I1->removeModule(M1);\n  ASSERT_EQ(std::distance(I1->modules_begin(), I1->modules_end()), 1);\n  EXPECT_EQ(&*I1->modules_begin(), M2);\n  ASSERT_EQ(std::distance(I2->modules_begin(), I2->modules_end()), 1);\n  EXPECT_EQ(&*I2->modules_begin(), M1);\n\n  // Check removeModule() removes the module if it is owned.\n  I1->removeModule(M2);\n  EXPECT_TRUE(I1->modules().empty());\n}\n\nTEST(Unit_IR, moduleIterationOrder) {\n  auto* Ir = IR::Create(Ctx);\n  auto* M1 = Ir->addModule(Ctx, \"b\");\n  auto* M2 = Ir->addModule(Ctx, \"a\");\n  auto* M3 = Ir->addModule(Ctx, \"a\");\n\n  EXPECT_EQ(std::distance(Ir->modules_begin(), Ir->modules_end()), 3);\n  auto It = Ir->modules_begin();\n  // Order of M2 and M3 is unspecified.\n  if (&*It == M2) {\n    ++It;\n    EXPECT_EQ(&*It, M3);\n  } else {\n    EXPECT_EQ(&*It, M3);\n    ++It;\n    EXPECT_EQ(&*It, M2);\n  }\n  ++It;\n  EXPECT_EQ(&*It, M1);\n}\n\nTEST(Unit_IR, findModules) {\n  auto* Ir = IR::Create(Ctx);\n  auto* M1 = Ir->addModule(Ctx, \"foo\");\n  auto* M2 = Ir->addModule(Ctx, \"bar\");\n  auto* M3 = Ir->addModule(Ctx, \"foo\");\n\n  {\n    auto F = Ir->findModules(\"foo\");\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 2);\n    // Order of M1 and M3 is unspecified.\n    EXPECT_EQ((std::set<Module*>{&*F.begin(), &*std::next(F.begin(), 1)}),\n              (std::set<Module*>{M1, M3}));\n  }\n\n  {\n    auto F = Ir->findModules(\"bar\");\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), M2);\n  }\n\n  EXPECT_TRUE(Ir->findModules(\"notfound\").empty());\n}\n\nTEST(Unit_IR, getModulesWithPreferredAddr) {\n  const Addr PreferredAddr{22678};\n  const size_t ModulesWithAddr{3};\n  const size_t ModulesWithoutAddr{5};\n\n  auto* Ir = IR::Create(Ctx);\n\n  std::string ModName = \"with_addr0\";\n  for (size_t I = 0; I < ModulesWithAddr; ++I) {\n    ModName[ModName.size() - 1] = '0' + I;\n    auto* M = Ir->addModule(Module::Create(Ctx, ModName));\n    M->setPreferredAddr(PreferredAddr);\n  }\n\n  ModName = \"without_addr0\";\n  for (size_t I = 0; I < ModulesWithoutAddr; ++I) {\n    ModName[ModName.size() - 1] = '0' + I;\n    Ir->addModule(Module::Create(Ctx, ModName));\n  }\n\n  size_t Count = std::count_if(Ir->modules_begin(), Ir->modules_end(),\n                               [PreferredAddr](const Module& M) {\n                                 return hasPreferredAddr(M, PreferredAddr);\n                               });\n  EXPECT_FALSE(Count == 0);\n  EXPECT_EQ(ModulesWithAddr, Count);\n}\n\nTEST(Unit_IR, addAuxData) {\n  std::vector<int64_t> AuxData = {1, 2, 3};\n  auto* Ir = IR::Create(Ctx);\n  Ir->addAuxData<TestVectorInt64>(std::move(AuxData));\n\n  ASSERT_NE(Ir->getAuxData<TestVectorInt64>(), nullptr);\n  EXPECT_EQ(*Ir->getAuxData<TestVectorInt64>(),\n            std::vector<int64_t>({1, 2, 3}));\n}\n\nTEST(Unit_IR, getAuxData) {\n  std::vector<int64_t> AuxDataVec = {1, 2, 3};\n  std::map<std::string, int64_t> AuxDataMap = {{\"foo\", 1}, {\"bar\", 2}};\n  auto* Ir = IR::Create(Ctx);\n  Ir->addAuxData<FooVectorInt64>(std::move(AuxDataVec));\n  Ir->addAuxData<AnAuxDataMap>(std::move(AuxDataMap));\n\n  auto* FooAuxData = Ir->getAuxData<FooVectorInt64>();\n  ASSERT_NE(FooAuxData, nullptr);\n  EXPECT_EQ(*FooAuxData, std::vector<int64_t>({1, 2, 3}));\n\n  auto* StoredAuxDataMap = Ir->getAuxData<AnAuxDataMap>();\n  std::map<std::string, int64_t> ToCompare = {{\"foo\", 1}, {\"bar\", 2}};\n  std::map<std::string, int64_t> BadToCompare = {{\"foo\", 1}, {\"bar\", 3}};\n  ASSERT_NE(StoredAuxDataMap, nullptr);\n  EXPECT_NE(*StoredAuxDataMap, BadToCompare);\n  EXPECT_EQ(*StoredAuxDataMap, ToCompare);\n}\n\nTEST(Unit_IR, auxDataRange) {\n  auto* Ir = IR::Create(Ctx);\n  Ir->addAuxData<FooVectorInt64>(std::vector<int64_t>{1, 2, 3});\n  Ir->addAuxData<BarVectorChar>(std::vector<char>{'a', 'b', 'c'});\n\n  auto A = Ir->aux_data();\n  EXPECT_EQ(std::distance(A.begin(), A.end()), 2);\n  // AuxDatas are sorted by range, but this is an implementation detail\n  EXPECT_EQ(A.begin()->Key, \"bar vector<char>\");\n  EXPECT_EQ((++A.begin())->Key, \"foo vector<int64_t>\");\n}\n\nTEST(Unit_IR, missingAuxData) {\n  auto* Ir = IR::Create(Ctx);\n  EXPECT_EQ(Ir->getAuxData<FooVectorInt64>(), nullptr);\n}\n\nTEST(Unit_IR, protobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  std::stringstream ss;\n  UUID MainID;\n\n  {\n    Context InnerCtx;\n    auto* Original = IR::Create(InnerCtx);\n    Original->addModule(Module::Create(InnerCtx, \"test\"));\n    Original->addAuxData<TestInt32>(42);\n\n    MainID = Original->modules_begin()->getUUID();\n    STH::save(*Original, ss);\n  }\n  auto* Result = STH::load<IR>(Ctx, ss);\n\n  EXPECT_EQ(Result->modules_begin()->getUUID(), MainID);\n  EXPECT_EQ(Result->getAuxDataSize(), 1);\n  ASSERT_NE(Result->getAuxData<TestInt32>(), nullptr);\n  EXPECT_EQ(*Result->getAuxData<TestInt32>(), 42);\n}\n\nTEST(Unit_IR, jsonRoundTrip) {\n  UUID MainID;\n  std::ostringstream Out;\n\n  {\n    Context InnerCtx;\n    auto* Original = IR::Create(InnerCtx);\n    Original->addModule(Module::Create(InnerCtx, \"test\"));\n    Original->addAuxData<TestInt32>(42);\n\n    MainID = Original->modules_begin()->getUUID();\n    Original->saveJSON(Out);\n  }\n  std::istringstream In(Out.str());\n  auto ResultOrErr = IR::loadJSON(Ctx, In);\n  ASSERT_TRUE(ResultOrErr);\n  auto* Result = *ResultOrErr;\n\n  EXPECT_EQ(Result->modules_begin()->getUUID(), MainID);\n  EXPECT_EQ(Result->getAuxDataSize(), 1);\n  ASSERT_NE(Result->getAuxData<TestInt32>(), nullptr);\n  EXPECT_EQ(*Result->getAuxData<TestInt32>(), 42);\n}\n\n// Attempt to load something missing GTIRB's magic number\n// prefix.\nTEST(Unit_IR, loadNotGTIRB) {\n  std::stringstream Stream(\"JUNK\");\n  Context C;\n  auto Result = IR::load(C, Stream);\n  EXPECT_FALSE(Result);\n  EXPECT_EQ(Result, gtirb::IR::load_error::NotGTIRB);\n  std::stringstream Err;\n  Err << Result.getError();\n}\n\n// Attempt to load something w/ GTIRB magic but\n// invalid GTIRB protobuf version\nTEST(Unit_IR, loadWrongVersion) {\n  std::stringstream Stream(\"GTIRB\\0\\0\\255JUNK\");\n  Context C;\n  auto Result = IR::load(C, Stream);\n  EXPECT_FALSE(Result);\n  EXPECT_EQ(Result, gtirb::IR::load_error::IncorrectVersion);\n  std::stringstream Err;\n  Err << Result.getError();\n}\n\n// Attempt to load something w/ valid GTIRB prefix\n// but invalid protobuf content.\nTEST(Unit_IR, loadCorruptFile) {\n  std::stringstream Stream;\n  Stream << \"GTIRB\";\n  Stream << '\\0' << '\\0';\n  Stream << static_cast<uint8_t>(GTIRB_PROTOBUF_VERSION);\n  Stream << \"JUNK\";\n  Context C;\n  auto Result = IR::load(C, Stream);\n  EXPECT_FALSE(Result);\n  EXPECT_EQ(Result, gtirb::IR::load_error::CorruptFile);\n  std::stringstream Err;\n  Err << Result.getError();\n}\n\nTEST(Unit_IR, setModuleName) {\n  auto* Ir = IR::Create(Ctx);\n  auto* M1 = Ir->addModule(Ctx, \"a\");\n  auto* M2 = Ir->addModule(Ctx, \"b\");\n  auto* M3 = Ir->addModule(Ctx, \"c\");\n\n  M2->setName(\"d\");\n  EXPECT_EQ(std::distance(Ir->modules_begin(), Ir->modules_end()), 3);\n  auto It = Ir->modules_begin();\n  EXPECT_EQ(&*It++, M1);\n  EXPECT_EQ(&*It++, M3);\n  EXPECT_EQ(&*It++, M2);\n}\n\nTEST(Unit_IR, CFG) {\n  Module* M1 = Module::Create(Ctx, \"a\");\n  Section* S1 = M1->addSection(Ctx, \"a1\");\n  ByteInterval* BI1 = S1->addByteInterval(Ctx, 10);\n  BI1->addBlock<CodeBlock>(Ctx, 0, 10);\n  M1->addProxyBlock(Ctx);\n\n  Module* M2 = Module::Create(Ctx, \"b\");\n  Section* S2 = M2->addSection(Ctx, \"b2\");\n  ByteInterval* BI2 = S2->addByteInterval(Ctx, 1);\n  BI2->addBlock<DataBlock>(Ctx, 0, 1);\n  M2->addProxyBlock(Ctx);\n\n  IR* Ir = IR::Create(Ctx);\n  Ir->addModule(M1);\n  Ir->addModule(M2);\n\n  {\n    auto [Begin, End] = vertices(Ir->getCFG());\n    ASSERT_EQ(std::distance(Begin, End), 3);\n    EXPECT_EQ((std::set<CfgNode*>{Ir->getCFG()[*std::next(Begin, 0)],\n                                  Ir->getCFG()[*std::next(Begin, 1)],\n                                  Ir->getCFG()[*std::next(Begin, 2)]}),\n              (std::set<CfgNode*>{&*M1->proxy_blocks_begin(),\n                                  &*M1->code_blocks_begin(),\n                                  &*M2->proxy_blocks_begin()}));\n  }\n\n  Ir->removeModule(M1);\n\n  {\n    auto [Begin, End] = vertices(Ir->getCFG());\n    ASSERT_EQ(std::distance(Begin, End), 1);\n    EXPECT_EQ(Ir->getCFG()[*Begin], &*M2->proxy_blocks_begin());\n  }\n\n  Ir->addModule(M1);\n\n  {\n    auto [Begin, End] = vertices(Ir->getCFG());\n    ASSERT_EQ(std::distance(Begin, End), 3);\n    EXPECT_EQ((std::set<CfgNode*>{Ir->getCFG()[*std::next(Begin, 0)],\n                                  Ir->getCFG()[*std::next(Begin, 1)],\n                                  Ir->getCFG()[*std::next(Begin, 2)]}),\n              (std::set<CfgNode*>{&*M1->proxy_blocks_begin(),\n                                  &*M1->code_blocks_begin(),\n                                  &*M2->proxy_blocks_begin()}));\n  }\n\n  M1->removeSection(S1);\n\n  {\n    auto [Begin, End] = vertices(Ir->getCFG());\n    ASSERT_EQ(std::distance(Begin, End), 2);\n    EXPECT_EQ((std::set<CfgNode*>{Ir->getCFG()[*std::next(Begin, 0)],\n                                  Ir->getCFG()[*std::next(Begin, 1)]}),\n              (std::set<CfgNode*>{&*M1->proxy_blocks_begin(),\n                                  &*M2->proxy_blocks_begin()}));\n  }\n\n  BI1->addBlock<CodeBlock>(Ctx, 0, 5);\n  M1->addSection(S1);\n\n  {\n    auto [Begin, End] = vertices(Ir->getCFG());\n    ASSERT_EQ(std::distance(Begin, End), 4);\n    EXPECT_EQ((std::set<CfgNode*>{Ir->getCFG()[*std::next(Begin, 0)],\n                                  Ir->getCFG()[*std::next(Begin, 1)],\n                                  Ir->getCFG()[*std::next(Begin, 2)],\n                                  Ir->getCFG()[*std::next(Begin, 3)]}),\n              (std::set<CfgNode*>{&*M1->proxy_blocks_begin(),\n                                  &*M1->code_blocks_begin(),\n                                  &*std::next(M1->code_blocks_begin()),\n                                  &*M2->proxy_blocks_begin()}));\n  }\n\n  S1->removeByteInterval(BI1);\n\n  {\n    auto [Begin, End] = vertices(Ir->getCFG());\n    ASSERT_EQ(std::distance(Begin, End), 2);\n    EXPECT_EQ((std::set<CfgNode*>{Ir->getCFG()[*std::next(Begin, 0)],\n                                  Ir->getCFG()[*std::next(Begin, 1)]}),\n              (std::set<CfgNode*>{&*M1->proxy_blocks_begin(),\n                                  &*M2->proxy_blocks_begin()}));\n  }\n\n  S1->addByteInterval(BI1);\n\n  {\n    auto [Begin, End] = vertices(Ir->getCFG());\n    ASSERT_EQ(std::distance(Begin, End), 4);\n    EXPECT_EQ((std::set<CfgNode*>{Ir->getCFG()[*std::next(Begin, 0)],\n                                  Ir->getCFG()[*std::next(Begin, 1)],\n                                  Ir->getCFG()[*std::next(Begin, 2)],\n                                  Ir->getCFG()[*std::next(Begin, 3)]}),\n              (std::set<CfgNode*>{&*M1->proxy_blocks_begin(),\n                                  &*M1->code_blocks_begin(),\n                                  &*std::next(M1->code_blocks_begin()),\n                                  &*M2->proxy_blocks_begin()}));\n  }\n}\n"
  },
  {
    "path": "src/test/Main.test.cpp",
    "content": "#include \"Main.test.hpp\"\n#include <gtirb/Context.hpp>\n#include <gtirb/IR.hpp>\n#include <chrono>\n#include <fstream>\n#include <gtest/gtest.h>\n#include <string>\n#include <thread>\n\nvoid registerAuxDataContainerTestAuxDataTypes();\nvoid registerIrTestAuxDataTypes();\nvoid registerModuleTestAuxDataTypes();\n\nstatic gtirb::Context Ctx;\n\n// This is a GTIRB IR provided by the separate test program\n// PrepTestGTIRB.\nstatic gtirb::IR* TestIr = nullptr;\n\nconst gtirb::IR* getTestIr() { return TestIr; }\n\nstatic void loadTestIr(std::string Filename) {\n  std::ifstream GtirbFile;\n  GtirbFile.open(Filename, std::ifstream::in | std::ifstream::binary);\n\n  if (GtirbFile) {\n    auto MaybeTestIr = gtirb::IR::load(Ctx, GtirbFile);\n    if (MaybeTestIr) {\n      TestIr = *MaybeTestIr;\n    }\n  }\n  GtirbFile.close();\n}\n\nint main(int argc, char** argv) {\n  // Register aux data types needed by testing\n  registerAuxDataContainerTestAuxDataTypes();\n  registerIrTestAuxDataTypes();\n  registerModuleTestAuxDataTypes();\n\n  // Expect a gtirb filename passed as argv[1]\n  std::string GtirbFilename;\n  if (argc >= 2) {\n    GtirbFilename = argv[1];\n  }\n\n  std::stringstream error_msgs;\n  if (GtirbFilename.empty()) {\n    error_msgs << \"*\\n* No pre-built GTIRB file specified, cross-process tests \"\n                  \"will fail!\\n*\\n\";\n  } else {\n    loadTestIr(GtirbFilename);\n  }\n\n  ::testing::InitGoogleTest(&argc, argv);\n  auto rv = RUN_ALL_TESTS();\n  std::cerr << error_msgs.str();\n  return rv;\n}\n"
  },
  {
    "path": "src/test/Main.test.hpp",
    "content": "#ifndef MAIN_TEST_HPP\n#define MAIN_TEST_HPP\n\nnamespace gtirb {\nclass IR;\n};\n// Utility for getting a handle to a previously build GTIRB IR.\nconst gtirb::IR* getTestIr();\n\n#endif // MAIN_TEST_HPP\n"
  },
  {
    "path": "src/test/MergeSortedIterator.test.cpp",
    "content": "//===- MergeSortedIterator.test.cpp -----------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include <gtirb/Utility.hpp>\n#include <boost/range/iterator_range.hpp>\n#include <gtest/gtest.h>\n#include <vector>\n\nusing namespace gtirb;\n\nTEST(Unit_MergeSortedIterator, testCtor0) {\n  MergeSortedIterator<std::vector<int>::iterator> MSI;\n}\n\nTEST(Unit_MergeSortedIterator, testCtor1) {\n  using Vector = std::vector<int>;\n  using VectorIt = Vector::iterator;\n\n  Vector Evens = {2, 4, 6, 8};\n  Vector Odds = {1, 3, 5, 7};\n  std::vector<boost::iterator_range<VectorIt>> Its = {\n      boost::make_iterator_range(Evens), boost::make_iterator_range(Odds)};\n\n  MergeSortedIterator<std::vector<int>::iterator> Begin{Its};\n  MergeSortedIterator<std::vector<int>::iterator> End;\n\n  Vector Combined = {1, 2, 3, 4, 5, 6, 7, 8};\n  auto ExpectedIt = Combined.begin();\n  auto GotIt = Begin;\n  while (ExpectedIt != Combined.end() && GotIt != End) {\n    ASSERT_EQ(*ExpectedIt, *GotIt);\n    ++ExpectedIt;\n    ++GotIt;\n  }\n  ASSERT_EQ(ExpectedIt, Combined.end());\n  ASSERT_EQ(GotIt, End);\n}\n\nTEST(Unit_MergeSortedIterator, testCtor2) {\n  using Vector = std::vector<int>;\n  using VectorIt = Vector::iterator;\n\n  Vector Evens = {2, 4, 6, 8};\n  Vector Odds = {1, 3, 5, 7};\n  std::vector<boost::iterator_range<VectorIt>> Its = {\n      boost::make_iterator_range(Evens), boost::make_iterator_range(Odds)};\n\n  MergeSortedIterator<std::vector<int>::iterator> Begin{Its.begin(), Its.end()};\n  MergeSortedIterator<std::vector<int>::iterator> End;\n\n  Vector Combined = {1, 2, 3, 4, 5, 6, 7, 8};\n  auto ExpectedIt = Combined.begin();\n  auto GotIt = Begin;\n  while (ExpectedIt != Combined.end() && GotIt != End) {\n    ASSERT_EQ(*ExpectedIt, *GotIt);\n    ++ExpectedIt;\n    ++GotIt;\n  }\n  ASSERT_EQ(ExpectedIt, Combined.end());\n  ASSERT_EQ(GotIt, End);\n}\n\nstruct CustomCompare {\n  bool operator()(int x, int y) const { return x >= y; }\n};\n\nTEST(Unit_MergeSortedIterator, testCustomCompare) {\n  using Vector = std::vector<int>;\n  using VectorIt = Vector::iterator;\n\n  Vector Evens = {8, 6, 4, 2};\n  Vector Odds = {7, 5, 3, 1};\n  std::vector<boost::iterator_range<VectorIt>> Its = {\n      boost::make_iterator_range(Evens), boost::make_iterator_range(Odds)};\n\n  MergeSortedIterator<std::vector<int>::iterator, CustomCompare> Begin{Its};\n  MergeSortedIterator<std::vector<int>::iterator, CustomCompare> End;\n\n  Vector Combined = {8, 7, 6, 5, 4, 3, 2, 1};\n  auto ExpectedIt = Combined.begin();\n  auto GotIt = Begin;\n  while (ExpectedIt != Combined.end() && GotIt != End) {\n    ASSERT_EQ(*ExpectedIt, *GotIt);\n    ++ExpectedIt;\n    ++GotIt;\n  }\n  ASSERT_EQ(ExpectedIt, Combined.end());\n  ASSERT_EQ(GotIt, End);\n}\n\nTEST(Unit_MergeSortedIterator, testEmptyRanges) {\n  using Vector = std::vector<int>;\n  using VectorIt = Vector::iterator;\n\n  Vector Evens = {2, 4, 6, 8};\n  Vector Empty = {};\n  Vector Odds = {1, 3, 5, 7};\n  std::vector<boost::iterator_range<VectorIt>> Its = {\n      boost::make_iterator_range(Evens), boost::make_iterator_range(Empty),\n      boost::make_iterator_range(Odds)};\n\n  MergeSortedIterator<std::vector<int>::iterator> Begin{Its};\n  MergeSortedIterator<std::vector<int>::iterator> End;\n\n  Vector Combined = {1, 2, 3, 4, 5, 6, 7, 8};\n  auto ExpectedIt = Combined.begin();\n  auto GotIt = Begin;\n  while (ExpectedIt != Combined.end() && GotIt != End) {\n    ASSERT_EQ(*ExpectedIt, *GotIt);\n    ++ExpectedIt;\n    ++GotIt;\n  }\n  ASSERT_EQ(ExpectedIt, Combined.end());\n  ASSERT_EQ(GotIt, End);\n}\n"
  },
  {
    "path": "src/test/Module.test.cpp",
    "content": "//===- Module.test.cpp ------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2021 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"SerializationTestHarness.hpp\"\n#include <gtirb/AuxData.hpp>\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/Context.hpp>\n#include <gtirb/DataBlock.hpp>\n#include <gtirb/IR.hpp>\n#include <gtirb/Module.hpp>\n#include <gtirb/Section.hpp>\n#include <gtirb/Symbol.hpp>\n#include <gtirb/SymbolicExpression.hpp>\n#include <gtirb/proto/Module.pb.h>\n#include <algorithm>\n#include <gtest/gtest.h>\n#include <iterator>\n#include <sstream>\n#include <tuple>\n#include <utility>\n\nnamespace gtirb {\nnamespace schema {\n\nstruct Foo {\n  static constexpr const char* Name = \"foo\";\n  typedef std::vector<int64_t> Type;\n};\n\nstruct Bar {\n  static constexpr const char* Name = \"bar\";\n  typedef std::vector<char> Type;\n};\n\nstruct AnTest {\n  static constexpr const char* Name = \"test\";\n  typedef uint32_t Type;\n};\n\n} // namespace schema\n} // namespace gtirb\n\nusing namespace gtirb;\nusing namespace gtirb::schema;\n\nvoid registerModuleTestAuxDataTypes() {\n  AuxDataContainer::registerAuxDataType<Foo>();\n  AuxDataContainer::registerAuxDataType<Bar>();\n  AuxDataContainer::registerAuxDataType<AnTest>();\n}\n\nTEST(Unit_Module, compilationIteratorTypes) {\n  static_assert(\n      std::is_same_v<Module::code_block_iterator::reference, CodeBlock&>);\n  static_assert(std::is_same_v<Module::const_code_block_iterator::reference,\n                               const CodeBlock&>);\n  static_assert(std::is_same_v<Module::code_block_subrange::iterator::reference,\n                               CodeBlock&>);\n  static_assert(\n      std::is_same_v<Module::const_code_block_subrange::iterator::reference,\n                     const CodeBlock&>);\n\n  static_assert(\n      std::is_same_v<Module::data_block_iterator::reference, DataBlock&>);\n  static_assert(std::is_same_v<Module::const_data_block_iterator::reference,\n                               const DataBlock&>);\n  static_assert(std::is_same_v<Module::data_block_subrange::iterator::reference,\n                               DataBlock&>);\n  static_assert(\n      std::is_same_v<Module::const_data_block_subrange::iterator::reference,\n                     const DataBlock&>);\n\n  static_assert(std::is_same_v<Module::section_iterator::reference, Section&>);\n  static_assert(std::is_same_v<Module::const_section_iterator::reference,\n                               const Section&>);\n  static_assert(\n      std::is_same_v<Module::section_name_iterator::reference, Section&>);\n  static_assert(std::is_same_v<Module::const_section_name_iterator::reference,\n                               const Section&>);\n  static_assert(\n      std::is_same_v<Module::section_subrange::iterator::reference, Section&>);\n  static_assert(\n      std::is_same_v<Module::const_section_subrange::iterator::reference,\n                     const Section&>);\n\n  static_assert(std::is_same_v<Module::symbolic_expression_iterator::reference,\n                               ByteInterval::SymbolicExpressionElement>);\n  static_assert(\n      std::is_same_v<Module::const_symbolic_expression_iterator::reference,\n                     ByteInterval::ConstSymbolicExpressionElement>);\n\n  static_assert(std::is_same_v<Module::symbol_iterator::reference, Symbol&>);\n  static_assert(\n      std::is_same_v<Module::const_symbol_iterator::reference, const Symbol&>);\n  static_assert(\n      std::is_same_v<Module::symbol_addr_iterator::reference, Symbol&>);\n  static_assert(std::is_same_v<Module::const_symbol_addr_iterator::reference,\n                               const Symbol&>);\n}\n\nTEST(Unit_Module, noCopyMoveConstructors) {\n  EXPECT_FALSE(std::is_copy_constructible_v<Module>);\n  EXPECT_FALSE(std::is_move_constructible_v<Module>);\n  EXPECT_FALSE(std::is_copy_assignable_v<Module>);\n  EXPECT_FALSE(std::is_move_assignable_v<Module>);\n}\n\nstatic Context Ctx;\n\nTEST(Unit_Module, ctor_0) { EXPECT_NE(Module::Create(Ctx, \"M\"), nullptr); }\n\nTEST(Unit_Module, setBinaryPath) {\n  const std::string StrPath(\"/home/gt/irb/foo\");\n  auto* M = Module::Create(Ctx, \"M\");\n\n  M->setBinaryPath(StrPath);\n\n  const auto& Path = M->getBinaryPath();\n  EXPECT_EQ(StrPath, Path);\n}\n\nTEST(Unit_Module, getFileFormatDefault) {\n  auto* M = Module::Create(Ctx, \"M\");\n  EXPECT_EQ(gtirb::FileFormat::Undefined, M->getFileFormat());\n}\n\nTEST(Unit_Module, auxDataRanges) {\n  auto* M = Module::Create(Ctx, \"M\");\n  M->addAuxData<Foo>(std::vector<int64_t>{1, 2, 3});\n  M->addAuxData<Bar>(std::vector<char>{'a', 'b', 'c'});\n\n  auto A = M->aux_data();\n  EXPECT_EQ(std::distance(A.begin(), A.end()), 2);\n  // AuxDatas are sorted by range, but this is an implementation detail\n  EXPECT_EQ(A.begin()->Key, Bar::Name);\n  EXPECT_EQ((++A.begin())->Key, Foo::Name);\n}\n\nTEST(Unit_Module, setFileFormat) {\n  auto* M = Module::Create(Ctx, \"M\");\n\n  M->setFileFormat(gtirb::FileFormat::COFF);\n  EXPECT_EQ(gtirb::FileFormat::COFF, M->getFileFormat());\n\n  M->setFileFormat(gtirb::FileFormat::MACHO);\n  EXPECT_EQ(gtirb::FileFormat::MACHO, M->getFileFormat());\n\n  M->setFileFormat(gtirb::FileFormat::Undefined);\n  EXPECT_EQ(gtirb::FileFormat::Undefined, M->getFileFormat());\n}\n\nTEST(Unit_Module, getRebaseDeltaDefault) {\n  auto* M = Module::Create(Ctx, \"M\");\n  EXPECT_EQ(int64_t{0}, M->getRebaseDelta());\n}\n\nTEST(Unit_Module, setRebaseDelta) {\n  auto* M = Module::Create(Ctx, \"M\");\n\n  EXPECT_FALSE(M->isRelocated());\n\n  M->setRebaseDelta(1);\n  EXPECT_EQ(int64_t{1}, M->getRebaseDelta());\n  EXPECT_TRUE(M->isRelocated());\n\n  M->setRebaseDelta(-1);\n  EXPECT_EQ(int64_t{-1}, M->getRebaseDelta());\n  EXPECT_TRUE(M->isRelocated());\n\n  M->setRebaseDelta(std::numeric_limits<int64_t>::max());\n  EXPECT_EQ(std::numeric_limits<int64_t>::max(), M->getRebaseDelta());\n  EXPECT_TRUE(M->isRelocated());\n\n  M->setRebaseDelta(std::numeric_limits<int64_t>::min());\n  EXPECT_EQ(std::numeric_limits<int64_t>::min(), M->getRebaseDelta());\n  EXPECT_TRUE(M->isRelocated());\n\n  M->setRebaseDelta(std::numeric_limits<int64_t>::lowest());\n  EXPECT_EQ(std::numeric_limits<int64_t>::lowest(), M->getRebaseDelta());\n  EXPECT_TRUE(M->isRelocated());\n}\n\nTEST(Unit_Module, getPreferredAddrDefault) {\n  auto* M = Module::Create(Ctx, \"M\");\n  EXPECT_EQ(Addr{}, M->getPreferredAddr());\n}\n\nTEST(Unit_Module, getISA) {\n  auto* M = Module::Create(Ctx, \"M\");\n\n  EXPECT_EQ(gtirb::ISA::Undefined, M->getISA());\n\n  M->setISA(gtirb::ISA::X64);\n  EXPECT_EQ(gtirb::ISA::X64, M->getISA());\n}\n\nTEST(Unit_Module, getByteOrder) {\n  auto* M = Module::Create(Ctx, \"M\");\n\n  EXPECT_EQ(gtirb::ByteOrder::Undefined, M->getByteOrder());\n\n  M->setByteOrder(gtirb::ByteOrder::Big);\n  EXPECT_EQ(gtirb::ByteOrder::Big, M->getByteOrder());\n}\n\nTEST(Unit_Module, setPreferredAddr) {\n  auto* M = Module::Create(Ctx, \"M\");\n  Addr Preferred{64};\n\n  EXPECT_EQ(M->getPreferredAddr(), Addr(0));\n\n  M->setPreferredAddr(Preferred);\n  EXPECT_EQ(Preferred, M->getPreferredAddr());\n}\n\nTEST(Unit_Module, getSymbolSet) {\n  auto* M = Module::Create(Ctx, \"M\");\n  EXPECT_EQ(std::distance(M->symbols().begin(), M->symbols().end()), 0);\n}\n\nTEST(Unit_Module, getName) {\n  auto* M = Module::Create(Ctx, \"M\");\n  EXPECT_EQ(M->getName(), \"M\");\n}\n\nTEST(Unit_Module, setName) {\n  auto* M = Module::Create(Ctx, \"M\");\n  EXPECT_EQ(M->getName(), \"M\");\n\n  M->setName(\"test\");\n  EXPECT_EQ(M->getName(), \"test\");\n}\n\nTEST(Unit_Module, sections) {\n  auto* M = Module::Create(Ctx, \"M\");\n  M->addSection(Ctx, \"test\");\n  EXPECT_EQ(M->sections_begin()->getName(), \"test\");\n  EXPECT_EQ(std::distance(M->sections_begin(), M->sections_end()), 1);\n  EXPECT_EQ(\n      std::distance(M->sections_by_name_begin(), M->sections_by_name_end()), 1);\n}\n\nTEST(Unit_Module, byteIntervals) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S1 = M->addSection(Ctx, \"gamma\");\n  auto* S2 = M->addSection(Ctx, \"beta\");\n  auto* S3 = M->addSection(Ctx, \"alpha\");\n  auto* BI1 = S1->addByteInterval(Ctx, 10);\n  auto* BI2 = S2->addByteInterval(Ctx, Addr(0), 10);\n  auto* BI3 = S3->addByteInterval(Ctx, Addr(10), 10);\n\n  // Create CodeBlocks and Symbols such that pointers do not change\n  // monotonically with respect to address. This will help determine whether\n  // CodeBlock and Symbol iteration is updated properly when ByteIntervals are\n  // relocated.\n\n  CodeBlock* CB[20];\n  Symbol* Sym[20];\n  for (int i = 0; i < 10; ++i) {\n    int index = (i & 0x1) ? 4 - (i >> 1) : 5 + (i >> 1);\n    CB[index] = BI2->addBlock<CodeBlock>(Ctx, index, 1);\n    CB[index + 10] = BI3->addBlock<CodeBlock>(Ctx, index, 1);\n\n    std::string name = \"sym_\";\n    Sym[index] = M->addSymbol(Ctx, CB[index], name.append(1, 'a' + index));\n    Sym[index + 10] =\n        M->addSymbol(Ctx, CB[index + 10], name.append(1, 'a' + index + 10));\n  }\n  for (int i = 0; i < 20; ++i) {\n    ASSERT_EQ(CB[i]->getAddress(), Addr(i));\n    ASSERT_EQ(Sym[i]->getAddress(), Addr(i));\n  }\n\n  // Iteration should be in order of increasing start address.\n  ASSERT_EQ(std::distance(M->byte_intervals_begin(), M->byte_intervals_end()),\n            3);\n  EXPECT_EQ(&*std::next(M->byte_intervals_begin(), 0), BI1);\n  EXPECT_EQ(&*std::next(M->byte_intervals_begin(), 1), BI2);\n  EXPECT_EQ(&*std::next(M->byte_intervals_begin(), 2), BI3);\n\n  ASSERT_EQ(std::distance(M->sections_begin(), M->sections_end()), 3);\n  EXPECT_EQ(&*std::next(M->sections_begin(), 0), S1);\n  EXPECT_EQ(&*std::next(M->sections_begin(), 1), S2);\n  EXPECT_EQ(&*std::next(M->sections_begin(), 2), S3);\n\n  // CodeBlocks and symbols should be in order.\n  ASSERT_EQ(std::distance(M->code_blocks_begin(), M->code_blocks_end()), 20);\n  for (int i = 0; i < 20; ++i) {\n    CodeBlock& CBi = *std::next(M->code_blocks_begin(), i);\n    EXPECT_EQ(CBi.getAddress(), Addr(i));\n    EXPECT_EQ(&CBi, CB[i]);\n  }\n\n  ASSERT_EQ(std::distance(M->symbols_by_addr_begin(), M->symbols_by_addr_end()),\n            20);\n  for (int i = 0; i < 20; ++i) {\n    Symbol& S = *std::next(M->symbols_by_addr_begin(), i);\n    EXPECT_EQ(S.getAddress(), Addr(i));\n    EXPECT_EQ(&S, Sym[i]);\n  }\n\n  // Iteration should be alphabetical by section name.\n  ASSERT_EQ(\n      std::distance(M->sections_by_name_begin(), M->sections_by_name_end()), 3);\n  EXPECT_EQ(&*std::next(M->sections_by_name_begin(), 0), S3);\n  EXPECT_EQ(&*std::next(M->sections_by_name_begin(), 1), S2);\n  EXPECT_EQ(&*std::next(M->sections_by_name_begin(), 2), S1);\n\n  BI2->setAddress(Addr(20));\n\n  // BI2 should now come last...\n  ASSERT_EQ(std::distance(M->byte_intervals_begin(), M->byte_intervals_end()),\n            3);\n  EXPECT_EQ(&*std::next(M->byte_intervals_begin(), 0), BI1);\n  EXPECT_EQ(&*std::next(M->byte_intervals_begin(), 1), BI3);\n  EXPECT_EQ(&*std::next(M->byte_intervals_begin(), 2), BI2);\n\n  ASSERT_EQ(std::distance(M->sections_begin(), M->sections_end()), 3);\n  EXPECT_EQ(&*std::next(M->sections_begin(), 0), S1);\n  EXPECT_EQ(&*std::next(M->sections_begin(), 1), S3);\n  EXPECT_EQ(&*std::next(M->sections_begin(), 2), S2);\n\n  // The first 10 CodeBlocks and Symbols (in BI2) should come after the second\n  // 10 (in BI3).\n  ASSERT_EQ(std::distance(M->code_blocks_begin(), M->code_blocks_end()), 20);\n  for (int i = 0; i < 10; ++i) {\n    CodeBlock& CBi = *std::next(M->code_blocks_begin(), i);\n    EXPECT_EQ(CBi.getAddress(), Addr(i + 10));\n    EXPECT_EQ(&CBi, CB[i + 10]);\n  }\n  for (int i = 0; i < 10; ++i) {\n    CodeBlock& CBi = *std::next(M->code_blocks_begin(), i + 10);\n    EXPECT_EQ(CBi.getAddress(), Addr(i + 20));\n    EXPECT_EQ(&CBi, CB[i]);\n  }\n\n  ASSERT_EQ(std::distance(M->symbols_by_addr_begin(), M->symbols_by_addr_end()),\n            20);\n  for (int i = 0; i < 10; ++i) {\n    Symbol& S = *std::next(M->symbols_by_addr_begin(), i);\n    EXPECT_EQ(S.getAddress(), Addr(i + 10));\n    EXPECT_EQ(&S, Sym[i + 10]);\n  }\n  for (int i = 0; i < 10; ++i) {\n    Symbol& S = *std::next(M->symbols_by_addr_begin(), i + 10);\n    EXPECT_EQ(S.getAddress(), Addr(i + 20));\n    EXPECT_EQ(&S, Sym[i]);\n  }\n\n  // Iteration should be unaffected by changing addresses...\n  ASSERT_EQ(\n      std::distance(M->sections_by_name_begin(), M->sections_by_name_end()), 3);\n  EXPECT_EQ(&*std::next(M->sections_by_name_begin(), 0), S3);\n  EXPECT_EQ(&*std::next(M->sections_by_name_begin(), 1), S2);\n  EXPECT_EQ(&*std::next(M->sections_by_name_begin(), 2), S1);\n}\n\nTEST(Unit_Module, findByteIntervalsOn) {\n  auto* M = Module::Create(Ctx, \"test\");\n  auto* S1 = M->addSection(Ctx, \"S1\");\n  auto* BI1 = S1->addByteInterval(Ctx, 16);\n  auto* S2 = M->addSection(Ctx, \"S2\");\n  auto* BI2 = S2->addByteInterval(Ctx, Addr(8), 12);\n  auto* S3 = M->addSection(Ctx, \"S3\");\n  auto* BI3 = S3->addByteInterval(Ctx, Addr(13), 8);\n  const Module* CM = M;\n\n  // Querying an out-of-bounds address returns an empty range.\n\n  auto Range = M->findByteIntervalsOn(Addr(0));\n  EXPECT_TRUE(Range.empty());\n\n  auto ConstRange = CM->findByteIntervalsOn(Addr(0));\n  EXPECT_TRUE(Range.empty());\n\n  // Querying a in-bounds address returns the correct range.\n\n  Range = M->findByteIntervalsOn(Addr(12));\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 1);\n  EXPECT_EQ(&*Range.begin(), BI2);\n\n  ConstRange = CM->findByteIntervalsOn(Addr(12));\n  ASSERT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 1);\n  EXPECT_EQ(&*ConstRange.begin(), BI2);\n\n  // Query returns correct set after addresses are updated.\n\n  BI1->setAddress(Addr(0));\n  Range = M->findByteIntervalsOn(Addr(0));\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 1);\n  EXPECT_EQ(&*Range.begin(), BI1);\n\n  ConstRange = CM->findByteIntervalsOn(Addr(0));\n  ASSERT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 1);\n  EXPECT_EQ(&*ConstRange.begin(), BI1);\n\n  Range = M->findByteIntervalsOn(Addr(12));\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 2);\n  EXPECT_EQ(&*std::next(Range.begin(), 0), BI1);\n  EXPECT_EQ(&*std::next(Range.begin(), 1), BI2);\n\n  ConstRange = CM->findByteIntervalsOn(Addr(12));\n  ASSERT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 0), BI1);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 1), BI2);\n\n  // Query is correct for ByteIntervals with overlapping start addresses.\n\n  BI1->setAddress(Addr(13));\n  Range = M->findByteIntervalsOn(Addr(14));\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 3);\n  EXPECT_EQ(&*std::next(Range.begin(), 0), BI2);\n  EXPECT_EQ(&*std::next(Range.begin(), 1), BI3);\n  EXPECT_EQ(&*std::next(Range.begin(), 2), BI1);\n\n  ConstRange = CM->findByteIntervalsOn(Addr(14));\n  ASSERT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 0), BI2);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 1), BI3);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 2), BI1);\n\n  // Moving a ByteInterval does not leave duplicates in codomain tree.\n\n  BI2->setAddress(Addr(13));\n  Range = M->findByteIntervalsOn(Addr(14));\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 3);\n  EXPECT_EQ(&*std::next(Range.begin(), 0), BI3);\n  EXPECT_EQ(&*std::next(Range.begin(), 1), BI2);\n  EXPECT_EQ(&*std::next(Range.begin(), 2), BI1);\n\n  ConstRange = CM->findByteIntervalsOn(Addr(14));\n  ASSERT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 0), BI3);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 1), BI2);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 2), BI1);\n\n  // Removing a ByteInterval with an overlapping address does not remove others.\n\n  BI3->setAddress(std::nullopt);\n  Range = M->findByteIntervalsOn(Addr(14));\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 2);\n  EXPECT_EQ(&*std::next(Range.begin(), 0), BI2);\n  EXPECT_EQ(&*std::next(Range.begin(), 1), BI1);\n\n  ConstRange = CM->findByteIntervalsOn(Addr(14));\n  ASSERT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 0), BI2);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 1), BI1);\n}\n\nTEST(Unit_Module, findSections) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S1 = M->addSection(Ctx, \"S1\");\n  auto* S2 = M->addSection(Ctx, \"S2\");\n  auto* S22 = M->addSection(Ctx, \"S2\");\n  auto* S3 = M->addSection(Ctx, \"S3\");\n  auto* BI1 = S1->addByteInterval(Ctx, Addr(1), 123);\n  auto* BI2 = S2->addByteInterval(Ctx, 100);\n  S3->addByteInterval(Ctx, Addr(50), 50);\n  S22->addByteInterval(Ctx, Addr(2), 22);\n\n  {\n    auto F = M->findSectionsOn(Addr(1));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(F.begin()->getName(), \"S1\");\n\n    F = M->findSectionsOn(Addr(50));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 2);\n    EXPECT_EQ(std::next(F.begin(), 0)->getName(), \"S1\");\n    EXPECT_EQ(std::next(F.begin(), 1)->getName(), \"S3\");\n\n    F = M->findSectionsOn(Addr(123));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(F.begin()->getName(), \"S1\");\n\n    F = M->findSectionsOn(Addr(124));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 0);\n  }\n\n  BI2->setAddress(Addr(50));\n\n  {\n    auto F = M->findSectionsOn(Addr(1));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(std::next(F.begin(), 0)->getName(), \"S1\");\n\n    F = M->findSectionsOn(Addr(50));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 3);\n    EXPECT_EQ(std::next(F.begin(), 0)->getName(), \"S1\");\n    EXPECT_EQ(std::next(F.begin(), 1)->getName(), \"S3\");\n    EXPECT_EQ(std::next(F.begin(), 2)->getName(), \"S2\");\n  }\n\n  BI1->setAddress(Addr(50));\n\n  {\n    auto F = M->findSectionsOn(Addr(1));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 0);\n\n    F = M->findSectionsOn(Addr(50));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 3);\n    EXPECT_EQ(std::next(F.begin(), 0)->getName(), \"S3\");\n    EXPECT_EQ(std::next(F.begin(), 1)->getName(), \"S2\");\n    EXPECT_EQ(std::next(F.begin(), 2)->getName(), \"S1\");\n  }\n\n  BI1->setAddress(std::nullopt);\n\n  {\n    auto F = M->findSectionsOn(Addr(1));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 0);\n\n    F = M->findSectionsOn(Addr(50));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 2);\n    EXPECT_EQ(std::next(F.begin(), 0)->getName(), \"S3\");\n    EXPECT_EQ(std::next(F.begin(), 1)->getName(), \"S2\");\n  }\n\n  {\n    auto F = M->findSections(\"S1\");\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(std::next(F.begin(), 0)->getName(), \"S1\");\n\n    F = M->findSections(\"S2\");\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 2);\n    EXPECT_EQ(std::next(F.begin(), 0)->getName(), \"S2\");\n    EXPECT_EQ(std::next(F.begin(), 1)->getName(), \"S2\");\n\n    F = M->findSections(\"dummy\");\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 0);\n  }\n}\n\nTEST(Unit_Module, sectionNameOrder) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S1 = M->addSection(Ctx, \"gamma\");\n  auto* S2 = M->addSection(Ctx, \"beta\");\n  auto* S3 = M->addSection(Ctx, \"alpha\");\n\n  ASSERT_EQ(\n      std::distance(M->sections_by_name_begin(), M->sections_by_name_end()), 3);\n  EXPECT_EQ(&*std::next(M->sections_by_name_begin(), 0), S3); // alpha\n  EXPECT_EQ(&*std::next(M->sections_by_name_begin(), 1), S2); // beta\n  EXPECT_EQ(&*std::next(M->sections_by_name_begin(), 2), S1); // gamma\n\n  S2->setName(\"omega\");\n  ASSERT_EQ(\n      std::distance(M->sections_by_name_begin(), M->sections_by_name_end()), 3);\n  EXPECT_EQ(&*std::next(M->sections_by_name_begin(), 0), S3); // alpha\n  EXPECT_EQ(&*std::next(M->sections_by_name_begin(), 1), S1); // gamma\n  EXPECT_EQ(&*std::next(M->sections_by_name_begin(), 2), S2); // omega\n}\n\nTEST(Unit_Module, blocks) {\n  auto I = IR::Create(Ctx);\n  auto M = I->addModule(Ctx, \"M\");\n  auto S = M->addSection(Ctx, \"test\");\n  auto BI = S->addByteInterval(Ctx, Addr(1), 10);\n  BI->addBlock<CodeBlock>(Ctx, 0, 10);\n\n  ASSERT_EQ(std::distance(M->code_blocks_begin(), M->code_blocks_end()), 1);\n  EXPECT_EQ(M->code_blocks_begin()->getAddress(), std::optional<Addr>(Addr(1)));\n\n  auto F = blocks(M->getIR()->getCFG());\n  ASSERT_EQ(std::distance(F.begin(), F.end()), 1);\n  EXPECT_EQ(F.begin()->getAddress(), Addr(1));\n}\n\nTEST(Unit_Module, cfgNodes) {\n  auto* I = IR::Create(Ctx);\n  auto* M = I->addModule(Ctx, \"M\");\n  auto S = M->addSection(Ctx, \"test\");\n  auto BI = S->addByteInterval(Ctx, Addr(1), 10);\n  auto* B = BI->addBlock<CodeBlock>(Ctx, 0, 10);\n  auto* P = M->addProxyBlock(Ctx);\n\n  EXPECT_EQ(std::distance(M->code_blocks_begin(), M->code_blocks_end()), 1);\n  auto Nodes = nodes(M->getIR()->getCFG());\n  EXPECT_EQ(std::distance(Nodes.begin(), Nodes.end()), 2);\n  auto It = Nodes.begin();\n  EXPECT_TRUE(&*It == B || &*It == P);\n  ++It;\n  EXPECT_NE(&*Nodes.begin(), &*It);\n  EXPECT_TRUE(&*It == B || &*It == P);\n}\n\nTEST(Unit_Module, findBlock) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S = M->addSection(Ctx, \"test\");\n  auto* BI = S->addByteInterval(Ctx, Addr(0), 30);\n  auto* B1 = BI->addBlock<CodeBlock>(Ctx, 1, 20);\n  auto* B2 = BI->addBlock<CodeBlock>(Ctx, 5, 10);\n\n  {\n    auto F = M->findCodeBlocksOn(Addr(0));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 0);\n\n    F = M->findCodeBlocksOn(Addr(1));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), B1);\n\n    F = M->findCodeBlocksOn(Addr(5));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 2);\n    EXPECT_EQ(&*F.begin(), B1);\n    EXPECT_EQ(&*++F.begin(), B2);\n\n    F = M->findCodeBlocksOn(Addr(14));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 2);\n    EXPECT_EQ(&*F.begin(), B1);\n    EXPECT_EQ(&*++F.begin(), B2);\n\n    F = M->findCodeBlocksOn(Addr(15));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), B1);\n\n    F = M->findCodeBlocksOn(Addr(20));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), B1);\n\n    F = M->findCodeBlocksOn(Addr(21));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 0);\n  }\n}\n\nTEST(Unit_Module, findBlocksOn) {\n  auto* M = Module::Create(Ctx, \"test\");\n  auto* S1 = M->addSection(Ctx, \"S1\");\n  auto* BI1 = S1->addByteInterval(Ctx, 16);\n  auto* CB11 = BI1->addBlock<CodeBlock>(Ctx, 0, 4);\n  auto* S2 = M->addSection(Ctx, \"S2\");\n  auto* BI2 = S2->addByteInterval(Ctx, Addr(0), 10);\n  auto* CB21 = BI2->addBlock<CodeBlock>(Ctx, 0, 2);\n  auto* CB22 = BI2->addBlock<CodeBlock>(Ctx, 5, 2);\n  auto* S3 = M->addSection(Ctx, \"S3\");\n  auto* BI3 = S3->addByteInterval(Ctx, Addr(4), 4);\n  auto* CB31 = BI3->addBlock<CodeBlock>(Ctx, 0, 3);\n  const Module* CM = M;\n\n  // Querying an out-of-bounds offset produces an empty range.\n\n  auto BlockRange = M->findBlocksOn(Addr(10));\n  EXPECT_TRUE(BlockRange.empty());\n\n  auto ConstBlockRange = CM->findBlocksOn(Addr(10));\n  EXPECT_TRUE(ConstBlockRange.empty());\n\n  // Querying an in-bounds offset returns the appropriate blocks from all\n  // ByteIntervals.\n\n  BlockRange = M->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB22);\n\n  ConstBlockRange = CM->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB22);\n\n  // Assigning a ByteInterval address may change the query results.\n\n  BI1->setAddress(Addr(4));\n\n  BlockRange = M->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB22);\n\n  ConstBlockRange = CM->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB22);\n\n  // Changing a ByteInterval's address may change the query results.\n\n  BI2->setAddress(Addr(4));\n\n  BlockRange = M->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB11);\n\n  ConstBlockRange = CM->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB11);\n\n  BI3->setAddress(Addr(0));\n\n  BlockRange = M->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n\n  ConstBlockRange = CM->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n}\n\nTEST(Unit_Module, findCodeBlocksOn) {\n  auto* M = Module::Create(Ctx, \"test\");\n  auto* S1 = M->addSection(Ctx, \"S1\");\n  auto* BI1 = S1->addByteInterval(Ctx, 16);\n  auto* CB11 = BI1->addBlock<CodeBlock>(Ctx, 0, 4);\n  auto* S2 = M->addSection(Ctx, \"S2\");\n  auto* BI2 = S2->addByteInterval(Ctx, Addr(0), 10);\n  auto* CB21 = BI2->addBlock<CodeBlock>(Ctx, 0, 2);\n  auto* CB22 = BI2->addBlock<CodeBlock>(Ctx, 5, 2);\n  auto* S3 = M->addSection(Ctx, \"S3\");\n  auto* BI3 = S3->addByteInterval(Ctx, Addr(4), 4);\n  auto* CB31 = BI3->addBlock<CodeBlock>(Ctx, 0, 3);\n  const Module* CM = M;\n\n  // Querying an out-of-bounds offset produces an empty range.\n\n  auto BlockRange = M->findCodeBlocksOn(Addr(10));\n  EXPECT_TRUE(BlockRange.empty());\n\n  auto ConstBlockRange = CM->findCodeBlocksOn(Addr(10));\n  EXPECT_TRUE(ConstBlockRange.empty());\n\n  // Querying an in-bounds offset returns the appropriate blocks from all\n  // ByteIntervals.\n\n  BlockRange = M->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB22);\n\n  ConstBlockRange = CM->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB22);\n\n  // Assigning a ByteInterval address may change the query results.\n\n  BI1->setAddress(Addr(4));\n\n  BlockRange = M->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB22);\n\n  ConstBlockRange = CM->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB22);\n\n  // Changing a ByteInterval's address may change the query results.\n\n  BI2->setAddress(Addr(4));\n\n  BlockRange = M->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB11);\n\n  ConstBlockRange = CM->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB11);\n\n  BI3->setAddress(Addr(0));\n\n  BlockRange = M->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n\n  ConstBlockRange = CM->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n}\n\nTEST(Unit_Module, findDataBlocksOn) {\n  auto* M = Module::Create(Ctx, \"test\");\n  auto* S1 = M->addSection(Ctx, \"S1\");\n  auto* BI1 = S1->addByteInterval(Ctx, 16);\n  auto* CB11 = BI1->addBlock<DataBlock>(Ctx, 0, 4);\n  auto* S2 = M->addSection(Ctx, \"S2\");\n  auto* BI2 = S2->addByteInterval(Ctx, Addr(0), 10);\n  auto* CB21 = BI2->addBlock<DataBlock>(Ctx, 0, 2);\n  auto* CB22 = BI2->addBlock<DataBlock>(Ctx, 5, 2);\n  auto* S3 = M->addSection(Ctx, \"S3\");\n  auto* BI3 = S3->addByteInterval(Ctx, Addr(4), 4);\n  auto* CB31 = BI3->addBlock<DataBlock>(Ctx, 0, 3);\n  const Module* CM = M;\n\n  // Querying an out-of-bounds offset produces an empty range.\n\n  auto BlockRange = M->findDataBlocksOn(Addr(10));\n  EXPECT_TRUE(BlockRange.empty());\n\n  auto ConstBlockRange = CM->findDataBlocksOn(Addr(10));\n  EXPECT_TRUE(ConstBlockRange.empty());\n\n  // Querying an in-bounds offset returns the appropriate blocks from all\n  // ByteIntervals.\n\n  BlockRange = M->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB22);\n\n  ConstBlockRange = CM->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB22);\n\n  // Assigning a ByteInterval address may change the query results.\n\n  BI1->setAddress(Addr(4));\n\n  BlockRange = M->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB22);\n\n  ConstBlockRange = CM->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB22);\n\n  // Changing a ByteInterval's address may change the query results.\n\n  BI2->setAddress(Addr(4));\n\n  BlockRange = M->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB11);\n\n  ConstBlockRange = CM->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB11);\n\n  BI3->setAddress(Addr(0));\n\n  BlockRange = M->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n\n  ConstBlockRange = CM->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n}\n\nTEST(Unit_Module, findBlocksAt) {\n  auto* M = Module::Create(Ctx, \"test\");\n  auto* S1 = M->addSection(Ctx, \"S1\");\n  auto* BI1 = S1->addByteInterval(Ctx, 16);\n  auto* CB11 = BI1->addBlock<CodeBlock>(Ctx, 0, 4);\n  auto* S2 = M->addSection(Ctx, \"S2\");\n  auto* BI2 = S2->addByteInterval(Ctx, Addr(0), 10);\n  auto* CB21 = BI2->addBlock<CodeBlock>(Ctx, 0, 2);\n  auto* CB22 = BI2->addBlock<CodeBlock>(Ctx, 5, 2);\n  auto* S3 = M->addSection(Ctx, \"S3\");\n  auto* BI3 = S3->addByteInterval(Ctx, Addr(4), 4);\n  auto* CB31 = BI3->addBlock<CodeBlock>(Ctx, 0, 3);\n  const Module* CM = M;\n\n  // Querying an out-of-bounds offset produces an empty range.\n\n  auto BlockRange = M->findBlocksAt(Addr(10), Addr(11));\n  EXPECT_TRUE(BlockRange.empty());\n\n  auto ConstBlockRange = CM->findBlocksAt(Addr(10), Addr(11));\n  EXPECT_TRUE(ConstBlockRange.empty());\n\n  // Querying an in-bounds offset returns the appropriate blocks from all\n  // ByteIntervals.\n\n  BlockRange = M->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB22);\n\n  ConstBlockRange = CM->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB22);\n\n  // Assigning a ByteInterval address may change the query results.\n\n  BI1->setAddress(Addr(4));\n\n  BlockRange = M->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB22);\n\n  ConstBlockRange = CM->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB22);\n\n  // Changing a ByteInterval's address may change the query results.\n\n  BI2->setAddress(Addr(4));\n\n  BlockRange = M->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB11);\n\n  ConstBlockRange = CM->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB11);\n\n  BI3->setAddress(Addr(0));\n\n  BlockRange = M->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n\n  ConstBlockRange = CM->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n}\n\nTEST(Unit_Module, findCodeBlocksAt) {\n  auto* M = Module::Create(Ctx, \"test\");\n  auto* S1 = M->addSection(Ctx, \"S1\");\n  auto* BI1 = S1->addByteInterval(Ctx, 16);\n  auto* CB11 = BI1->addBlock<CodeBlock>(Ctx, 0, 4);\n  auto* S2 = M->addSection(Ctx, \"S2\");\n  auto* BI2 = S2->addByteInterval(Ctx, Addr(0), 10);\n  auto* CB21 = BI2->addBlock<CodeBlock>(Ctx, 0, 2);\n  auto* CB22 = BI2->addBlock<CodeBlock>(Ctx, 5, 2);\n  auto* S3 = M->addSection(Ctx, \"S3\");\n  auto* BI3 = S3->addByteInterval(Ctx, Addr(4), 4);\n  auto* CB31 = BI3->addBlock<CodeBlock>(Ctx, 0, 3);\n  const Module* CM = M;\n\n  // Querying an out-of-bounds offset produces an empty range.\n\n  auto BlockRange = M->findCodeBlocksAt(Addr(10), Addr(11));\n  EXPECT_TRUE(BlockRange.empty());\n\n  auto ConstBlockRange = CM->findCodeBlocksAt(Addr(10), Addr(11));\n  EXPECT_TRUE(ConstBlockRange.empty());\n\n  // Querying an in-bounds offset returns the appropriate blocks from all\n  // ByteIntervals.\n\n  BlockRange = M->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB22);\n\n  ConstBlockRange = CM->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB22);\n\n  // Assigning a ByteInterval address may change the query results.\n\n  BI1->setAddress(Addr(4));\n\n  BlockRange = M->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB22);\n\n  ConstBlockRange = CM->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB22);\n\n  // Changing a ByteInterval's address may change the query results.\n\n  BI2->setAddress(Addr(4));\n\n  BlockRange = M->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB11);\n\n  ConstBlockRange = CM->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB11);\n\n  BI3->setAddress(Addr(0));\n\n  BlockRange = M->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n\n  ConstBlockRange = CM->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n}\n\nTEST(Unit_Module, findDataBlocksAt) {\n  auto* M = Module::Create(Ctx, \"test\");\n  auto* S1 = M->addSection(Ctx, \"S1\");\n  auto* BI1 = S1->addByteInterval(Ctx, 16);\n  auto* CB11 = BI1->addBlock<DataBlock>(Ctx, 0, 4);\n  auto* S2 = M->addSection(Ctx, \"S2\");\n  auto* BI2 = S2->addByteInterval(Ctx, Addr(0), 10);\n  auto* CB21 = BI2->addBlock<DataBlock>(Ctx, 0, 2);\n  auto* CB22 = BI2->addBlock<DataBlock>(Ctx, 5, 2);\n  auto* S3 = M->addSection(Ctx, \"S3\");\n  auto* BI3 = S3->addByteInterval(Ctx, Addr(4), 4);\n  auto* CB31 = BI3->addBlock<DataBlock>(Ctx, 0, 3);\n  const Module* CM = M;\n\n  // Querying an out-of-bounds offset produces an empty range.\n\n  auto BlockRange = M->findDataBlocksAt(Addr(10), Addr(11));\n  EXPECT_TRUE(BlockRange.empty());\n\n  auto ConstBlockRange = CM->findDataBlocksAt(Addr(10), Addr(11));\n  EXPECT_TRUE(ConstBlockRange.empty());\n\n  // Querying an in-bounds offset returns the appropriate blocks from all\n  // ByteIntervals.\n\n  BlockRange = M->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB22);\n\n  ConstBlockRange = CM->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB22);\n\n  // Assigning a ByteInterval address may change the query results.\n\n  BI1->setAddress(Addr(4));\n\n  BlockRange = M->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB22);\n\n  ConstBlockRange = CM->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB22);\n\n  // Changing a ByteInterval's address may change the query results.\n\n  BI2->setAddress(Addr(4));\n\n  BlockRange = M->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB11);\n\n  ConstBlockRange = CM->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB11);\n\n  BI3->setAddress(Addr(0));\n\n  BlockRange = M->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n\n  ConstBlockRange = CM->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n}\n\nTEST(Unit_Module, dataObjects) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S = M->addSection(Ctx, \"test\");\n  auto* BI = S->addByteInterval(Ctx, Addr(1), 123);\n  BI->addBlock<DataBlock>(Ctx, 0, 123);\n  ASSERT_NE(M->data_blocks_begin(), M->data_blocks_end());\n  EXPECT_EQ(M->data_blocks_begin()->getAddress(), Addr(1));\n}\n\nTEST(Unit_Module, findData) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S = M->addSection(Ctx, \"test\");\n  auto* BI = S->addByteInterval(Ctx, Addr(0), 30);\n\n  auto* D1 = BI->addBlock<DataBlock>(Ctx, 1, 10);\n  auto* D2 = BI->addBlock<DataBlock>(Ctx, 5, 10);\n\n  {\n    auto F = M->findDataBlocksOn(Addr(0));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 0);\n\n    F = M->findDataBlocksOn(Addr(1));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), D1);\n\n    F = M->findDataBlocksOn(Addr(5));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 2);\n    EXPECT_EQ(&*F.begin(), D1);\n    EXPECT_EQ(&*(++F.begin()), D2);\n\n    F = M->findDataBlocksOn(Addr(10));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 2);\n    EXPECT_EQ(&*F.begin(), D1);\n    EXPECT_EQ(&*(++F.begin()), D2);\n\n    F = M->findDataBlocksOn(Addr(11));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), D2);\n\n    F = M->findDataBlocksOn(Addr(14));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), D2);\n\n    F = M->findDataBlocksOn(Addr(15));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 0);\n  }\n}\n\nTEST(Unit_Module, symbolIterationOrder) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S1 = M->addSymbol(Ctx, Addr(3), \"foo\");\n  auto* S2 = M->addSymbol(Ctx, Addr(2), \"bar\");\n  auto* S3 = M->addSymbol(Ctx, Addr(1), \"foo\");\n\n  {\n    auto F = M->symbols_by_name();\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 3);\n    auto It = F.begin();\n    // symbol_name_iterator returns values in name order but does not specify\n    // order for symbols with the same name.\n    EXPECT_EQ(&*It++, S2);\n    EXPECT_EQ((std::set<Symbol*>{&*It++, &*It++}), (std::set<Symbol*>{S1, S3}));\n  }\n}\n\nTEST(Unit_Module, findSymbols) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S = M->addSection(Ctx, \"test\");\n  auto* BI = S->addByteInterval(Ctx, Addr(1), 1);\n  auto* B = BI->addBlock<CodeBlock>(Ctx, 0, 1);\n\n  auto* S1 = M->addSymbol(Ctx, Addr(1), \"foo\");\n  auto* S2 = M->addSymbol(Ctx, B, \"bar\");\n  auto* S3 = M->addSymbol(Ctx, Addr(2), \"foo\");\n  auto* S4 = M->addSymbol(Ctx, B, \"baz\");\n\n  {\n    auto F = M->findSymbols(\"foo\");\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 2);\n    // Order of S1 and S2 is unspecified.\n    EXPECT_EQ((std::set<Symbol*>{&*F.begin(), &*std::next(F.begin(), 1)}),\n              (std::set<Symbol*>{S1, S3}));\n  }\n\n  {\n    auto F = M->findSymbols(\"bar\");\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), S2);\n  }\n\n  EXPECT_TRUE(M->findSymbols(\"notfound\").empty());\n\n  {\n    auto F = M->findSymbols(Addr(1));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 3);\n    // Order of S1, S2, and S4 is unspecified.\n    EXPECT_EQ((std::set<Symbol*>{&*F.begin(), &*std::next(F.begin(), 1),\n                                 &*std::next(F.begin(), 2)}),\n              (std::set<Symbol*>{S1, S2, S4}));\n  }\n\n  {\n    auto F = M->findSymbols(Addr(2));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), S3);\n  }\n\n  EXPECT_TRUE(M->findSymbols(Addr(3)).empty());\n\n  {\n    auto F = M->findSymbols(Addr(0), Addr(2));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 3);\n    // Order of S1, S2, and S4 is unspecified.\n    EXPECT_EQ((std::set<Symbol*>{&*F.begin(), &*std::next(F.begin(), 1),\n                                 &*std::next(F.begin(), 2)}),\n              (std::set<Symbol*>{S1, S2, S4}));\n  }\n\n  {\n    auto F = M->findSymbols(Addr(0), Addr(5));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 4);\n    // Order of S1, S2, and S4 is unspecified. All three should be returned\n    // before S3.\n    EXPECT_EQ((std::set<Symbol*>{&*F.begin(), &*std::next(F.begin(), 1),\n                                 &*std::next(F.begin(), 2)}),\n              (std::set<Symbol*>{S1, S2, S4}));\n    EXPECT_EQ(&*std::next(F.begin(), 3), S3);\n  }\n\n  {\n    auto F = M->findSymbols(Addr(10), Addr(25));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 0);\n  }\n\n  {\n    auto F = M->findSymbols(*B);\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 2);\n    // Order of S2 and S4 is unspecified.\n    EXPECT_EQ((std::set<Symbol*>{&*F.begin(), &*std::next(F.begin(), 1)}),\n              (std::set<Symbol*>{S2, S4}));\n  }\n}\n\nTEST(Unit_Module, symbolWithoutAddr) {\n  auto* M = Module::Create(Ctx, \"M\");\n  M->addSymbol(Ctx, \"test\");\n  EXPECT_EQ(M->findSymbols(\"test\").begin()->getName(), \"test\");\n}\n\nTEST(Unit_Module, renameSymbol) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S1 = M->addSymbol(Ctx, \"foo\");\n  auto* S2 = M->addSymbol(Ctx, Addr(1), \"bar\");\n  auto* S3 = M->addSymbol(Ctx, Addr(2), \"bar\");\n\n  S1->setName(\"test1\");\n  S2->setName(\"test2\");\n\n  {\n    auto F = M->findSymbols(\"foo\");\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 0);\n\n    F = M->findSymbols(\"bar\");\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), S3);\n\n    F = M->findSymbols(\"test1\");\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), S1);\n\n    F = M->findSymbols(\"test2\");\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), S2);\n  }\n  {\n    auto F = M->findSymbols(Addr(1));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), S2);\n\n    F = M->findSymbols(Addr(2));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), S3);\n  }\n}\n\nTEST(Unit_Module, setReferent) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S = M->addSection(Ctx, \"test\");\n  auto* BI = S->addByteInterval(Ctx, Addr(0), 5);\n\n  auto* B1 = BI->addBlock<CodeBlock>(Ctx, 1, 1);\n  auto* B2 = BI->addBlock<CodeBlock>(Ctx, 2, 1);\n  auto* B3 = BI->addBlock<CodeBlock>(Ctx, 3, 1);\n  auto* B4 = BI->addBlock<CodeBlock>(Ctx, 4, 1);\n  auto* B5 = BI->addBlock<CodeBlock>(Ctx, 5, 1);\n  auto* S1 = M->addSymbol(Ctx, \"foo\");\n  auto* S2 = M->addSymbol(Ctx, B1, \"bar\");\n  auto* S3 = M->addSymbol(Ctx, B1, \"foo\");\n  auto* S4 = M->addSymbol(Ctx, B2, \"bar\");\n\n  S1->setReferent(B3);\n  S2->setReferent(B4);\n  S4->setReferent(B5);\n\n  {\n    auto F = M->findSymbols(\"foo\");\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 2);\n    EXPECT_EQ(&*F.begin(), S1);\n    EXPECT_EQ(&*(++F.begin()), S3);\n\n    F = M->findSymbols(\"bar\");\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 2);\n    EXPECT_EQ(&*F.begin(), S2);\n    EXPECT_EQ(&*(++F.begin()), S4);\n  }\n\n  {\n    auto F = M->findSymbols(Addr(1));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), S3);\n\n    F = M->findSymbols(Addr(2));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 0);\n\n    F = M->findSymbols(Addr(3));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), S1);\n\n    F = M->findSymbols(Addr(4));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), S2);\n\n    F = M->findSymbols(Addr(5));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), S4);\n  }\n}\n\nTEST(Unit_Module, setSymbolAddress) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S = M->addSection(Ctx, \"test\");\n  auto* BI = S->addByteInterval(Ctx, Addr(0), 5);\n\n  auto* B1 = BI->addBlock<CodeBlock>(Ctx, 1, 1);\n  auto* S1 = M->addSymbol(Ctx, \"foo\");\n  auto* S2 = M->addSymbol(Ctx, B1, \"bar\");\n  auto* S3 = M->addSymbol(Ctx, B1, \"bar\");\n\n  S1->setAddress(Addr(2));\n  S2->setAddress(Addr(3));\n\n  {\n    auto F = M->findSymbols(\"bar\");\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 2);\n    EXPECT_EQ(&*F.begin(), S2);\n    EXPECT_EQ(&*(++F.begin()), S3);\n  }\n\n  {\n    auto F = M->findSymbols(Addr(1));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), S3);\n\n    F = M->findSymbols(Addr(2));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), S1);\n\n    F = M->findSymbols(Addr(3));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(&*F.begin(), S2);\n  }\n}\n\nTEST(Unit_Module, symbolicExpressions) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S = M->addSection(Ctx, \"test\");\n  auto* BI = S->addByteInterval(Ctx, Addr(1), 123);\n  auto* Sym = M->addSymbol(Ctx, \"test\");\n\n  BI->addSymbolicExpression(0, SymAddrConst{0, Sym});\n  EXPECT_EQ(std::distance(M->symbolic_expressions_begin(),\n                          M->symbolic_expressions_end()),\n            1);\n}\n\nTEST(Unit_Module, findSymbolicExpressionsAts) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S = M->addSection(Ctx, \"test\");\n  auto* BI = S->addByteInterval(Ctx, Addr(0), 10);\n\n  auto* S1 = M->addSymbol(Ctx, Addr(1), \"foo\");\n  auto* S2 = M->addSymbol(Ctx, Addr(5), \"bar\");\n\n  BI->addSymbolicExpression(1, SymAddrConst{0, S1});\n  BI->addSymbolicExpression(5, SymAddrConst{0, S2});\n\n  {\n    auto F = M->findSymbolicExpressionsAt(Addr(1), Addr(5));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(std::get<SymAddrConst>(F.begin()->getSymbolicExpression()).Sym,\n              S1);\n  }\n\n  {\n    auto F = M->findSymbolicExpressionsAt(Addr(1), Addr(6));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 2);\n    EXPECT_EQ(std::get<SymAddrConst>(F.begin()->getSymbolicExpression()).Sym,\n              S1);\n    EXPECT_EQ(\n        std::get<SymAddrConst>((++F.begin())->getSymbolicExpression()).Sym, S2);\n  }\n\n  {\n    auto F = M->findSymbolicExpressionsAt(Addr(1), Addr(3));\n    ASSERT_EQ(std::distance(F.begin(), F.end()), 1);\n    EXPECT_EQ(std::get<SymAddrConst>(F.begin()->getSymbolicExpression()).Sym,\n              S1);\n  }\n\n  {\n    auto F = M->findSymbolicExpressionsAt(Addr(6), Addr(50));\n    EXPECT_EQ(std::distance(F.begin(), F.end()), 0);\n  }\n}\n\nTEST(Unit_Module, protobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  std::stringstream ss;\n\n  UUID BlockID, DataID, ProxyID, SectionID;\n  size_t WhichSymbolic;\n\n  {\n    Context InnerCtx;\n    IR* OI = IR::Create(InnerCtx);\n    Module* Original = OI->addModule(InnerCtx, \"module\");\n    Original->setBinaryPath(\"test\");\n    Original->setPreferredAddr(Addr(3));\n    Original->setRebaseDelta(4);\n    Original->setFileFormat(FileFormat::ELF);\n    Original->setISA(ISA::X64);\n    Original->setByteOrder(ByteOrder::Little);\n    Original->addAuxData<AnTest>(0);\n    Symbol* Sym = Original->addSymbol(InnerCtx, Addr(1), \"name1\");\n    Original->addSymbol(InnerCtx, Addr(2), \"name1\");\n    Original->addSymbol(InnerCtx, Addr(1), \"name3\");\n    auto S = Original->addSection(InnerCtx, \"test\");\n    auto BI = S->addByteInterval(InnerCtx, Addr(1), 2);\n    BI->addBlock<CodeBlock>(InnerCtx, 0, 2);\n    BI->addBlock<DataBlock>(InnerCtx, 0, 2);\n    auto* P = Original->addProxyBlock(InnerCtx);\n    BI->addSymbolicExpression<SymAddrConst>(7, 0, Sym);\n    BlockID = blocks(Original->getIR()->getCFG()).begin()->getUUID();\n    DataID = Original->data_blocks_begin()->getUUID();\n    ProxyID = P->getUUID();\n    SectionID = Original->sections_begin()->getUUID();\n    WhichSymbolic = Original->symbolic_expressions_begin()->getOffset();\n\n    STH::save(*Original, ss);\n  }\n\n  Module* Result = STH::load<Module>(Ctx, ss);\n  IR::Create(Ctx)->addModule(Result);\n\n  EXPECT_EQ(Result->getBinaryPath(), \"test\");\n  EXPECT_EQ(Result->getPreferredAddr(), Addr(3));\n  EXPECT_EQ(Result->getRebaseDelta(), 4);\n  EXPECT_EQ(Result->getFileFormat(), FileFormat::ELF);\n  EXPECT_EQ(Result->getISA(), ISA::X64);\n  EXPECT_EQ(Result->getByteOrder(), ByteOrder::Little);\n  EXPECT_EQ(Result->getName(), \"module\");\n\n  // Make sure all symbols are present despite repeated names and addresses.\n  EXPECT_EQ(std::distance(Result->symbols_begin(), Result->symbols_end()), 3);\n  {\n    auto Found = Result->findSymbols(\"name1\");\n    EXPECT_EQ(distance(Found.begin(), Found.end()), 2);\n  }\n  {\n    auto Found = Result->findSymbols(Addr(1));\n    EXPECT_EQ(distance(Found.begin(), Found.end()), 2);\n  }\n\n  // Make sure various collections and node members are serialized, but\n  // don't check in detail as they have their own unit tests.\n  EXPECT_EQ(Result->getAuxDataSize(), 1);\n  EXPECT_NE(Result->getAuxData<AnTest>(), nullptr);\n\n  ASSERT_EQ(num_vertices(Result->getIR()->getCFG()), 2);\n  {\n    auto Nodes = nodes(Result->getIR()->getCFG());\n    auto It = Nodes.begin();\n    EXPECT_TRUE(&*It);\n    EXPECT_TRUE(It->getUUID() == BlockID || It->getUUID() == ProxyID);\n    ++It;\n    EXPECT_TRUE(&*It);\n    EXPECT_NE(Nodes.begin()->getUUID(), It->getUUID());\n    EXPECT_TRUE(It->getUUID() == BlockID || It->getUUID() == ProxyID);\n  }\n\n  ASSERT_EQ(\n      std::distance(Result->code_blocks_begin(), Result->code_blocks_end()), 1);\n  EXPECT_EQ(Result->code_blocks_begin()->getUUID(), BlockID);\n  ASSERT_EQ(\n      std::distance(Result->data_blocks_begin(), Result->data_blocks_end()), 1);\n  EXPECT_EQ(Result->data_blocks_begin()->getUUID(), DataID);\n  ASSERT_EQ(\n      std::distance(Result->proxy_blocks_begin(), Result->proxy_blocks_end()),\n      1);\n  EXPECT_EQ(Result->proxy_blocks_begin()->getUUID(), ProxyID);\n  EXPECT_EQ(Result->proxy_blocks_begin()->getModule(), Result);\n\n  ASSERT_EQ(std::distance(Result->sections_begin(), Result->sections_end()), 1);\n  EXPECT_EQ(Result->sections_begin()->getUUID(), SectionID);\n\n  ASSERT_EQ(std::distance(Result->symbolic_expressions_begin(),\n                          Result->symbolic_expressions_end()),\n            1);\n  EXPECT_EQ(Result->symbolic_expressions_begin()->getOffset(), WhichSymbolic);\n}\n\nTEST(Unit_Module, protobufNodePointers) {\n  // Ensure that when we cannot load an object that does not exist in the\n  // serialized form that we fail to load the GTIRB again because it is wrong.\n  using STH = gtirb::SerializationTestHarness;\n  std::stringstream ss;\n\n  {\n    Context InnerCtx;\n    auto* Original = Module::Create(InnerCtx, \"M\");\n    auto* S = Original->addSection(InnerCtx, \"test\");\n    auto* BI = S->addByteInterval(InnerCtx, Addr(1), 2);\n    auto* Data = BI->addBlock<DataBlock>(InnerCtx, 0, 0);\n    auto* DataSym = Original->addSymbol(InnerCtx, Data, \"data\");\n\n    // Not part of IR\n    auto* DanglingData = DataBlock::Create(InnerCtx, 0);\n    Original->addSymbol(InnerCtx, DanglingData, \"dangling\");\n\n    auto* Code = BI->addBlock<CodeBlock>(InnerCtx, 0, 2);\n    Original->addSymbol(InnerCtx, Code, \"code\");\n    BI->addSymbolicExpression<SymAddrConst>(2, 0, DataSym);\n\n    // Not part of IR\n    auto* DanglingSym = Symbol::Create(InnerCtx, Addr(1), \"foo\");\n    BI->addSymbolicExpression<SymAddrConst>(3, 0, DanglingSym);\n\n    STH::save(*Original, ss);\n  }\n\n  auto* Result = STH::load<Module>(Ctx, ss);\n  EXPECT_EQ(Result, nullptr);\n}\n\nTEST(Unit_Module, removeNodes) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S = M->addSection(Ctx, \"test\");\n  auto* BI = S->addByteInterval(Ctx, Addr(0), 0);\n  BI->addBlock<CodeBlock>(Ctx, 0, 0);\n  BI->addBlock<DataBlock>(Ctx, 0, 0);\n  auto* P = M->addProxyBlock(Ctx);\n  auto* Sym = M->addSymbol(Ctx, \"test\");\n\n  EXPECT_EQ(std::distance(M->sections_begin(), M->sections_end()), 1);\n  EXPECT_EQ(std::distance(M->byte_intervals_begin(), M->byte_intervals_end()),\n            1);\n  EXPECT_EQ(std::distance(M->code_blocks_begin(), M->code_blocks_end()), 1);\n  EXPECT_EQ(std::distance(M->data_blocks_begin(), M->data_blocks_end()), 1);\n  EXPECT_EQ(std::distance(M->proxy_blocks_begin(), M->proxy_blocks_end()), 1);\n  EXPECT_EQ(std::distance(M->symbols_begin(), M->symbols_end()), 1);\n\n  M->removeSection(S);\n\n  EXPECT_EQ(std::distance(M->sections_begin(), M->sections_end()), 0);\n  EXPECT_EQ(std::distance(M->byte_intervals_begin(), M->byte_intervals_end()),\n            0);\n  EXPECT_EQ(std::distance(M->code_blocks_begin(), M->code_blocks_end()), 0);\n  EXPECT_EQ(std::distance(M->data_blocks_begin(), M->data_blocks_end()), 0);\n  EXPECT_EQ(std::distance(M->proxy_blocks_begin(), M->proxy_blocks_end()), 1);\n  EXPECT_EQ(std::distance(M->symbols_begin(), M->symbols_end()), 1);\n\n  M->removeProxyBlock(P);\n\n  EXPECT_EQ(std::distance(M->sections_begin(), M->sections_end()), 0);\n  EXPECT_EQ(std::distance(M->byte_intervals_begin(), M->byte_intervals_end()),\n            0);\n  EXPECT_EQ(std::distance(M->code_blocks_begin(), M->code_blocks_end()), 0);\n  EXPECT_EQ(std::distance(M->data_blocks_begin(), M->data_blocks_end()), 0);\n  EXPECT_EQ(std::distance(M->proxy_blocks_begin(), M->proxy_blocks_end()), 0);\n  EXPECT_EQ(std::distance(M->symbols_begin(), M->symbols_end()), 1);\n\n  M->removeSymbol(Sym);\n\n  EXPECT_EQ(std::distance(M->sections_begin(), M->sections_end()), 0);\n  EXPECT_EQ(std::distance(M->byte_intervals_begin(), M->byte_intervals_end()),\n            0);\n  EXPECT_EQ(std::distance(M->code_blocks_begin(), M->code_blocks_end()), 0);\n  EXPECT_EQ(std::distance(M->data_blocks_begin(), M->data_blocks_end()), 0);\n  EXPECT_EQ(std::distance(M->proxy_blocks_begin(), M->proxy_blocks_end()), 0);\n  EXPECT_EQ(std::distance(M->symbols_begin(), M->symbols_end()), 0);\n}\n\nTEST(Unit_Module, removeInvalidSection) {\n  auto* M1 = Module::Create(Ctx, \"M1\");\n  auto* M2 = Module::Create(Ctx, \"M2\");\n  auto* S1 = M1->addSection(Ctx, \"S1\");\n  S1->addByteInterval(Ctx, Addr(0), 10);\n  auto* S2 = M2->addSection(Ctx, \"S2\");\n  S2->addByteInterval(Ctx, Addr(0), 10);\n\n  EXPECT_FALSE(M1->sections().empty());\n  EXPECT_FALSE(M1->findSectionsOn(Addr(5)).empty());\n  EXPECT_FALSE(M2->sections().empty());\n  EXPECT_FALSE(M2->findSectionsOn(Addr(5)).empty());\n\n  // Removing a section from a Module that isn't its parent should have no\n  // effect.\n  M1->removeSection(S2);\n\n  EXPECT_FALSE(M1->sections().empty());\n  EXPECT_FALSE(M1->findSectionsOn(Addr(5)).empty());\n  EXPECT_FALSE(M2->sections().empty());\n  EXPECT_FALSE(M2->findSectionsOn(Addr(5)).empty());\n}\n\nTEST(Unit_Module, mutateBlocksWithSymbols) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S = M->addSection(Ctx, \"test\");\n  auto* BIC = S->addByteInterval(Ctx, Addr(0), 10);\n  auto* BID = S->addByteInterval(Ctx, Addr(10), 10);\n  auto* CB = BIC->addBlock<CodeBlock>(Ctx, 1, 2);\n  auto* DB = BID->addBlock<DataBlock>(Ctx, 3, 4);\n  auto* SymC = M->addSymbol(Ctx, CB, \"code\");\n  auto* SymD = M->addSymbol(Ctx, DB, \"data\");\n  Module::symbol_addr_range Range;\n\n  Range = M->findSymbols(Addr(1));\n  EXPECT_EQ(std::distance(Range.begin(), Range.end()), 1);\n  EXPECT_EQ(&Range.front(), SymC);\n\n  Range = M->findSymbols(Addr(13));\n  EXPECT_EQ(std::distance(Range.begin(), Range.end()), 1);\n  EXPECT_EQ(&Range.front(), SymD);\n\n  Range = M->findSymbols(Addr(21));\n  EXPECT_EQ(std::distance(Range.begin(), Range.end()), 0);\n\n  BIC->setAddress(Addr(20));\n\n  Range = M->findSymbols(Addr(1));\n  EXPECT_EQ(std::distance(Range.begin(), Range.end()), 0);\n\n  Range = M->findSymbols(Addr(13));\n  EXPECT_EQ(std::distance(Range.begin(), Range.end()), 1);\n  EXPECT_EQ(&Range.front(), SymD);\n\n  Range = M->findSymbols(Addr(21));\n  EXPECT_EQ(std::distance(Range.begin(), Range.end()), 1);\n  EXPECT_EQ(&Range.front(), SymC);\n}\n\nTEST(Unit_Module, addBlocksWithSymbols) {\n  auto* M = Module::Create(Ctx, \"M\");\n  auto* S = M->addSection(Ctx, \"test\");\n  auto* BI1 = S->addByteInterval(Ctx, Addr(0), 10);\n  auto* BI2 = S->addByteInterval(Ctx, Addr(10), 10);\n  auto* BI3 = S->addByteInterval(Ctx, Addr(20), 10);\n  auto* BC = BI1->addBlock<CodeBlock>(Ctx, 1, 2);\n  auto* BD = BI2->addBlock<DataBlock>(Ctx, 1, 2);\n  auto* SymC = M->addSymbol(Ctx, BC, \"code\");\n  auto* SymD = M->addSymbol(Ctx, BD, \"data\");\n\n  Module::symbol_addr_range Range;\n\n  Range = M->findSymbols(Addr(1));\n  EXPECT_EQ(std::distance(Range.begin(), Range.end()), 1);\n  EXPECT_EQ(&Range.front(), SymC);\n\n  Range = M->findSymbols(Addr(11));\n  EXPECT_EQ(std::distance(Range.begin(), Range.end()), 1);\n  EXPECT_EQ(&Range.front(), SymD);\n\n  Range = M->findSymbols(Addr(21));\n  EXPECT_EQ(std::distance(Range.begin(), Range.end()), 0);\n\n  BI3->addBlock(1, BC);\n\n  Range = M->findSymbols(Addr(1));\n  EXPECT_EQ(std::distance(Range.begin(), Range.end()), 0);\n\n  Range = M->findSymbols(Addr(11));\n  EXPECT_EQ(std::distance(Range.begin(), Range.end()), 1);\n  EXPECT_EQ(&Range.front(), SymD);\n\n  Range = M->findSymbols(Addr(21));\n  EXPECT_EQ(std::distance(Range.begin(), Range.end()), 1);\n  EXPECT_EQ(&Range.front(), SymC);\n}\n"
  },
  {
    "path": "src/test/Node.test.cpp",
    "content": "//===- Node.test.cpp --------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include <gtirb/Context.hpp>\n#include <gtirb/Node.hpp>\n#include <fstream>\n#include <gtest/gtest.h>\n\nstatic gtirb::Context Ctx;\n\nTEST(Unit_Node, ctor_0) { EXPECT_NE(gtirb::Node::Create(Ctx), nullptr); }\n\nTEST(Unit_Node, uniqueUuids) {\n  std::vector<gtirb::UUID> Uuids;\n\n  // Create a bunch of UUID's, then make sure we don't have any duplicates.\n\n  for (size_t I = 0; I < 512; ++I) {\n    const auto* N = gtirb::Node::Create(Ctx);\n    Uuids.push_back(N->getUUID());\n  }\n\n  std::sort(std::begin(Uuids), std::end(Uuids));\n  const auto end = std::unique(std::begin(Uuids), std::end(Uuids));\n\n  EXPECT_EQ(std::end(Uuids), end) << \"Duplicate UUID's were generated.\";\n}\n\n// TEST(Unit_Node, copyGetsNewUUID) {\n//  gtirb::Node *Node = gtirb::Node::Create(Ctx);\n//  gtirb::Node Copy(*Node);\n//\n//  EXPECT_NE(Node->getUUID(), Copy.getUUID());\n//  EXPECT_EQ(gtirb::Node::getByUUID(Node->getUUID()), Node);\n//  EXPECT_EQ(gtirb::Node::getByUUID(Copy.getUUID()), &Copy);\n//}\n\nTEST(Unit_Node, getByUUID) {\n  gtirb::Node* N = gtirb::Node::Create(Ctx);\n\n  EXPECT_EQ(gtirb::Node::getByUUID(Ctx, N->getUUID()), N);\n\n  const gtirb::Context& ConstCtx = Ctx;\n  EXPECT_EQ(gtirb::Node::getByUUID(ConstCtx, N->getUUID()), N);\n}\n"
  },
  {
    "path": "src/test/Offset.test.cpp",
    "content": "//===- Offset.test.cpp ------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include <gtirb/Offset.hpp>\n#include <boost/uuid/random_generator.hpp>\n#include <gtest/gtest.h>\n\nusing namespace gtirb;\n\nTEST(Unit_Offset, ordering) {\n  UUID uuid1{boost::uuids::random_generator()()};\n  UUID uuid2{boost::uuids::random_generator()()};\n  uint64_t disp1(5);\n  uint64_t disp2(10);\n  Offset offset1(uuid1, disp1);\n  Offset offset2(uuid1, disp2);\n  Offset offset3(uuid2, disp1);\n  Offset offset4(uuid2, disp2);\n  EXPECT_TRUE(offset1 < offset2);\n  EXPECT_TRUE(offset3 < offset4);\n  if (uuid1 < uuid2) {\n    EXPECT_TRUE(offset1 < offset3);\n    EXPECT_TRUE(offset2 < offset3);\n    EXPECT_TRUE(offset1 < offset4);\n    EXPECT_TRUE(offset2 < offset4);\n  }\n  if (uuid2 < uuid1) {\n    EXPECT_TRUE(offset1 > offset3);\n    EXPECT_TRUE(offset2 > offset3);\n    EXPECT_TRUE(offset1 > offset4);\n    EXPECT_TRUE(offset2 > offset4);\n  }\n}\n\nTEST(Unit_Offset, hash) {\n  UUID uuid1{boost::uuids::random_generator()()};\n  uint64_t disp1(5);\n  uint64_t disp2(10);\n  Offset offset1(uuid1, disp1);\n  Offset offset2(uuid1, disp2);\n  EXPECT_EQ(std::hash<Offset>()(offset1), std::hash<Offset>()(offset1));\n  EXPECT_NE(std::hash<Offset>()(offset1), std::hash<Offset>()(offset2));\n}\n"
  },
  {
    "path": "src/test/PrepDeathTest.hpp",
    "content": "#ifndef PREP_DEATH_TEST_HPP\n#define PREP_DEATH_TEST_HPP\n\n#include \"config-test.h\"\n\n#ifdef HAVE_RESOURCE_H\n#include <cstdlib>\n#include <cstring>\n#include <sys/resource.h>\n\n// Constructing an instance of this class will inhibit dumping of a\n// core file on systems that support get/setrlimit(). This is useful\n// to avoid generating core files when running death tests (tests that\n// are designed to trigger failures - particularly assertions.) On\n// destruction, the previous rlimit for core files is restored.\n//\n// One can set the env variable DEATH_TEST_CORE to a non-zero value to\n// override this and still generate a core.\nclass PrepDeathTest {\npublic:\n  PrepDeathTest() {\n    char* EnvVar = getenv(\"DEATH_TEST_CORE\");\n    if (EnvVar == nullptr || strcmp(EnvVar, \"0\") == 0) {\n      struct rlimit CurrCoreRLimit;\n      if (getrlimit(RLIMIT_CORE, &CurrCoreRLimit) != 0) {\n        // If this fails, just drop out and don't worry about\n        // it. We'll just have to deal with extraneous cores.\n        return;\n      }\n\n      PrevCoreRLimit = CurrCoreRLimit;\n      CurrCoreRLimit.rlim_cur = 0;\n      if (setrlimit(RLIMIT_CORE, &CurrCoreRLimit) != 0) {\n        // If this fails, just drop out and don't worry about\n        // it. We'll just have to deal with extraneous cores.\n        return;\n      }\n\n      RLimitSet = true;\n    }\n  }\n\n  ~PrepDeathTest() {\n    if (RLimitSet) {\n      setrlimit(RLIMIT_CORE, &PrevCoreRLimit);\n    }\n  }\n\nprivate:\n  bool RLimitSet = false;\n  rlimit PrevCoreRLimit;\n};\n\n#else // HAVE_RESOURCE_H\n\n// When we're not on a system that supports get/setrlimit(),\n// PrepDeathTest is just a nop.\nclass PrepDeathTest {};\n\n#endif // HAVE_RESOURCE_H\n\n#endif // PREP_DEATH_TEST_HPP\n"
  },
  {
    "path": "src/test/PrepTestGTIRB.cpp",
    "content": "// This is a small utility program to generate a GTIRB file that can\n// then be loaded by TestGTIRB. The fact this is a separate program\n// allows us to test some aspects of the AuxDataContainer\n// implementation that depend on different processes having different\n// type schemas registered for AuxData types.\n\n#include \"AuxDataContainerSchema.hpp\"\n#include <gtirb/AuxDataContainer.hpp>\n#include <gtirb/Context.hpp>\n#include <gtirb/IR.hpp>\n#include <fstream>\n#include <iostream>\n\nvoid registerAuxDataTypes() {\n  // This schema is *registered* here but unregistered in the unit test.\n  gtirb::AuxDataContainer::registerAuxDataType<\n      gtirb::schema::UnRegisteredType>();\n}\n\nint main(int argc, char* argv[]) {\n  registerAuxDataTypes();\n\n  // Name of the gtirb file to create is expected in argv[1].\n  std::string GtirbFilename;\n  if (argc >= 2) {\n    GtirbFilename = argv[1];\n  }\n\n  if (GtirbFilename.empty()) {\n    std::cerr << \"*\\n* No pre-built GTIRB file specified, cannot create GTIRB \"\n                 \"test file!\\n*\\n\";\n    return -1;\n  }\n\n  std::ofstream GtirbFile;\n  GtirbFile.open(GtirbFilename, std::ifstream::out | std::ifstream::binary);\n\n  if (!GtirbFile) {\n    std::cerr << \"*\\n* Failed to create GTIRB file: \" << GtirbFilename\n              << \"\\n*\\n\";\n    return -1;\n  }\n\n  gtirb::Context Ctx;\n  gtirb::IR* Ir = gtirb::IR::Create(Ctx);\n\n  // Add content to the IR that the unit test can make use of.\n  Ir->addAuxData<gtirb::schema::UnRegisteredType>(42);\n\n  Ir->save(GtirbFile);\n  GtirbFile.close();\n\n  return 0;\n}\n"
  },
  {
    "path": "src/test/ProxyBlock.test.cpp",
    "content": "//===- ProxyBlock.test.cpp ---------------------------------------*- C++\n//-*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"SerializationTestHarness.hpp\"\n#include <gtirb/Context.hpp>\n#include <gtirb/ProxyBlock.hpp>\n#include <gtest/gtest.h>\n#include <sstream>\n\nusing namespace gtirb;\n\nstatic Context Ctx;\n\nTEST(Unit_ProxyBlock, noCopyMoveConstructors) {\n  EXPECT_FALSE(std::is_copy_constructible_v<ProxyBlock>);\n  EXPECT_FALSE(std::is_move_constructible_v<ProxyBlock>);\n  EXPECT_FALSE(std::is_copy_assignable_v<ProxyBlock>);\n  EXPECT_FALSE(std::is_move_assignable_v<ProxyBlock>);\n}\n\nTEST(Unit_ProxyBlock, protobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  std::stringstream ss;\n  UUID uuid;\n  {\n    Context InnerCtx;\n    ProxyBlock* Original = ProxyBlock::Create(InnerCtx);\n    uuid = Original->getUUID();\n    STH::save(*Original, ss);\n  }\n  ProxyBlock* Result = STH::load<ProxyBlock>(Ctx, ss);\n\n  EXPECT_EQ(uuid, Result->getUUID());\n  EXPECT_EQ(Result->getModule(), nullptr);\n}\n"
  },
  {
    "path": "src/test/Section.test.cpp",
    "content": "//===- Section.test.cpp -----------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"SerializationTestHarness.hpp\"\n#include \"TestHelpers.hpp\"\n#include <gtirb/Context.hpp>\n#include <gtirb/Section.hpp>\n#include <gtirb/proto/Section.pb.h>\n#include <gtest/gtest.h>\n#include <limits>\n#include <sstream>\n\nusing namespace gtirb;\n\nstatic Context Ctx;\n\nTEST(Unit_Section, compilationIteratorTypes) {\n  static_assert(std::is_same_v<Section::block_iterator::reference, Node&>);\n  static_assert(\n      std::is_same_v<Section::const_block_iterator::reference, const Node&>);\n  static_assert(\n      std::is_same_v<Section::block_subrange::iterator::reference, Node&>);\n  static_assert(\n      std::is_same_v<Section::const_block_subrange::iterator::reference,\n                     const Node&>);\n\n  {\n    Section::block_iterator BIt;\n    Section::const_block_iterator CBIt = BIt;\n    CBIt = BIt;\n\n    Section::block_range BRng;\n    Section::const_block_range CBRng = BRng;\n    CBRng = BRng;\n  }\n  static_assert(!std::is_convertible_v<Section::const_block_iterator,\n                                       Section::block_iterator>);\n  static_assert(\n      !std::is_convertible_v<Section::const_block_range, Section::block_range>);\n}\n\nTEST(Unit_Section, noCopyMoveConstructors) {\n  EXPECT_FALSE(std::is_copy_constructible_v<Section>);\n  EXPECT_FALSE(std::is_move_constructible_v<Section>);\n  EXPECT_FALSE(std::is_copy_assignable_v<Section>);\n  EXPECT_FALSE(std::is_move_assignable_v<Section>);\n}\n\nTEST(Unit_Section, getAddress) {\n  using OAddr = std::optional<Addr>;\n  using OSize = std::optional<uint64_t>;\n\n  auto* S = Section::Create(Ctx, \"test\");\n  EXPECT_EQ(S->getAddress(), OAddr());\n  EXPECT_EQ(S->getSize(), OSize());\n\n  S->addByteInterval(Ctx, Addr(5), 10);\n  EXPECT_EQ(S->getAddress(), OAddr(Addr(5)));\n  EXPECT_EQ(S->getSize(), OSize(10));\n\n  S->addByteInterval(Ctx, Addr(15), 10);\n  EXPECT_EQ(S->getAddress(), OAddr(Addr(5)));\n  EXPECT_EQ(S->getSize(), OSize(20));\n\n  S->addByteInterval(Ctx, OAddr(), 10);\n  EXPECT_EQ(S->getAddress(), OAddr());\n  EXPECT_EQ(S->getSize(), OSize());\n}\n\nTEST(Unit_Section, flags) {\n  auto* S = Section::Create(Ctx, \"test\");\n  EXPECT_FALSE(S->isFlagSet(SectionFlag::Undefined));\n\n  S->addFlag(SectionFlag::Executable);\n  EXPECT_TRUE(S->isFlagSet(SectionFlag::Executable));\n\n  S->removeFlag(SectionFlag::Executable);\n  EXPECT_FALSE(S->isFlagSet(SectionFlag::Executable));\n\n  S->addFlags(SectionFlag::Initialized, SectionFlag::Loaded);\n  if (*S->flags_begin() == SectionFlag::Initialized)\n    EXPECT_EQ(SectionFlag::Loaded, *(++S->flags_begin()));\n  else {\n    EXPECT_EQ(SectionFlag::Loaded, *S->flags_begin());\n    EXPECT_EQ(SectionFlag::Initialized, *(++S->flags_begin()));\n  }\n}\n\nTEST(Unit_Section, protobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  std::stringstream ss;\n\n  {\n    Context InnerCtx;\n    auto* Original = Section::Create(InnerCtx, \"name\");\n    Original->addFlags(SectionFlag::Executable, SectionFlag::Loaded,\n                       SectionFlag::Writable);\n    STH::save(*Original, ss);\n  }\n  auto* Result = STH::load<Section>(Ctx, ss);\n\n  EXPECT_EQ(Result->getName(), \"name\");\n  EXPECT_TRUE(Result->isFlagSet(SectionFlag::Executable));\n  EXPECT_TRUE(Result->isFlagSet(SectionFlag::Loaded));\n  EXPECT_TRUE(Result->isFlagSet(SectionFlag::Writable));\n  EXPECT_FALSE(Result->isFlagSet(SectionFlag::Initialized));\n  EXPECT_FALSE(Result->isFlagSet(SectionFlag::Readable));\n  EXPECT_FALSE(Result->isFlagSet(SectionFlag::ThreadLocal));\n}\n\nTEST(Unit_Section, findByteIntervalsOn) {\n  auto* S = Section::Create(Ctx, \"test\");\n  auto* BI1 = S->addByteInterval(Ctx, 16);\n  auto* BI2 = S->addByteInterval(Ctx, Addr(8), 12);\n  auto* BI3 = S->addByteInterval(Ctx, Addr(13), 8);\n  const Section* CS = S;\n\n  // Querying an out-of-bounds address returns an empty range.\n\n  auto Range = S->findByteIntervalsOn(Addr(0));\n  EXPECT_TRUE(Range.empty());\n\n  auto ConstRange = CS->findByteIntervalsOn(Addr(0));\n  EXPECT_TRUE(Range.empty());\n\n  // Querying a in-bounds address returns the correct range.\n\n  Range = S->findByteIntervalsOn(Addr(12));\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 1);\n  EXPECT_EQ(&*Range.begin(), BI2);\n\n  ConstRange = CS->findByteIntervalsOn(Addr(12));\n  ASSERT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 1);\n  EXPECT_EQ(&*ConstRange.begin(), BI2);\n\n  // Query returns correct set after addresses are updated.\n\n  BI1->setAddress(Addr(0));\n  Range = S->findByteIntervalsOn(Addr(0));\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 1);\n  EXPECT_EQ(&*Range.begin(), BI1);\n\n  ConstRange = CS->findByteIntervalsOn(Addr(0));\n  ASSERT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 1);\n  EXPECT_EQ(&*ConstRange.begin(), BI1);\n\n  Range = S->findByteIntervalsOn(Addr(12));\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 2);\n  EXPECT_EQ(&*std::next(Range.begin(), 0), BI1);\n  EXPECT_EQ(&*std::next(Range.begin(), 1), BI2);\n\n  ConstRange = CS->findByteIntervalsOn(Addr(12));\n  ASSERT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 0), BI1);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 1), BI2);\n\n  // Query is correct for ByteIntervals with overlapping start addresses.\n\n  BI1->setAddress(Addr(13));\n  Range = S->findByteIntervalsOn(Addr(14));\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 3);\n  EXPECT_EQ(&*std::next(Range.begin(), 0), BI2);\n  EXPECT_EQ(&*std::next(Range.begin(), 1), BI3);\n  EXPECT_EQ(&*std::next(Range.begin(), 2), BI1);\n\n  ConstRange = CS->findByteIntervalsOn(Addr(14));\n  ASSERT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 0), BI2);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 1), BI3);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 2), BI1);\n\n  // Moving a ByteInterval does not leave duplicates in codomain tree.\n\n  BI2->setAddress(Addr(13));\n  Range = S->findByteIntervalsOn(Addr(14));\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 3);\n  EXPECT_EQ(&*std::next(Range.begin(), 0), BI3);\n  EXPECT_EQ(&*std::next(Range.begin(), 1), BI2);\n  EXPECT_EQ(&*std::next(Range.begin(), 2), BI1);\n\n  ConstRange = CS->findByteIntervalsOn(Addr(14));\n  ASSERT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 0), BI3);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 1), BI2);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 2), BI1);\n\n  // Removing a ByteInterval with an overlapping address does not remove others.\n\n  BI3->setAddress(std::nullopt);\n  Range = S->findByteIntervalsOn(Addr(14));\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 2);\n  EXPECT_EQ(&*std::next(Range.begin(), 0), BI2);\n  EXPECT_EQ(&*std::next(Range.begin(), 1), BI1);\n\n  ConstRange = CS->findByteIntervalsOn(Addr(14));\n  ASSERT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 0), BI2);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 1), BI1);\n}\n\nTEST(Unit_Section, findByteIntervalsAt) {\n  auto* S = Section::Create(Ctx, \"test\");\n  auto* BI1 = S->addByteInterval(Ctx, 16);\n  auto* BI2 = S->addByteInterval(Ctx, Addr(8), 16);\n  const Section* CS = S;\n\n  // Querying an out-of-bounds address returns an empty range.\n\n  auto Range = S->findByteIntervalsAt(Addr(0));\n  EXPECT_TRUE(Range.empty());\n\n  auto ConstRange = CS->findByteIntervalsAt(Addr(0));\n  EXPECT_TRUE(ConstRange.empty());\n\n  // Querying exact start address returns the correct interval.\n\n  Range = S->findByteIntervalsAt(Addr(8));\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 1);\n  EXPECT_EQ(&*Range.begin(), BI2);\n\n  ConstRange = CS->findByteIntervalsAt(Addr(8));\n  ASSERT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 1);\n  EXPECT_EQ(&*ConstRange.begin(), BI2);\n\n  // Querying a range of addresses returns everything in range.\n\n  Range = S->findByteIntervalsAt(Addr(0), Addr(static_cast<uint64_t>(-1)));\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 1);\n  EXPECT_EQ(&*Range.begin(), BI2);\n\n  ConstRange =\n      CS->findByteIntervalsAt(Addr(0), Addr(static_cast<uint64_t>(-1)));\n  ASSERT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 1);\n  EXPECT_EQ(&*ConstRange.begin(), BI2);\n\n  Range = S->findByteIntervalsAt(Addr(16), Addr(32));\n  EXPECT_TRUE(Range.empty());\n\n  ConstRange = CS->findByteIntervalsAt(Addr(16), Addr(32));\n  EXPECT_TRUE(ConstRange.empty());\n\n  // Querying an invalid address range returns an empty ByteInterval range.\n\n  Range = S->findByteIntervalsAt(Addr(16), Addr(0));\n  EXPECT_TRUE(Range.empty());\n\n  ConstRange = CS->findByteIntervalsAt(Addr(16), Addr(0));\n  EXPECT_TRUE(ConstRange.empty());\n\n  // Changing the ByteInterval addresses changes the results.\n\n  BI1->setAddress(Addr(4));\n  Range = S->findByteIntervalsAt(Addr(0), Addr(32));\n  ASSERT_EQ(std::distance(Range.begin(), Range.end()), 2);\n  EXPECT_EQ(&*std::next(Range.begin(), 0), BI1);\n  EXPECT_EQ(&*std::next(Range.begin(), 1), BI2);\n\n  ConstRange = CS->findByteIntervalsAt(Addr(0), Addr(32));\n  ASSERT_EQ(std::distance(ConstRange.begin(), ConstRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 0), BI1);\n  EXPECT_EQ(&*std::next(ConstRange.begin(), 1), BI2);\n}\n\nTEST(Unit_Section, findBlocksOn) {\n  auto* S = Section::Create(Ctx, \"test\");\n  auto* BI1 = S->addByteInterval(Ctx, 16);\n  auto* CB11 = BI1->addBlock<CodeBlock>(Ctx, 0, 4);\n  auto* BI2 = S->addByteInterval(Ctx, Addr(0), 10);\n  auto* CB21 = BI2->addBlock<CodeBlock>(Ctx, 0, 2);\n  auto* CB22 = BI2->addBlock<CodeBlock>(Ctx, 5, 2);\n  auto* BI3 = S->addByteInterval(Ctx, Addr(4), 4);\n  auto* CB31 = BI3->addBlock<CodeBlock>(Ctx, 0, 3);\n  const Section* CS = S;\n\n  // Querying an out-of-bounds offset produces an empty range.\n\n  auto BlockRange = S->findBlocksOn(Addr(10));\n  EXPECT_TRUE(BlockRange.empty());\n\n  auto ConstBlockRange = CS->findBlocksOn(Addr(10));\n  EXPECT_TRUE(ConstBlockRange.empty());\n\n  // Querying an in-bounds offset returns the appropriate blocks from all\n  // ByteIntervals.\n\n  BlockRange = S->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB22);\n\n  ConstBlockRange = CS->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB22);\n\n  // Assigning a ByteInterval address may change the query results.\n\n  BI1->setAddress(Addr(4));\n\n  BlockRange = S->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB22);\n\n  ConstBlockRange = CS->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB22);\n\n  // Changing a ByteInterval's address may change the query results.\n\n  BI2->setAddress(Addr(4));\n\n  BlockRange = S->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB11);\n\n  ConstBlockRange = CS->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB11);\n\n  BI3->setAddress(Addr(0));\n\n  BlockRange = S->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n\n  ConstBlockRange = CS->findBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n}\n\nTEST(Unit_Section, findCodeBlocksOn) {\n  auto* S = Section::Create(Ctx, \"test\");\n  auto* BI1 = S->addByteInterval(Ctx, 16);\n  auto* CB11 = BI1->addBlock<CodeBlock>(Ctx, 0, 4);\n  auto* BI2 = S->addByteInterval(Ctx, Addr(0), 10);\n  auto* CB21 = BI2->addBlock<CodeBlock>(Ctx, 0, 2);\n  auto* CB22 = BI2->addBlock<CodeBlock>(Ctx, 5, 2);\n  auto* BI3 = S->addByteInterval(Ctx, Addr(4), 4);\n  auto* CB31 = BI3->addBlock<CodeBlock>(Ctx, 0, 3);\n  const Section* CS = S;\n\n  // Querying an out-of-bounds offset produces an empty range.\n\n  auto BlockRange = S->findCodeBlocksOn(Addr(10));\n  EXPECT_TRUE(BlockRange.empty());\n\n  auto ConstBlockRange = CS->findCodeBlocksOn(Addr(10));\n  EXPECT_TRUE(ConstBlockRange.empty());\n\n  // Querying an in-bounds offset returns the appropriate blocks from all\n  // ByteIntervals.\n\n  BlockRange = S->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB22);\n\n  ConstBlockRange = CS->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB22);\n\n  // Assigning a ByteInterval address may change the query results.\n\n  BI1->setAddress(Addr(4));\n\n  BlockRange = S->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB22);\n\n  ConstBlockRange = CS->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB22);\n\n  // Changing a ByteInterval's address may change the query results.\n\n  BI2->setAddress(Addr(4));\n\n  BlockRange = S->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB11);\n\n  ConstBlockRange = CS->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB11);\n\n  BI3->setAddress(Addr(0));\n\n  BlockRange = S->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n\n  ConstBlockRange = CS->findCodeBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n}\n\nTEST(Unit_Section, findDataBlocksOn) {\n  auto* S = Section::Create(Ctx, \"test\");\n  auto* BI1 = S->addByteInterval(Ctx, 16);\n  auto* CB11 = BI1->addBlock<DataBlock>(Ctx, 0, 4);\n  auto* BI2 = S->addByteInterval(Ctx, Addr(0), 10);\n  auto* CB21 = BI2->addBlock<DataBlock>(Ctx, 0, 2);\n  auto* CB22 = BI2->addBlock<DataBlock>(Ctx, 5, 2);\n  auto* BI3 = S->addByteInterval(Ctx, Addr(4), 4);\n  auto* CB31 = BI3->addBlock<DataBlock>(Ctx, 0, 3);\n  const Section* CS = S;\n\n  // Querying an out-of-bounds offset produces an empty range.\n\n  auto BlockRange = S->findDataBlocksOn(Addr(10));\n  EXPECT_TRUE(BlockRange.empty());\n\n  auto ConstBlockRange = CS->findDataBlocksOn(Addr(10));\n  EXPECT_TRUE(ConstBlockRange.empty());\n\n  // Querying an in-bounds offset returns the appropriate blocks from all\n  // ByteIntervals.\n\n  BlockRange = S->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB22);\n\n  ConstBlockRange = CS->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB22);\n\n  // Assigning a ByteInterval address may change the query results.\n\n  BI1->setAddress(Addr(4));\n\n  BlockRange = S->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB22);\n\n  ConstBlockRange = CS->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB22);\n\n  // Changing a ByteInterval's address may change the query results.\n\n  BI2->setAddress(Addr(4));\n\n  BlockRange = S->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB11);\n\n  ConstBlockRange = CS->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB11);\n\n  BI3->setAddress(Addr(0));\n\n  BlockRange = S->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n\n  ConstBlockRange = CS->findDataBlocksOn(Addr(5));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n}\n\nTEST(Unit_Section, findBlocksAt) {\n  auto* S = Section::Create(Ctx, \"test\");\n  auto* BI1 = S->addByteInterval(Ctx, 16);\n  auto* CB11 = BI1->addBlock<CodeBlock>(Ctx, 0, 4);\n  auto* BI2 = S->addByteInterval(Ctx, Addr(0), 10);\n  auto* CB21 = BI2->addBlock<CodeBlock>(Ctx, 0, 2);\n  auto* CB22 = BI2->addBlock<CodeBlock>(Ctx, 5, 2);\n  auto* BI3 = S->addByteInterval(Ctx, Addr(4), 4);\n  auto* CB31 = BI3->addBlock<CodeBlock>(Ctx, 0, 3);\n  const Section* CS = S;\n\n  // Querying an out-of-bounds offset produces an empty range.\n\n  auto BlockRange = S->findBlocksAt(Addr(10), Addr(20));\n  EXPECT_TRUE(BlockRange.empty());\n\n  auto ConstBlockRange = CS->findBlocksAt(Addr(10), Addr(20));\n  EXPECT_TRUE(ConstBlockRange.empty());\n\n  // Querying an in-bounds offset returns the appropriate blocks from all\n  // ByteIntervals.\n\n  BlockRange = S->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB22);\n\n  ConstBlockRange = CS->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB22);\n\n  // Assigning a ByteInterval address may change the query results.\n\n  BI1->setAddress(Addr(4));\n\n  BlockRange = S->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB22);\n\n  ConstBlockRange = CS->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB22);\n\n  // Changing a ByteInterval's address may change the query results.\n\n  BI2->setAddress(Addr(4));\n\n  BlockRange = S->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB11);\n\n  ConstBlockRange = CS->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB11);\n\n  BI3->setAddress(Addr(0));\n\n  BlockRange = S->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n\n  ConstBlockRange = CS->findBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n}\n\nTEST(Unit_Section, findCodeBlocksAt) {\n  auto* S = Section::Create(Ctx, \"test\");\n  auto* BI1 = S->addByteInterval(Ctx, 16);\n  auto* CB11 = BI1->addBlock<CodeBlock>(Ctx, 0, 4);\n  auto* BI2 = S->addByteInterval(Ctx, Addr(0), 10);\n  auto* CB21 = BI2->addBlock<CodeBlock>(Ctx, 0, 2);\n  auto* CB22 = BI2->addBlock<CodeBlock>(Ctx, 5, 2);\n  auto* BI3 = S->addByteInterval(Ctx, Addr(4), 4);\n  auto* CB31 = BI3->addBlock<CodeBlock>(Ctx, 0, 3);\n  const Section* CS = S;\n\n  // Querying an out-of-bounds offset produces an empty range.\n\n  auto BlockRange = S->findCodeBlocksAt(Addr(10), Addr(20));\n  EXPECT_TRUE(BlockRange.empty());\n\n  auto ConstBlockRange = CS->findCodeBlocksAt(Addr(10), Addr(20));\n  EXPECT_TRUE(ConstBlockRange.empty());\n\n  // Querying an in-bounds offset returns the appropriate blocks from all\n  // ByteIntervals.\n\n  BlockRange = S->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB22);\n\n  ConstBlockRange = CS->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB22);\n\n  // Assigning a ByteInterval address may change the query results.\n\n  BI1->setAddress(Addr(4));\n\n  BlockRange = S->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB22);\n\n  ConstBlockRange = CS->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB22);\n\n  // Changing a ByteInterval's address may change the query results.\n\n  BI2->setAddress(Addr(4));\n\n  BlockRange = S->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB11);\n\n  ConstBlockRange = CS->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB11);\n\n  BI3->setAddress(Addr(0));\n\n  BlockRange = S->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n\n  ConstBlockRange = CS->findCodeBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n}\n\nTEST(Unit_Section, findDataBlocksAt) {\n  auto* S = Section::Create(Ctx, \"test\");\n  auto* BI1 = S->addByteInterval(Ctx, 16);\n  auto* CB11 = BI1->addBlock<DataBlock>(Ctx, 0, 4);\n  auto* BI2 = S->addByteInterval(Ctx, Addr(0), 10);\n  auto* CB21 = BI2->addBlock<DataBlock>(Ctx, 0, 2);\n  auto* CB22 = BI2->addBlock<DataBlock>(Ctx, 5, 2);\n  auto* BI3 = S->addByteInterval(Ctx, Addr(4), 4);\n  auto* CB31 = BI3->addBlock<DataBlock>(Ctx, 0, 3);\n  const Section* CS = S;\n\n  // Querying an out-of-bounds offset produces an empty range.\n\n  auto BlockRange = S->findDataBlocksAt(Addr(10), Addr(20));\n  EXPECT_TRUE(BlockRange.empty());\n\n  auto ConstBlockRange = CS->findDataBlocksAt(Addr(10), Addr(20));\n  EXPECT_TRUE(ConstBlockRange.empty());\n\n  // Querying an in-bounds offset returns the appropriate blocks from all\n  // ByteIntervals.\n\n  BlockRange = S->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB22);\n\n  ConstBlockRange = CS->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB22);\n\n  // Assigning a ByteInterval address may change the query results.\n\n  BI1->setAddress(Addr(4));\n\n  BlockRange = S->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB22);\n\n  ConstBlockRange = CS->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB22);\n\n  // Changing a ByteInterval's address may change the query results.\n\n  BI2->setAddress(Addr(4));\n\n  BlockRange = S->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 2), CB11);\n\n  ConstBlockRange = CS->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 3);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB31);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 2), CB11);\n\n  BI3->setAddress(Addr(0));\n\n  BlockRange = S->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(BlockRange.begin(), BlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(BlockRange.begin(), 1), CB11);\n\n  ConstBlockRange = CS->findDataBlocksAt(Addr(3), Addr(6));\n  ASSERT_EQ(std::distance(ConstBlockRange.begin(), ConstBlockRange.end()), 2);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 0), CB21);\n  EXPECT_EQ(&*std::next(ConstBlockRange.begin(), 1), CB11);\n}\n\nTEST(Unit_Section, testIterationOrder) {\n  auto* S = Section::Create(Ctx, \"test\");\n  auto* BI1 = S->addByteInterval(Ctx, Addr(0));\n  auto* CB11 = BI1->addBlock<CodeBlock>(Ctx, 0, 0);\n  auto* CB12 = BI1->addBlock<CodeBlock>(Ctx, 0, 1);\n  auto* BI2 = S->addByteInterval(Ctx, Addr(0));\n  auto* DB21 = BI2->addBlock<DataBlock>(Ctx, 0, 0);\n  auto* DB22 = BI2->addBlock<DataBlock>(Ctx, 0, 1);\n  auto* BI3 = S->addByteInterval(Ctx, Addr(1));\n  auto* DB31 = BI3->addBlock<DataBlock>(Ctx, 0, 0);\n  auto* DB32 = BI3->addBlock<DataBlock>(Ctx, 0, 1);\n\n  {\n    std::vector<Node*> ExpectedOrder = {CB11, DB21, CB12, DB22, DB31, DB32};\n    EXPECT_EQ(pointers(S->blocks()), ExpectedOrder);\n  }\n}\n"
  },
  {
    "path": "src/test/SerializationTestHarness.hpp",
    "content": "//===- SerializationTestHarness.hpp -----------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n\n#ifndef SERIALIZATION_TEST_HARNESS_HPP\n#define SERIALIZATION_TEST_HARNESS_HPP\n\n#include <gtirb/ByteInterval.hpp>\n#include <gtirb/CFG.hpp>\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/DataBlock.hpp>\n#include <gtirb/IR.hpp>\n#include <gtirb/Module.hpp>\n#include <gtirb/Section.hpp>\n#include <gtirb/Symbol.hpp>\n#include <iostream>\n\nnamespace gtirb {\n\n// This is a utility class that allows unit tests to access the\n// private serialization primitives for individual GTIRB classes. All\n// GTIRB classes be-friend this class so they don't have to be-friend\n// all the individual unit tests.\n//\n// Note: this class accesses the save/load member functions in each\n// GTIRB class, not the to/fromProtobuf functions, as we do not want\n// protobuf Message instances allocated here or in the unit test\n// code. If they were allocated here, we would have problems on\n// Windows due to protobuf not being dllexported in the gtirb.so\n// library.\nclass SerializationTestHarness {\npublic:\n  template <typename T> static void save(const T& Val, std::ostream& Out) {\n    Val.save(Out);\n  }\n\n  template <typename T> static auto load(Context& C, std::istream& In) {\n    return T::load(C, In);\n  }\n\n  template <typename T, typename P>\n  static auto load(Context& C, P* Parent, std::istream& In) {\n    return T::load(C, Parent, In);\n  }\n\n  static bool byteIntervalLoadSymbolicExpressions(Context& Ctx,\n                                                  ByteInterval& BI,\n                                                  std::istream& In) {\n    return BI.loadSymbolicExpressions(Ctx, In);\n  }\n};\n\ntemplate <>\ninline auto SerializationTestHarness::load<IR>(Context& C, std::istream& In) {\n  ErrorOr<IR*> Result = IR::load(C, In);\n  if (Result)\n    return *Result;\n  return static_cast<IR*>(nullptr);\n}\n\n// Serializaton for CFGs, for which there isn't a class-level protobuf\n// concept in the C++ API.\nvoid GTIRB_EXPORT_API cfgSave(const CFG& Cfg, std::ostream& Out);\nvoid GTIRB_EXPORT_API cfgLoad(Context& C, CFG& Result, std::istream& In);\n\n// Serialization for SymbolicExpressions\nvoid GTIRB_EXPORT_API symbolicExpressionSave(const SymbolicExpression& SE,\n                                             std::ostream& Out);\nvoid GTIRB_EXPORT_API symbolicExpressionLoad(Context& C,\n                                             SymbolicExpression& Result,\n                                             std::istream& In);\n\n} // namespace gtirb\n\n#endif // SERIALIZATION_TEST_HARNESS_HPP\n"
  },
  {
    "path": "src/test/Symbol.test.cpp",
    "content": "//===- Symbol.test.cpp ------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"SerializationTestHarness.hpp\"\n#include <gtirb/CfgNode.hpp>\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/Context.hpp>\n#include <gtirb/DataBlock.hpp>\n#include <gtirb/Module.hpp>\n#include <gtirb/ProxyBlock.hpp>\n#include <gtirb/Symbol.hpp>\n#include <gtirb/proto/Symbol.pb.h>\n#include <gtest/gtest.h>\n#include <sstream>\n\nusing namespace gtirb;\n\nstatic Context Ctx;\n\nTEST(Unit_Symbol, noCopyMoveConstructors) {\n  EXPECT_FALSE(std::is_copy_constructible_v<Symbol>);\n  EXPECT_FALSE(std::is_move_constructible_v<Symbol>);\n  EXPECT_FALSE(std::is_copy_assignable_v<Symbol>);\n  EXPECT_FALSE(std::is_move_assignable_v<Symbol>);\n}\n\nTEST(Unit_Symbol, ctor_0) { EXPECT_NE(Symbol::Create(Ctx, \"test\"), nullptr); }\n\nTEST(Unit_Symbol, setReferent) {\n  auto* Mod = Module::Create(Ctx, \"test\");\n  auto* Sym = Mod->addSymbol(Ctx, \"test\");\n  auto* S = Mod->addSection(Ctx, \"test\");\n  auto* BI = S->addByteInterval(Ctx, Addr(0), 4);\n  auto* Data = BI->addBlock<DataBlock>(Ctx, 0, 2);\n  auto* B = BI->addBlock<CodeBlock>(Ctx, 1, 2);\n  auto* Proxy = Mod->addProxyBlock(Ctx);\n\n  // Symbol should have no referent yet.\n  EXPECT_EQ(Sym->getReferent<Node>(), nullptr);\n  EXPECT_FALSE(Sym->getAddress());\n  EXPECT_FALSE(Sym->hasReferent());\n\n  Sym->setReferent(Data);\n  EXPECT_EQ(Sym->getReferent<CodeBlock>(), nullptr);\n  EXPECT_EQ(Sym->getReferent<DataBlock>(), Data);\n  EXPECT_EQ(Sym->getReferent<ProxyBlock>(), nullptr);\n  EXPECT_EQ(Sym->getAddress(), Addr(0));\n  EXPECT_TRUE(Sym->hasReferent());\n\n  Sym->setReferent(B);\n  EXPECT_EQ(Sym->getReferent<CodeBlock>(), B);\n  EXPECT_EQ(Sym->getReferent<DataBlock>(), nullptr);\n  EXPECT_EQ(Sym->getReferent<ProxyBlock>(), nullptr);\n  EXPECT_EQ(Sym->getAddress(), Addr(1));\n  EXPECT_TRUE(Sym->hasReferent());\n\n  Sym->setReferent(Proxy);\n  EXPECT_EQ(Sym->getReferent<CodeBlock>(), nullptr);\n  EXPECT_EQ(Sym->getReferent<DataBlock>(), nullptr);\n  EXPECT_EQ(Sym->getReferent<ProxyBlock>(), Proxy);\n  EXPECT_FALSE(Sym->getAddress());\n  EXPECT_TRUE(Sym->hasReferent());\n\n  Sym->setReferent<DataBlock>(nullptr);\n  EXPECT_EQ(Sym->getReferent<Node>(), nullptr);\n  EXPECT_FALSE(Sym->getAddress());\n  EXPECT_FALSE(Sym->hasReferent());\n}\n\nTEST(Unit_Symbol, protobufRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  std::stringstream sym_ss;\n  std::stringstream mod_ss;\n  UUID DataUUID;\n\n  // Symbol with referent\n  {\n    Context InnerCtx;\n    auto* Mod = Module::Create(InnerCtx, \"test\");\n    auto* Original = Symbol::Create(InnerCtx, \"test\");\n\n    auto* S = Mod->addSection(InnerCtx, \"test\");\n    auto* BI = S->addByteInterval(InnerCtx, Addr(0), 10);\n    auto* Data = BI->addBlock<DataBlock>(InnerCtx, 1, 1);\n    DataUUID = Data->getUUID();\n    Original->setReferent(Data);\n\n    STH::save(*Original, sym_ss);\n\n    // We must manually serialize the symbol referent. This would typically be\n    // done automatically for the user when they serialized the IR.\n    STH::save(*Mod, mod_ss);\n  }\n\n  {\n    Context InnerCtx;\n    (void)STH::load<Module>(InnerCtx, mod_ss); // See above.\n    auto* Result = STH::load<Symbol>(InnerCtx, sym_ss);\n\n    EXPECT_EQ(Result->getAddress(), Addr(1));\n    EXPECT_EQ(Result->getName(), \"test\");\n    EXPECT_EQ(Result->getReferent<DataBlock>()->getUUID(), DataUUID);\n    EXPECT_EQ(Result->getReferent<CodeBlock>(), nullptr);\n  }\n\n  // Symbol with address\n  std::stringstream sym_ss2;\n  {\n    Context InnerCtx;\n    auto* Original = Symbol::Create(InnerCtx, Addr(2), \"test\");\n    STH::save(*Original, sym_ss2);\n  }\n\n  {\n    Context InnerCtx;\n    auto* Result = STH::load<Symbol>(InnerCtx, sym_ss2);\n\n    EXPECT_EQ(Result->getAddress(), Addr(2));\n    EXPECT_EQ(Result->getName(), \"test\");\n    EXPECT_EQ(Result->getReferent<DataBlock>(), nullptr);\n    EXPECT_EQ(Result->getReferent<CodeBlock>(), nullptr);\n  }\n\n  // Symbol without address\n  std::stringstream sym_ss3;\n  {\n    Context InnerCtx;\n    auto* Original = Symbol::Create(InnerCtx, \"test\");\n    STH::save(*Original, sym_ss3);\n  }\n\n  {\n    Context InnerCtx;\n    auto* Result = STH::load<Symbol>(InnerCtx, sym_ss3);\n    EXPECT_FALSE(Result->getAddress());\n    EXPECT_EQ(Result->getName(), \"test\");\n  }\n}\n\nTEST(Unit_Symbol, visitation) {\n  auto* Sym = Symbol::Create(Ctx, CodeBlock::Create(Ctx, 2), \"test\");\n  auto* NoRef = Symbol::Create(Ctx, \"test2\");\n\n  struct Visitor {\n    int operator()(CodeBlock* B) {\n      // This should not be called with a null pointer.\n      EXPECT_NE(B, nullptr);\n      return 0;\n    }\n    long operator()(DataBlock*) {\n      // This overload should never be called.\n      EXPECT_TRUE(false);\n      return 1;\n    }\n    long operator()(ProxyBlock*) {\n      // This overload should never be called.\n      EXPECT_TRUE(false);\n      return 1;\n    }\n  };\n  EXPECT_EQ(0, *Sym->visit(Visitor{}));\n\n  // The version that has no referent should not call any of the visitor\n  // functions and the returned optional should not have a value.\n  struct NoRefVisitor {\n    int operator()(const CfgNode*) const {\n      EXPECT_TRUE(false);\n      return 0;\n    }\n    int operator()(const DataBlock*) const {\n      EXPECT_TRUE(false);\n      return 1;\n    }\n  };\n  EXPECT_FALSE(NoRef->visit(NoRefVisitor{}));\n\n  // Similar to the test above, but ensuring we can visit without a return type.\n  struct ConstVoidVisitor {\n    void operator()(const CfgNode* N) const { EXPECT_NE(N, nullptr); }\n    void operator()(const DataBlock*) const { EXPECT_TRUE(false); }\n  };\n  Sym->visit(ConstVoidVisitor{});\n\n  // Ensure that we can provide a visitor that uses a base type.\n  struct GenericVisitor {\n    void operator()(const Node* N) const {\n      EXPECT_NE(N, nullptr);\n      // This should still only be called once.\n      static int Counter;\n      EXPECT_EQ(Counter++, 0);\n    }\n  };\n  Sym->visit(GenericVisitor{});\n\n  // Ensure that we can provide a lambda as a callable.\n  Sym->visit([](const Node* N) {\n    EXPECT_NE(N, nullptr);\n    // This should still only be called once.\n    static int Counter;\n    EXPECT_EQ(Counter++, 0);\n  });\n\n  // The following is example code that should not compile. We cannot use gtest\n  // to ensure that we get the appropriate compile errors, unfortunately.\n  // struct NotEnoughOverloads {\n  //  void operator()(const Block*) {}\n  //};\n  // Sym->visit(NotEnoughOverloads{}); // Error\n\n  // struct IncorrectReturnTypes {\n  //  std::string operator()(Block*) { return \"\"; }\n  //  int operator()(DataBlock*) { return 0; }\n  //};\n  // Sym->visit(IncorrectReturnTypes{}); // Error\n}\n\nTEST(Unit_Symbol, atEnd) {\n  auto* Mod = Module::Create(Ctx, \"test\");\n  auto* Sym = Mod->addSymbol(Ctx, \"test\");\n  auto* S = Mod->addSection(Ctx, \"test\");\n  auto* BI = S->addByteInterval(Ctx, Addr(0), 4);\n  auto* Data = BI->addBlock<DataBlock>(Ctx, 0, 2);\n  auto* B = BI->addBlock<CodeBlock>(Ctx, 1, 2);\n\n  Sym->setReferent(B);\n  Sym->setAtEnd(true);\n  EXPECT_EQ(Sym->getAddress(), gtirb::Addr{3});\n\n  Sym->setReferent(B);\n  Sym->setAtEnd(false);\n  EXPECT_EQ(Sym->getAddress(), gtirb::Addr{1});\n\n  Sym->setReferent(Data);\n  Sym->setAtEnd(true);\n  EXPECT_EQ(Sym->getAddress(), gtirb::Addr{2});\n\n  Sym->setReferent(Data);\n  Sym->setAtEnd(false);\n  EXPECT_EQ(Sym->getAddress(), gtirb::Addr{0});\n}\n"
  },
  {
    "path": "src/test/SymbolicExpression.test.cpp",
    "content": "//===- SymbolicExpression.test.cpp ------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"SerializationTestHarness.hpp\"\n#include <gtirb/Context.hpp>\n#include <gtirb/Symbol.hpp>\n#include <gtirb/SymbolicExpression.hpp>\n#include <gtirb/proto/SymbolicExpression.pb.h>\n#include <gtest/gtest.h>\n#include <sstream>\n\nusing namespace gtirb;\n\nstatic Context Ctx;\n\nTEST(Unit_SymbolicExpression, protobufRoundTrip) {\n  Symbol* Sym1 = Symbol::Create(Ctx, Addr(1), \"test1\");\n  Symbol* Sym2 = Symbol::Create(Ctx, Addr(2), \"test2\");\n\n  // SymAddrConst\n  {\n    SymAttributeSet OrigSASet;\n    OrigSASet.insert({SymAttribute::ABS, SymAttribute::G0});\n    SymbolicExpression original(SymAddrConst{1, Sym1, OrigSASet});\n\n    gtirb::SymbolicExpression Result;\n    std::stringstream ss;\n    symbolicExpressionSave(original, ss);\n    symbolicExpressionLoad(Ctx, Result, ss);\n\n    SymAddrConst S = std::get<SymAddrConst>(Result);\n    EXPECT_EQ(S.Offset, 1);\n    EXPECT_EQ(S.Sym->getName(), \"test1\");\n    EXPECT_EQ(S.Attributes, OrigSASet);\n  }\n\n  // SymAddrAddr\n  {\n    SymbolicExpression original(SymAddrAddr{1, 2, Sym1, Sym2});\n\n    gtirb::SymbolicExpression Result;\n    std::stringstream ss;\n    symbolicExpressionSave(original, ss);\n    symbolicExpressionLoad(Ctx, Result, ss);\n\n    SymAddrAddr S = std::get<SymAddrAddr>(Result);\n    EXPECT_EQ(S.Scale, 1);\n    EXPECT_EQ(S.Offset, 2);\n    EXPECT_EQ(S.Sym1->getName(), \"test1\");\n    EXPECT_EQ(S.Sym2->getName(), \"test2\");\n  }\n}\n\nTEST(Unit_SymAttributeSet, unknownAttributes) {\n  std::ostringstream Out;\n  {\n    auto* I = IR::Create(Ctx);\n    auto* M = I->addModule(Ctx, \"foo\");\n    auto* S = M->addSection(Ctx, \"bar\");\n    auto* B = S->addByteInterval(Ctx, Addr(0), 8);\n\n    Symbol* Sym = Symbol::Create(Ctx, Addr(4), \"baz\");\n    SymAttributeSet Attrs{SymAttribute::GOT, static_cast<SymAttribute>(0xBEEF)};\n    B->addSymbolicExpression<SymAddrConst>(4, SymAddrConst{0, Sym, Attrs});\n\n    I->save(Out);\n  }\n\n  std::istringstream In(Out.str());\n  {\n    auto ResultOrErr = IR::load(Ctx, In);\n    ASSERT_TRUE(ResultOrErr);\n\n    auto* I = *ResultOrErr;\n    EXPECT_EQ(std::distance(I->symbolic_expressions_begin(),\n                            I->symbolic_expressions_end()),\n              1);\n    EXPECT_TRUE(std::holds_alternative<SymAddrConst>(\n        I->symbolic_expressions_begin()->getSymbolicExpression()));\n\n    SymAttributeSet Attrs =\n        std::get<SymAddrConst>(\n            I->symbolic_expressions_begin()->getSymbolicExpression())\n            .Attributes;\n    EXPECT_EQ(Attrs.count(SymAttribute::GOT), 1);\n    EXPECT_EQ(Attrs.count(static_cast<SymAttribute>(0xBEEF)), 1);\n  }\n}\n"
  },
  {
    "path": "src/test/TestHelpers.hpp",
    "content": "//===- TestHelpers.hpp ------------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2024 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n\n#ifndef GTIRB_TEST_HELPERS_H\n#define GTIRB_TEST_HELPERS_H\n\n#include <boost/iterator/transform_iterator.hpp>\n#include <boost/range/iterator_range.hpp>\n\n// Transforms a range of references into a range of pointers.\ntemplate <typename RangeTy> auto pointers(const RangeTy& Range) {\n  auto GetPointer = [](auto& arg) { return &arg; };\n  return boost::make_iterator_range(\n      boost::make_transform_iterator(Range.begin(), GetPointer),\n      boost::make_transform_iterator(Range.end(), GetPointer));\n}\n\n#endif // GTIRB_TEST_HELPERS_H\n"
  },
  {
    "path": "src/test/TypedNodeTest.cpp",
    "content": "//===- TypedNodeTest.cpp ----------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include \"SerializationTestHarness.hpp\"\n#include <gtirb/CodeBlock.hpp>\n#include <gtirb/Context.hpp>\n#include <gtirb/DataBlock.hpp>\n#include <gtirb/IR.hpp>\n#include <gtirb/Module.hpp>\n#include <gtirb/Section.hpp>\n#include <gtirb/Symbol.hpp>\n#include <gtirb/SymbolicExpression.hpp>\n#include <gtirb/proto/IR.pb.h>\n#include <gtirb/proto/Module.pb.h>\n#include <gtirb/proto/Section.pb.h>\n#include <gtirb/proto/Symbol.pb.h>\n#include <boost/uuid/uuid_generators.hpp>\n#include <gtest/gtest.h>\n#include <sstream>\n#include <type_traits>\n\nusing testing::Types;\n\ntypedef Types<gtirb::ByteInterval*, //\n              gtirb::CodeBlock*,    //\n              gtirb::DataBlock*,    //\n              gtirb::IR*,           //\n              gtirb::Module*,       //\n              gtirb::ProxyBlock*,   //\n              gtirb::Section*,      //\n              gtirb::Symbol*        //\n              >\n    TypeImplementations;\n\nstatic gtirb::Context Ctx;\n\n// ----------------------------------------------------------------------------\n// Helper for constructing nodes. Most nodes can be created with no arguments\n// and can use the main template. But the template can be specialized for node\n// types that require constructor arguments (e.g., Module).\n\ntemplate <class T> auto Create(gtirb::Context& C) { return T::Create(C); }\n\ntemplate <> auto Create<gtirb::Module>(gtirb::Context& C) {\n  return gtirb::Module::Create(C, \"test\");\n}\n\n// ----------------------------------------------------------------------------\n// Typed test fixture.\n\ntemplate <class T> class TypedNodeTest : public testing::Test {\nprotected:\n  TypedNodeTest() = default;\n  virtual ~TypedNodeTest() = default;\n};\n\nTYPED_TEST_SUITE_P(TypedNodeTest);\n\n// I tried making this a member of TypedNodeTest, but the member is unavailable\n// within the tests themselves, so this macro is used as a hacky solution.\n#define Type std::remove_pointer_t<TypeParam>\n\n// ----------------------------------------------------------------------------\n// Tests to run on all types.\n\nTYPED_TEST_P(TypedNodeTest, ctor_0) { EXPECT_NE(Create<Type>(Ctx), nullptr); }\n\nTYPED_TEST_P(TypedNodeTest, uniqueUuids) {\n  std::vector<gtirb::UUID> Uuids;\n  // Create a bunch of UUID's, then make sure we don't have any duplicates.\n\n  for (size_t I = 0; I < 64; ++I) {\n    const TypeParam N = Create<Type>(Ctx);\n    Uuids.push_back(N->getUUID());\n  }\n\n  std::sort(std::begin(Uuids), std::end(Uuids));\n  const auto end = std::unique(std::begin(Uuids), std::end(Uuids));\n\n  EXPECT_EQ(std::end(Uuids), end) << \"Duplicate UUID's were generated.\";\n}\n\nTYPED_TEST_P(TypedNodeTest, getByUUID) {\n  TypeParam Node = Create<Type>(Ctx);\n  EXPECT_EQ(gtirb::Node::getByUUID(Ctx, Node->getUUID()), Node);\n}\n\nTYPED_TEST_P(TypedNodeTest, protobufUUIDRoundTrip) {\n  using STH = gtirb::SerializationTestHarness;\n  std::stringstream ss;\n  gtirb::UUID OrigId;\n  {\n    gtirb::Context InnerCtx;\n    TypeParam Node1 = Create<Type>(InnerCtx);\n    OrigId = Node1->getUUID();\n\n    STH::save(*Node1, ss);\n  }\n\n  TypeParam Node2 = STH::load<Type>(Ctx, ss);\n  EXPECT_EQ(Node2->getUUID(), OrigId);\n}\n\nTYPED_TEST_P(TypedNodeTest, deserializeUpdatesUUIDMap) {\n  using STH = gtirb::SerializationTestHarness;\n  gtirb::UUID Id;\n  std::stringstream ss;\n\n  {\n    gtirb::Context InnerCtx;\n    TypeParam Node1 = Create<Type>(InnerCtx);\n    Id = Node1->getUUID();\n\n    STH::save(*Node1, ss);\n  }\n\n  EXPECT_EQ(Type::getByUUID(Ctx, Id), nullptr);\n\n  TypeParam Node2 = STH::load<Type>(Ctx, ss);\n  EXPECT_EQ(Type::getByUUID(Ctx, Id), Node2);\n}\n\nREGISTER_TYPED_TEST_SUITE_P(TypedNodeTest,             //\n                            protobufUUIDRoundTrip,     //\n                            ctor_0,                    //\n                            uniqueUuids,               //\n                            deserializeUpdatesUUIDMap, //\n                            getByUUID);\n\nINSTANTIATE_TYPED_TEST_SUITE_P(Unit_Nodes,           // Instance name\n                               TypedNodeTest,        // Test case name\n                               TypeImplementations); // Type list\n"
  },
  {
    "path": "src/test/UtilsDeprecatedGlobals.test.cpp",
    "content": "//===- UtilsDeprecatedGlobals.test.cpp --------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2024 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#include <gtirb/Allocator.hpp>\n#include <gtest/gtest.h>\n\n/*\nEnsure it is possible to use utility functions with no namespace if\nGTIRB_WRAP_UTILS_IN_NAMESPACE is not defined.\n*/\nTEST(Unit_IR, globalNextPowerOfTwo) { EXPECT_EQ(NextPowerOf2(5), 8U); }\n"
  },
  {
    "path": "src/test/UtilsUsingGtirbNamespace.test.cpp",
    "content": "//===- UtilsUsingGtirbNamespace.test.cpp ------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2024 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n#define GTIRB_WRAP_UTILS_IN_NAMESPACE\n#include <gtirb/Allocator.hpp>\n#include <gtest/gtest.h>\n\n/*\nEnsure it is possible to use utility functions by using the gtirb namesapce when\nGTIRB_WRAP_UTILS_IN_NAMESPACE is defined.\n*/\nusing namespace gtirb;\nTEST(Unit_IR, namespacedNextPowerOfTwo) { EXPECT_EQ(NextPowerOf2(5), 8U); }\nTEST(Unit_IR, explicitNamespacedNextPowerOfTwo) {\n  EXPECT_EQ(gtirb::NextPowerOf2(5), 8U);\n}\n"
  },
  {
    "path": "src/test/config-test.h.in",
    "content": "#cmakedefine HAVE_RESOURCE_H 1\n"
  },
  {
    "path": "src/test/runtests.cmake",
    "content": "# This is a short script that manages passing a gtirb file between two test\n# executables. The first is expected to create the gtirb file. The second is\n# expected to consume the file. The filename is passed as argv[1] to both\n# executables. The file is removed after both have run.\n\nmacro(EXEC_CHECK CMD)\n  execute_process(COMMAND ${CMD} ${ARGN} RESULT_VARIABLE CMD_RESULT)\n  if(CMD_RESULT)\n    message(FATAL_ERROR \"Error running ${CMD} ${ARGN}\")\n  endif()\nendmacro()\nset(GTIRB_FILENAME testfile.gtirb)\nexec_check(\"${CMD1}\" \"${GTIRB_FILENAME}\")\nexec_check(\"${CMD2}\" \"${GTIRB_FILENAME}\")\nfile(REMOVE ${GTIRB_FILENAME})\n"
  },
  {
    "path": "src/test/testInputBinary/CMakeLists.txt",
    "content": "# Generate several projects of increasing size and complexity for use in testing\n# GTIRB.\nmacro(GTIRB_BUILD_GTBINARY_MACRO)\n  set(PROJECT_NAME gtirbTestInputBinary${_GENERATION_CONSTANT})\n\n  set(${PROJECT_NAME}_H)\n\n  set(${PROJECT_NAME}_SRC TestInputBinary.cpp)\n\n  if(UNIX AND NOT WIN32)\n    set(SYSLIBS ${CMAKE_DL_LIBS})\n  else()\n    set(SYSLIBS)\n  endif()\n\n  add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_H} ${${PROJECT_NAME}_SRC})\n\n  set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER \"gtirb/test\")\n\n  target_compile_definitions(\n    ${PROJECT_NAME} PRIVATE -DGENERATION_CONSTANT=${_GENERATION_CONSTANT}\n  )\n\n  target_link_libraries(${PROJECT_NAME} ${SYSLIBS})\nendmacro()\n\nset(_GENERATION_CONSTANT 2)\ngtirb_build_gtbinary_macro()\n\nset(_GENERATION_CONSTANT 8)\ngtirb_build_gtbinary_macro()\n\nset(_GENERATION_CONSTANT 16)\ngtirb_build_gtbinary_macro()\n\nset(_GENERATION_CONSTANT 32)\ngtirb_build_gtbinary_macro()\n\nset(_GENERATION_CONSTANT 64)\ngtirb_build_gtbinary_macro()\n\n# set(_GENERATION_CONSTANT 128) GTIRB_BUILD_GTBINARY_MACRO()\n\n# set(_GENERATION_CONSTANT 256) GTIRB_BUILD_GTBINARY_MACRO()\n\n# set(_GENERATION_CONSTANT 512) GTIRB_BUILD_GTBINARY_MACRO()\n"
  },
  {
    "path": "src/test/testInputBinary/TestInputBinary.cpp",
    "content": "//===- TestInputBinary.cpp --------------------------------------*- C++ -*-===//\n//\n//  Copyright (C) 2020 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n///\n/// \\file \t\tTestInputBinary.cpp\n///\n/// References:\n/// \thttp://www.boost.org/doc/libs/1_66_0/libs/preprocessor/doc/index.html\n///\n/// Define GENERATION_CONSTANT to be between 1 and 65536.\n///\n\n#include <array>\n#include <cstdint>\n#include <cstdlib>\n#include <exception>\n#include <iostream>\n#include <stdio.h>\n#include <string>\n\n/// Compute a factorial\nint64_t Factorial(int64_t x) {\n  if (x <= 0) {\n    return 1;\n  } else {\n    return x * Factorial(x - 1);\n  }\n}\n\nstd::string IndirectFoo() { return \"Foo\"; }\n\nstd::string IndirectBar() { return \"Bar\"; }\n\nconst char* Index8[] = {\"one\",  \"two\", \"three\", \"four\",\n                        \"five\", \"six\", \"seven\", \"eight\"};\n\ntemplate <int N, int I> class GeneratedClass {\npublic:\n  GeneratedClass() { this->setName(\"GeneratedClass\"); }\n\n  /// Template function to print an integer.\n  void printInteger() {\n    std::cout << \"Class<\" << N << \", \" << I << \"> \";\n    std::cout << \"Factorial: !\" << I << \" = \" << Factorial(I) << \"; \";\n    std::cout << \"Throws: \" << this->randomThrow() << \"; \";\n    std::cout << \"Index: \" << this->randomIndex() << \"; \";\n    std::cout << \"Indirect: \" << this->randomIndirect() << \"; \";\n    std::cout << \"Member: \" << this->member << \"; \";\n    std::cout << std::endl;\n  }\n\n  bool randomThrow() {\n    this->setName(\"VOID\");\n    this->member += rand();\n\n    try {\n      if (rand() % 256 == 0) {\n        throw std::logic_error(\"Ramdom Throw\");\n      }\n    } catch (...) {\n      return true;\n    }\n\n    return false;\n  }\n\n  std::string randomIndex() const { return std::string(Index8[rand() % 8]); }\n\n  std::string randomIndirect() {\n    this->member -= rand();\n\n    if (rand() % 2 == 0) {\n      return IndirectFoo();\n    }\n\n    return IndirectBar();\n  }\n\n  void operator()() {\n    this->printInteger();\n\n    // Generate small binaries.\n    GeneratedClass<N - 1, I>()();\n\n    // Generate much bigger binaries\n    // GeneratedClass<N - 1, I + N>()();\n    // GeneratedClass<N - 1, I - N>()();\n  }\n\n  void setName(const std::string& x) { this->name = x; }\n\nprivate:\n  std::string name;\n  int64_t member{0};\n};\n\n// The \"Exit\" case for macro expansion.\ntemplate <int I> class GeneratedClass<0, I> {\npublic:\n  void operator()() {\n    // Empty\n  }\n};\n\nint main() { GeneratedClass<GENERATION_CONSTANT, 0>()(); }\n"
  },
  {
    "path": "src/test/testInterop/CMakeLists.txt",
    "content": "set(PROJECT_NAME testInterop)\n\nadd_executable(test_floats test_floats.cpp)\nadd_executable(test_variants test_variants.cpp)\nset_target_properties(test_floats PROPERTIES FOLDER \"gtirb/test/testInterop\")\nset_target_properties(test_variants PROPERTIES FOLDER \"gtirb/test/testInterop\")\n\ntarget_link_libraries(test_floats gtirb)\ntarget_link_libraries(test_variants gtirb)\n\ntarget_compile_definitions(test_floats PRIVATE GTIRB_WRAP_UTILS_IN_NAMESPACE)\ntarget_compile_definitions(test_variants PRIVATE GTIRB_WRAP_UTILS_IN_NAMESPACE)\n\nset(${PROJECT_NAME}_SCRIPTS test_floats.py test_variants.py)\nset(test_floats ${CMAKE_BINARY_DIR}/bin/test_floats)\n\nforeach(script_name ${${PROJECT_NAME}_SCRIPTS})\n  configure_file(\n    ${script_name} ${CMAKE_CURRENT_BINARY_DIR}/${script_name} @ONLY\n  )\nendforeach()\n"
  },
  {
    "path": "src/test/testInterop/test_floats.cpp",
    "content": "//===- test_floats.cpp ----------------------------------------------*- C++\n//-*-===//\n//\n//  Copyright (C) 2021 GrammaTech, Inc.\n//\n//  This code is licensed under the MIT license. See the LICENSE file in the\n//  project root for license terms.\n//\n//  This project is sponsored by the Office of Naval Research, One Liberty\n//  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n//  N68335-17-C-0700.  The content of the information does not necessarily\n//  reflect the position or policy of the Government and no official\n//  endorsement should be inferred.\n//\n//===----------------------------------------------------------------------===//\n\n#include <gtirb/gtirb.hpp>\n#include <cstring>\n#include <fstream>\n#include <iostream>\n\nstruct AFloat {\n  static constexpr const char* Name = \"AFloat\";\n  typedef float Type;\n};\n\nstruct ADouble {\n  static constexpr const char* Name = \"ADouble\";\n  typedef double Type;\n};\n\nvoid registerAuxData() {\n  gtirb::AuxDataContainer::registerAuxDataType<AFloat>();\n  gtirb::AuxDataContainer::registerAuxDataType<ADouble>();\n};\n\nint test_floats(const std::string& filename) {\n  gtirb::Context C;\n  std::ifstream inpt(filename, std::ios::binary);\n  auto ir = gtirb::IR::load(C, inpt);\n  if (ir) {\n    auto f = (*ir)->getAuxData<AFloat>();\n    auto g = (*ir)->getAuxData<ADouble>();\n    if (f && g && (*f == 0.5) && (*g == 2.0)) {\n      return 0;\n    }\n  }\n  return 1;\n}\n\nvoid create_floats(const std::string& filename) {\n  std::ofstream out(filename, std::ios::binary);\n  gtirb::Context C;\n  auto ir = gtirb::IR::Create(C);\n  ir->addAuxData<AFloat>(0.5);\n  ir->addAuxData<ADouble>(2.0);\n  ir->save(out);\n}\n\nint usage(const char* argv0) {\n  std::cout << \"Usage: \" << argv0 << \" {-r filename | -w filename}\\n\";\n  return -1;\n}\n\nint main(int argc, char** argv) {\n  if (argc < 3)\n    return usage(argv[0]);\n  registerAuxData();\n  if (strcmp(\"-w\", argv[1]) == 0) {\n    create_floats(argv[2]);\n    return 0;\n  } else if (strcmp(\"-r\", argv[1]) == 0) {\n    return test_floats(argv[2]);\n  } else {\n    return usage(argv[0]);\n  }\n}\n"
  },
  {
    "path": "src/test/testInterop/test_floats.py",
    "content": "# ===- test_floats.py ----------------------------------*- python -*-===//\n#\n#  Copyright (C) 2021 GrammaTech, Inc.\n#\n#  This code is licensed under the MIT license.\n#  See the LICENSE file in the project root for license terms.\n#\n#  This project is sponsored by the Office of Naval Research, One Liberty\n#  Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #\n#  N68335-17-C-0700.  The content of the information does not necessarily\n#  reflect the position or policy of the Government and no official\n#  endorsement should be inferred.\n#\n# ===-----------------------------------------------------------------===//\n\nimport argparse\n\nimport gtirb\n\n\ndef create_floats(filename: str):\n    ir = gtirb.IR()\n    ir.aux_data[\"AFloat\"] = gtirb.AuxData(0.5, \"float\")\n    ir.aux_data[\"ADouble\"] = gtirb.AuxData(2.0, \"double\")\n    ir.save_protobuf(filename)\n\n\ndef check_for_floats(filename: str) -> bool:\n    ir = gtirb.IR.load_protobuf(filename)\n    f = ir.aux_data[\"AFloat\"]\n    float_success = f.type_name == \"float\" and f.data == 0.5\n    g = ir.aux_data[\"ADouble\"]\n    double_success = g.type_name == \"double\" and g.data == 2.0\n    return float_success and double_success\n\n\nparser = argparse.ArgumentParser()\nparser.add_argument(\"-w\", required=False, type=str)\nparser.add_argument(\"-r\", required=False, type=str)\n\nif __name__ == \"__main__\":\n    args = parser.parse_args()\n    if args.w:\n        create_floats(args.w)\n    elif args.r:\n        if check_for_floats(args.r):\n            exit(0)\n        else:\n            exit(1)\n"
  },
  {
    "path": "src/test/testInterop/test_variants.cpp",
    "content": "#include <gtirb/gtirb.hpp>\n#include <cstring>\n#include <fstream>\n#include <iostream>\n#include <map>\n#include <string>\n#include <variant>\n\nstruct SimpleVariantMap {\n  typedef std::map<uint32_t, std::variant<int32_t, std::string>> Type;\n  static constexpr const char* Name = \"simpleVariantMap\";\n};\n\nstruct ComplexVariantMap {\n  typedef std::map<std::string, std::variant<int64_t, std::string, int64_t>>\n      Type;\n  static constexpr const char* Name = \"complexVariantMap\";\n};\n\nstatic const SimpleVariantMap::Type simpleMap{\n    {1, 1}, {2, \"a\"}, {3, \"z\"}, {4, -1}};\n\ntypedef std::variant<int64_t, std::string, int64_t> Var;\n\nstatic const ComplexVariantMap::Type complexMap{\n    {\"a\", Var(std::in_place_index<0>, 1)},\n    {\"b\", Var(\"hello\")},\n    {\"c\", Var(std::in_place_index<2>, 4)},\n    {\"d\", Var(std::in_place_index<0>, 0)}};\n\nvoid register_schema() {\n  gtirb::AuxDataContainer::registerAuxDataType<SimpleVariantMap>();\n  gtirb::AuxDataContainer::registerAuxDataType<ComplexVariantMap>();\n}\n\nvoid add_auxdata(gtirb::IR* Ir) {\n  auto NewSimpleMap = simpleMap;\n  auto NewComplexMap = complexMap;\n  Ir->addAuxData<SimpleVariantMap>(std::move(NewSimpleMap));\n  Ir->addAuxData<ComplexVariantMap>(std::move(NewComplexMap));\n}\n\nbool write_ir(const std::string& filename) {\n  std::ofstream dest{filename};\n  gtirb::Context Ctx;\n  auto* Ir = gtirb::IR::Create(Ctx);\n  if (!Ir)\n    return 1;\n  add_auxdata(Ir);\n  Ir->save(dest);\n  return 0;\n}\n\nbool check_ir(const std::string& filename) {\n  std::ifstream Src{filename, std::ios::binary | std::ios::in};\n  gtirb::Context Ctx;\n  auto MaybeIR = gtirb::IR::load(Ctx, Src);\n  if (!MaybeIR)\n    return 1;\n  auto* Ir = *MaybeIR;\n  auto* NewSimpleMap = Ir->getAuxData<SimpleVariantMap>();\n  if (!NewSimpleMap)\n    return 1;\n  auto* NewComplexMap = Ir->getAuxData<ComplexVariantMap>();\n  if (!NewComplexMap)\n    return 1;\n  return 0;\n}\n\nint usage(const char* argv0) {\n  std::cout << \"Usage: \" << argv0 << \" {-r filename | -w filename}\\n\";\n  return -1;\n}\n\nint main(int argc, char** argv) {\n  if (argc < 3)\n    return usage(argv[0]);\n  register_schema();\n  if (strcmp(argv[1], \"-r\") == 0)\n    return check_ir(argv[2]);\n  if (strcmp(argv[1], \"-w\") == 0)\n    return write_ir(argv[2]);\n  return usage(argv[0]);\n}\n"
  },
  {
    "path": "src/test/testInterop/test_variants.py",
    "content": "import dataclasses\nimport os\nimport tempfile\nfrom typing import Any, ClassVar\n\nimport gtirb\n\n\nclass V1(gtirb.Variant):\n    type_list = [\n        int,\n        str,\n    ]\n\n    def __init__(self, val: Any):\n        index = self.type_list.index(type(val))\n        super().__init__(index, val)\n\n\ndef compare_variant_maps(m1, m2):\n    assert not set(m1.keys()) ^ set(m2.keys())\n    assert not set(v.val for v in m1.values()) ^ set(\n        v.val for v in m2.values()\n    )\n\n\ndef make_simple_variant_map():\n    vmap = {1: V1(1), 2: V1(\"a\"), 3: V1(\"z\"), 4: V1(-1)}\n\n    ad = gtirb.AuxData(vmap, \"mapping<uint32_t,variant<int32_t,string>>\")\n    ir = gtirb.IR()\n    ir.aux_data[\"simpleVariantMap\"] = ad\n    return ir, vmap\n\n\ndef test_mapvariant():\n    ir, vmap = make_simple_variant_map()\n    _, tmp = tempfile.mkstemp()\n    try:\n        ir.save_protobuf(tmp)\n        ir2 = gtirb.IR.load_protobuf(tmp)\n    finally:\n        os.remove(tmp)\n    ad2 = ir2.aux_data[\"simpleVariantMap\"].data\n    compare_variant_maps(ad2, vmap)\n\n\n@dataclasses.dataclass\nclass I1:\n    GTIRB_TYPE: ClassVar[str] = \"int64_t\"\n    data: int\n\n\n@dataclasses.dataclass\nclass I2:\n    GTIRB_TYPE: ClassVar[str] = \"int64_t\"\n    data: int\n\n\n@dataclasses.dataclass\nclass S1:\n    GTIRB_TYPE: ClassVar[str] = \"string\"\n    data: str\n\n\n@dataclasses.dataclass\nclass MyMap:\n    TYPELIST = [\n        I1,\n        S1,\n        I2,\n    ]\n    GTIRB_TYPE = \"variant<\" + \",\".join(t.GTIRB_TYPE for t in TYPELIST) + \">\"\n\n    def __init__(self, map_) -> None:\n        self._map = map_\n\n    def __eq__(self, __o: object) -> bool:\n        if not isinstance(__o, MyMap):\n            return False\n        return self._map == __o._map\n\n    def __repr__(self) -> str:\n        return f\"MyMap({self._map!r})\"\n\n    def toAuxData(self):\n        return {\n            k: gtirb.Variant(self.TYPELIST.index(type(v)), v.data)\n            for k, v in self._map.items()\n        }\n\n    @classmethod\n    def fromAuxData(cls, auxdata: gtirb.AuxData):\n        if not isinstance(auxdata.data, dict):\n            raise Exception()\n        newmap = dict()\n        for (k, v) in auxdata.data.items():\n            newmap[k] = cls.TYPELIST[v.index](v.val)\n        return cls(newmap)\n\n\ndef make_complex_variant_map():\n    variant_map = MyMap({\"a\": I1(1), \"b\": S1(\"hello\"), \"c\": I2(4), \"d\": I1(0)})\n\n    ad = gtirb.AuxData(\n        data=variant_map.toAuxData(),\n        type_name=f\"mapping<string,{MyMap.GTIRB_TYPE}>\",\n    )\n    ir = gtirb.IR()\n    ir.aux_data[\"complexVariantMap\"] = ad\n    return ir, variant_map\n\n\ndef test_complex_variant_map():\n    ir, variant_map = make_complex_variant_map()\n    _, tmp = tempfile.mkstemp()\n    try:\n        ir.save_protobuf(tmp)\n        ir2 = gtirb.IR.load_protobuf(tmp)\n    finally:\n        os.remove(tmp)\n    ad2 = MyMap.fromAuxData(ir2.aux_data[\"complexVariantMap\"])\n    assert ad2 == variant_map\n\n\ndef write_ir(filename):\n    ir, _ = make_simple_variant_map()\n    ir2, _ = make_complex_variant_map()\n    ir.aux_data[\"complexVariantMap\"] = ir2.aux_data[\"complexVariantMap\"]\n    ir.save_protobuf(filename)\n\n\ndef check_ir(filename):\n    ir = gtirb.IR.load_protobuf(filename)\n    _, simple = make_simple_variant_map()\n    compare_variant_maps(ir.aux_data[\"simpleVariantMap\"].data, simple)\n    my_map = MyMap.fromAuxData(ir.aux_data[\"complexVariantMap\"])\n    _, my_other_map = make_complex_variant_map()\n    assert my_other_map == my_map, (my_other_map, my_map)\n\n\nif __name__ == \"__main__\":\n    import argparse\n\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\"-r\")\n    parser.add_argument(\"-w\")\n    args = parser.parse_args()\n\n    if args.r:\n        check_ir(args.r)\n\n    if args.w:\n        write_ir(args.w)\n"
  },
  {
    "path": "version.txt",
    "content": "VERSION_MAJOR 2\nVERSION_MINOR 3\nVERSION_PATCH 2\nVERSION_PROTOBUF 4\n"
  }
]