diff --git a/.clang-format b/.clang-format
index 05baf03..74f95dc 100644
--- a/.clang-format
+++ b/.clang-format
@@ -125,7 +125,7 @@ IndentCaseBlocks: false
IndentCaseLabels: false
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
-IndentPPDirectives: None
+IndentPPDirectives: BeforeHash
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
deleted file mode 100644
index 818d35b..0000000
--- a/.devcontainer/Dockerfile
+++ /dev/null
@@ -1,17 +0,0 @@
-FROM mcr.microsoft.com/devcontainers/cpp:1-ubuntu-22.04
-
-USER vscode
-
-# Install latest cmake
-RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
-RUN echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ jammy main' | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null
-RUN sudo apt-get update && sudo apt-get install -y cmake
-
-# Install pre-commit
-RUN sudo apt-get install -y python3-pip && pip3 install pre-commit
-
-# Avoid ASAN Stalling
-# See: https://github.com/google/sanitizers/issues/1614
-# Alternative is to update to above clang-18 and gcc-13.2
-# Maybe crashing codespace???
-RUN sudo sysctl -w vm.mmap_rnd_bits=28
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
deleted file mode 100644
index 07344f6..0000000
--- a/.devcontainer/devcontainer.json
+++ /dev/null
@@ -1,18 +0,0 @@
-// For format details, see https://aka.ms/devcontainer.json. For config options, see the
-// README at: https://github.com/devcontainers/templates/tree/main/src/cpp
-
-{
- "name": "Beman Project Generic Devcontainer",
- "build": {
- "dockerfile": "Dockerfile"
- },
- "postCreateCommand": "bash .devcontainer/postcreate.sh",
- "customizations": {
- "vscode": {
- "extensions": [
- "ms-vscode.cpptools",
- "ms-vscode.cmake-tools"
- ]
- }
- }
-}
diff --git a/.devcontainer/postcreate.sh b/.devcontainer/postcreate.sh
deleted file mode 100644
index bddba03..0000000
--- a/.devcontainer/postcreate.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-# Setup pre-commit
-pre-commit
-pre-commit install
diff --git a/.exemplar_version b/.exemplar_version
new file mode 100644
index 0000000..447909a
--- /dev/null
+++ b/.exemplar_version
@@ -0,0 +1 @@
+ab5c7c0cbf1f67eb43b7be9c2d18acd4d6de1ea4
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..793dce7
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,5 @@
+infra/** linguist-vendored
+cookiecutter/** linguist-vendored
+*.bib -linguist-detectable
+*.tex -linguist-detectable
+papers/* linguist-documentation
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 5463655..6b8dfea 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,23 +1,3 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-# Codeowners for reviews on PRs
-# Note(river):
-# **Please understand how codeowner file work before uncommenting anything in this section:**
-# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
-#
-# For projects using exemplar as a template and intend to reuse its infrastructure,
-# River (@wusatosi) helped create most of the original infrastructure under the scope described below,
-# they are more than happy to help out with any PRs downstream,
-# as well as to sync any useful change upstream to exemplar.
-#
-# Github Actions:
-# .github/workflows/ @wusatosi # Add other project owners here
-#
-# Devcontainer:
-# .devcontainer/ @wusatosi # Add other project owners here
-#
-# Pre-commit:
-# .pre-commit-config.yaml @wusatosi # Add other project owners here
-# .markdownlint.yaml @wusatosi # Add other project owners here
-
-* @ednolan @RobertLeahy
+* @RobertLeahy
diff --git a/.github/ISSUE_TEMPLATE/implementation-deficiency.md b/.github/ISSUE_TEMPLATE/implementation-deficiency.md
new file mode 100644
index 0000000..4a0ee77
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/implementation-deficiency.md
@@ -0,0 +1,35 @@
+---
+name: Implementation Deficiency
+about: Report a bug or performance issue of our implementation
+title: ''
+labels: bug
+assignees: ''
+
+---
+
+
+
+## Describe the deficiency
+
+A clear and concise description of what the deficiency is.
+Link all relevant issues.
+This could be a bug, or a performance problem.
+
+## To Reproduce
+
+```c++
+// Use case
+```
+
+## Expected Behavior
+
+A clear and concise description of what you expected to happen.
+
+## Additional Discussions
+
+Add any other context about the problem here.
+If you believe your issue is platform dependent,
+please post your compiler versions here.
diff --git a/.github/ISSUE_TEMPLATE/infrastructure-issues.md b/.github/ISSUE_TEMPLATE/infrastructure-issues.md
new file mode 100644
index 0000000..11fbd13
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/infrastructure-issues.md
@@ -0,0 +1,29 @@
+---
+name: Infrastructure Issues
+about: Report a bug or feature request with our Infrastructure
+title: ''
+labels: infra
+assignees: ''
+
+---
+
+
+
+## I am attempting to
+
+Describe what you were attempting to do.
+
+## Expected Behavior
+
+A clear and concise description of what you expected to happen.
+
+## Current Behavior
+
+A clear and concise description of what actually happened.
+
+## Additional Discussions
+
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/paper-discussion.md b/.github/ISSUE_TEMPLATE/paper-discussion.md
new file mode 100644
index 0000000..14c9e4f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/paper-discussion.md
@@ -0,0 +1,33 @@
+---
+name: Paper Discussion
+about: Provide feedback to current API
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+
+
+## Use case
+
+Describe your concerns about adding this change to the C++ Standard Library.
+
+```c++
+// example snippet
+```
+
+## What I like
+
+Let us know what you find positive about current approach / design.
+
+## What I dislike
+
+Let us know what you find negative about current approach / design.
+
+## Discussion
+
+Let us know if you have any more remarks.
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..071cb28
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,5 @@
+
diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml
index 0d5f8ba..6f0ef58 100644
--- a/.github/workflows/ci_tests.yml
+++ b/.github/workflows/ci_tests.yml
@@ -4,275 +4,147 @@ name: Continuous Integration Tests
on:
push:
+ branches:
+ - main
pull_request:
- # Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
schedule:
- - cron: '30 15 * * *'
+ - cron: '37 16 * * 1'
jobs:
- preset-test:
- strategy:
- matrix:
- presets:
- - preset: "gcc-debug"
- platform: "ubuntu-latest"
- - preset: "gcc-release"
- platform: "ubuntu-latest"
- - preset: "appleclang-debug"
- platform: "macos-latest"
- - preset: "appleclang-release"
- platform: "macos-latest"
- - preset: "msvc-debug"
- platform: "windows-latest"
- - preset: "msvc-release"
- platform: "windows-latest"
- name: "Preset: ${{ matrix.presets.preset }} on ${{ matrix.presets.platform }}"
- runs-on: ${{ matrix.presets.platform }}
- steps:
- - uses: actions/checkout@v4
- - name: Setup build environment
- uses: lukka/get-cmake@latest
- with:
- cmakeVersion: "~3.25.0"
- ninjaVersion: "^1.11.1"
- - name: Setup MSVC
- if: startsWith(matrix.presets.platform, 'windows')
- uses: TheMrMilchmann/setup-msvc-dev@v3
- with:
- arch: x64
- - name: Run preset
- run: cmake --workflow --preset ${{ matrix.presets.preset }}
-
- gtest-test:
- strategy:
- fail-fast: false
- matrix:
- platform:
- - description: "Ubuntu GNU"
- os: ubuntu-latest
- toolchain: "cmake/gnu-toolchain.cmake"
- - description: "Ubuntu LLVM"
- os: ubuntu-latest
- toolchain: "cmake/llvm-toolchain.cmake"
- - description: "Windows MSVC"
- os: windows-latest
- toolchain: "cmake/msvc-toolchain.cmake"
- - description: "Macos Appleclang"
- os: macos-latest
- toolchain: "cmake/appleclang-toolchain.cmake"
- cpp_version: [20, 23, 26]
- cmake_args:
- - description: "Default"
- - description: "TSan"
- args: "-DBEMAN_BUILDSYS_SANITIZER=TSan"
- - description: "MaxSan"
- args: "-DBEMAN_BUILDSYS_SANITIZER=MaxSan"
- include:
- - platform:
- description: "Ubuntu GCC"
- os: ubuntu-latest
- toolchain: "cmake/gnu-toolchain.cmake"
- cpp_version: 20
- cmake_args:
- description: "Werror"
- args: "-DCMAKE_CXX_FLAGS='-Werror=all -Werror=extra'"
- - platform:
- description: "Ubuntu GCC"
- os: ubuntu-latest
- toolchain: "cmake/gnu-toolchain.cmake"
- cpp_version: 20
- cmake_args:
- description: "Dynamic"
- args: "-DBUILD_SHARED_LIBS=on"
- exclude:
- # MSVC does not support thread sanitizer
- - platform:
- description: "Windows MSVC"
- cmake_args:
- description: "TSan"
-
- name: "Unit: ${{ matrix.platform.description }} ${{ matrix.cpp_version }} ${{ matrix.cmake_args.description }}"
- runs-on: ${{ matrix.platform.os }}
- steps:
- - uses: actions/checkout@v4
- - name: Install Ninja
- uses: lukka/get-cmake@latest
- with:
- cmakeVersion: "~3.25.0"
- ninjaVersion: "^1.11.1"
- - name: Setup MSVC
- if: startsWith(matrix.platform.os, 'windows')
- uses: TheMrMilchmann/setup-msvc-dev@v3
- with:
- arch: x64
- - name: Setup Macos
- if: startsWith(matrix.platform.os, 'macos')
- run: sudo chmod -R 777 /opt/
- - name: Print installed softwares
- shell: bash
- run: |
- echo "Build system:"
- cmake --version
- ninja --version
- - name: Configure CMake
- run: |
- cmake -B build -S . -DCMAKE_CXX_STANDARD=${{ matrix.cpp_version }} -DCMAKE_TOOLCHAIN_FILE="${{ matrix.platform.toolchain }}" ${{ matrix.cmake_args.args }}
- env:
- CMAKE_GENERATOR: "Ninja Multi-Config"
- - name: Build Release
- run: |
- # Portable commands only
- cmake --build build --config Release --parallel --verbose
- cmake --build build --config Release --target all_verify_interface_header_sets
- cmake --install build --config Release --prefix /opt/beman.elide
- ls -R /opt/beman.elide
- - name: Test Release
- run: ctest --test-dir build --build-config Release
- - name: Build Debug
- run: |
- # Portable commands only
- cmake --build build --config Debug --parallel --verbose
- cmake --build build --config Debug --target all_verify_interface_header_sets
- cmake --install build --config Debug --prefix /opt/beman.elide
- ls -R /opt/beman.elide
- - name: Test Debug
- run: ctest --test-dir build --build-config Debug
-
- configuration-test:
- runs-on: ubuntu-latest
- strategy:
- matrix:
- args:
- - name: "Disable build testing"
- arg: "-DBEMAN_ELIDE_BUILD_TESTS=OFF"
- name: "CMake: ${{ matrix.args.name }}"
- steps:
- - uses: actions/checkout@v4
- - name: Setup build environment
- uses: lukka/get-cmake@latest
- with:
- cmakeVersion: "~3.25.0"
- ninjaVersion: "^1.11.1"
- - name: Print installed softwares
- run: |
- cmake --version
- ninja --version
- - name: Configure CMake
- run: |
- cmake -B build -S . -DCMAKE_CXX_STANDARD=20 ${{ matrix.args.arg }}
- env:
- CMAKE_GENERATOR: "Ninja Multi-Config"
- - name: Build Release
- run: |
- # Portable commands only
- cmake --build build --config Release --parallel --verbose
- cmake --build build --config Release --target all_verify_interface_header_sets
- cmake --install build --config Release --prefix /opt/beman.elide
- ls -R /opt/beman.elide
- - name: Build Debug
- run: |
- # Portable commands only
- cmake --build build --config Debug --parallel --verbose
- cmake --build build --config Debug --target all_verify_interface_header_sets
- cmake --install build --config Debug --prefix /opt/beman.elide
- ls -R /opt/beman.elide
-
- compiler-test:
- runs-on: ubuntu-24.04
- strategy:
- matrix:
- compilers:
- - class: GNU
- version: 14
- - class: GNU
- version: 13
- - class: GNU
- version: 12
- - class: LLVM
- version: 20
- - class: LLVM
- version: 19
- - class: LLVM
- version: 18
- - class: LLVM
- version: 17
- name: "Compiler: ${{ matrix.compilers.class }} ${{ matrix.compilers.version }}"
- steps:
- - uses: actions/checkout@v4
- - name: Setup build environment
- uses: lukka/get-cmake@latest
- with:
- cmakeVersion: "~3.25.0"
- ninjaVersion: "^1.11.1"
- - name: Install Compiler
- id: install-compiler
- run: |
- if [ "${{ matrix.compilers.class }}" = "GNU" ]; then
- CC=gcc-${{ matrix.compilers.version }}
- CXX=g++-${{ matrix.compilers.version }}
-
- sudo add-apt-repository universe
- sudo apt-get update
- sudo apt-get install -y $CC
- sudo apt-get install -y $CXX
-
- $CC --version
- $CXX --version
- else
- wget https://apt.llvm.org/llvm.sh
- chmod +x llvm.sh
- sudo bash llvm.sh ${{ matrix.compilers.version }}
-
- CC=clang-${{ matrix.compilers.version }}
- CXX=clang++-${{ matrix.compilers.version }}
-
- $CC --version
- $CXX --version
- fi
-
- echo "CC=$CC" >> "$GITHUB_OUTPUT"
- echo "CXX=$CXX" >> "$GITHUB_OUTPUT"
- - name: Configure CMake
- run: |
- cmake -B build -S . -DCMAKE_CXX_STANDARD=20
- env:
- CC: ${{ steps.install-compiler.outputs.CC }}
- CXX: ${{ steps.install-compiler.outputs.CXX }}
- CMAKE_GENERATOR: "Ninja Multi-Config"
- - name: Build Debug
- run: |
- cmake --build build --config Debug --verbose
- cmake --build build --config Debug --target all_verify_interface_header_sets
- cmake --install build --config Debug --prefix /opt/beman.elide
- find /opt/beman.elide -type f
- - name: Test Debug
- run: ctest --test-dir build --build-config Debug
+ beman-submodule-check:
+ uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-submodule-check.yml@1.5.3
+ preset-test:
+ uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-preset-test.yml@1.5.3
+ with:
+ matrix_config: >
+ [
+ {"preset": "gcc-debug", "image": "ghcr.io/bemanproject/infra-containers-gcc:latest"},
+ {"preset": "gcc-release", "image": "ghcr.io/bemanproject/infra-containers-gcc:latest"},
+ {"preset": "llvm-debug", "image": "ghcr.io/bemanproject/infra-containers-clang:latest"},
+ {"preset": "llvm-release", "image": "ghcr.io/bemanproject/infra-containers-clang:latest"},
+ {"preset": "appleclang-debug", "runner": "macos-latest"},
+ {"preset": "appleclang-release", "runner": "macos-latest"},
+ {"preset": "msvc-debug", "runner": "windows-latest"},
+ {"preset": "msvc-release", "runner": "windows-latest"}
+ ]
+
+ build-and-test:
+ uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-build-and-test.yml@1.5.3
+ with:
+ matrix_config: >
+ {
+ "gcc": [
+ { "versions": ["15"],
+ "tests": [
+ { "cxxversions": ["c++26"],
+ "tests": [
+ { "stdlibs": ["libstdc++"],
+ "tests": [
+ "Debug.Default", "Release.Default", "Release.TSan",
+ "Release.MaxSan", "Debug.Werror",
+ "Debug.Coverage"
+ ]
+ }
+ ]
+ },
+ { "cxxversions": ["c++23", "c++20"],
+ "tests": [{ "stdlibs": ["libstdc++"], "tests": ["Release.Default"]}]
+ }
+ ]
+ },
+ { "versions": ["14", "13"],
+ "tests": [
+ { "cxxversions": ["c++26", "c++23", "c++20"],
+ "tests": [{ "stdlibs": ["libstdc++"], "tests": ["Release.Default"]}]
+ }
+ ]
+ },
+ {
+ "versions": ["12", "11"],
+ "tests": [
+ { "cxxversions": ["c++23", "c++20"],
+ "tests": [{ "stdlibs": ["libstdc++"], "tests": ["Release.Default"]}]
+ }
+ ]
+ }
+ ],
+ "clang": [
+ { "versions": ["22"],
+ "tests": [
+ {"cxxversions": ["c++26"],
+ "tests": [
+ { "stdlibs": ["libstdc++", "libc++"],
+ "tests": [
+ "Debug.Default", "Release.Default", "Release.TSan",
+ "Release.MaxSan", "Debug.Werror"
+ ]
+ }
+ ]
+ },
+ { "cxxversions": ["c++23", "c++20"],
+ "tests": [
+ {"stdlibs": ["libstdc++", "libc++"], "tests": ["Release.Default"]}
+ ]
+ }
+ ]
+ },
+ { "versions": ["21", "20", "19"],
+ "tests": [
+ { "cxxversions": ["c++26", "c++23", "c++20"],
+ "tests": [
+ {"stdlibs": ["libstdc++", "libc++"], "tests": ["Release.Default"]}
+ ]
+ }
+ ]
+ },
+ { "versions": ["18"],
+ "tests": [
+ { "cxxversions": ["c++26", "c++23", "c++20"],
+ "tests": [{"stdlibs": ["libc++"], "tests": ["Release.Default"]}]
+ },
+ { "cxxversions": ["c++23", "c++20"],
+ "tests": [{"stdlibs": ["libstdc++"], "tests": ["Release.Default"]}]
+ }
+ ]
+ },
+ { "versions": ["17"],
+ "tests": [
+ { "cxxversions": ["c++26", "c++23", "c++20"],
+ "tests": [{"stdlibs": ["libc++"], "tests": ["Release.Default"]}]
+ },
+ { "cxxversions": ["c++20"],
+ "tests": [{"stdlibs": ["libstdc++"], "tests": ["Release.Default"]}]
+ }
+ ]
+ }
+ ],
+ "appleclang": [
+ { "versions": ["latest"],
+ "tests": [
+ { "cxxversions": ["c++26", "c++23", "c++20"],
+ "tests": [{ "stdlibs": ["libc++"], "tests": ["Release.Default"]}]
+ }
+ ]
+ }
+ ],
+ "msvc": [
+ { "versions": ["latest"],
+ "tests": [
+ { "cxxversions": ["c++23"],
+ "tests": [
+ { "stdlibs": ["stl"],
+ "tests": ["Debug.Default", "Release.Default", "Release.MaxSan"]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
create-issue-when-fault:
- runs-on: ubuntu-latest
- needs: [preset-test, gtest-test, configuration-test, compiler-test]
+ needs: [preset-test, build-and-test]
if: failure() && github.event_name == 'schedule'
- steps:
- # See https://github.com/cli/cli/issues/5075
- - uses: actions/checkout@v4
- - name: Create issue
- run: |
- issue_num=$(gh issue list -s open -S "[SCHEDULED-BUILD] Build & Test failure" -L 1 --json number | jq 'if length == 0 then -1 else .[0].number end')
-
- body="**Build-and-Test Failure Report**
- - **Time of Failure**: $(date -u '+%B %d, %Y, %H:%M %Z')
- - **Commit**: [${{ github.sha }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }})
- - **Action Run**: [View logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
-
- The scheduled build-and-test triggered by cron has failed.
- Please investigate the logs and recent changes associated with this commit or rerun the workflow if you believe this is an error."
-
- if [[ $issue_num -eq -1 ]]; then
- gh issue create --repo ${{ github.repository }} --title "[SCHEDULED-BUILD] Build & Test failure" --body "$body"
- else
- gh issue comment --repo ${{ github.repository }} $issue_num --body "$body"
- fi
- env:
- GH_TOKEN: ${{ github.token }}
+ uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-create-issue-when-fault.yml@1.5.3
diff --git a/.github/workflows/pre-commit-check.yml b/.github/workflows/pre-commit-check.yml
new file mode 100644
index 0000000..980f6c5
--- /dev/null
+++ b/.github/workflows/pre-commit-check.yml
@@ -0,0 +1,19 @@
+name: Lint Check (pre-commit)
+
+on:
+ # We have to use pull_request_target here as pull_request does not grant
+ # enough permission for reviewdog
+ pull_request_target:
+ push:
+ branches:
+ - main
+
+permissions:
+ contents: read
+ checks: write
+ issues: write
+ pull-requests: write
+
+jobs:
+ pre-commit:
+ uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-pre-commit.yml@1.5.3
diff --git a/.github/workflows/pre-commit-update.yml b/.github/workflows/pre-commit-update.yml
new file mode 100644
index 0000000..08e2c03
--- /dev/null
+++ b/.github/workflows/pre-commit-update.yml
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+name: Weekly pre-commit autoupdate
+
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: "23 16 * * 4"
+
+jobs:
+ auto-update-pre-commit:
+ uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-update-pre-commit.yml@1.5.3
+ secrets:
+ APP_ID: ${{ secrets.AUTO_PR_BOT_APP_ID }}
+ PRIVATE_KEY: ${{ secrets.AUTO_PR_BOT_PRIVATE_KEY }}
diff --git a/.gitignore b/.gitignore
index 286a38e..d293e3b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,12 @@
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+/.cache
/compile_commands.json
/build
+
+# ignore emacs temp files
+*~
+\#*\#
+
+# ignore vscode settings
+.vscode
diff --git a/.markdownlint.yaml b/.markdownlint.yaml
index 81f5fcd..21c2849 100644
--- a/.markdownlint.yaml
+++ b/.markdownlint.yaml
@@ -7,3 +7,4 @@ MD033: false
# Update the comment in .clang-format if we no-longer tie these two column limits.
MD013:
line_length: 119
+ code_blocks: false
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index a26bab0..eb01186 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -2,7 +2,7 @@
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v5.0.0
+ rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@@ -13,21 +13,36 @@ repos:
# This brings in a portable version of clang-format.
# See also: https://github.com/ssciwr/clang-format-wheel
- repo: https://github.com/pre-commit/mirrors-clang-format
- rev: v18.1.8
+ rev: v22.1.4
hooks:
- id: clang-format
types_or: [c++, c]
# CMake linting and formatting
- - repo: https://github.com/BlankSpruce/gersemi
- rev: 0.15.1
+ - repo: https://github.com/BlankSpruce/gersemi-pre-commit
+ rev: 0.27.2
hooks:
- id: gersemi
name: CMake linting
+ exclude: ^.*/tests/.*/data/ # Exclude test data directories
# Markdown linting
# Config file: .markdownlint.yaml
- - repo: https://github.com/igorshubovych/markdownlint-cli
- rev: v0.42.0
+ # Commented out to disable this by default. Uncomment to enable markdown linting.
+ # - repo: https://github.com/igorshubovych/markdownlint-cli
+ # rev: v0.42.0
+ # hooks:
+ # - id: markdownlint
+
+ - repo: https://github.com/codespell-project/codespell
+ rev: v2.4.2
+ hooks:
+ - id: codespell
+
+ # Beman Standard checking via beman-tidy
+ - repo: https://github.com/bemanproject/beman-tidy
+ rev: v0.3.1
hooks:
- - id: markdownlint
+ - id: beman-tidy
+
+exclude: 'cookiecutter/|infra/'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6329852..28d7072 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,40 +1,45 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-cmake_minimum_required(VERSION 3.25)
+cmake_minimum_required(VERSION 3.30...4.3)
project(
- beman.elide
+ beman.elide # CMake Project Name, which is also the name of the top-level
+ # targets (e.g., library, executable, etc.).
DESCRIPTION "Implements proposed std::elide"
LANGUAGES CXX
+ VERSION 0.1.0
)
-enable_testing()
-
# [CMAKE.SKIP_TESTS]
option(
BEMAN_ELIDE_BUILD_TESTS
- "Enable building tests and test infrastructure. Default: ON. Values: { ON, OFF }."
+ "Enable building tests and test infrastructure. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }."
${PROJECT_IS_TOP_LEVEL}
)
-include(FetchContent)
-include(GNUInstallDirs)
+# for find of beman_install_library and configure_build_telemetry
+include(infra/cmake/beman-install-library.cmake)
+include(infra/cmake/BuildTelemetryConfig.cmake)
-if(BEMAN_ELIDE_BUILD_TESTS)
- # Fetch GoogleTest
- FetchContent_Declare(
- googletest
- GIT_REPOSITORY https://github.com/google/googletest.git
- GIT_TAG
- f8d7d77c06936315286eb55f8de22cd23c188571 # release-1.14.0
- EXCLUDE_FROM_ALL
- )
- set(INSTALL_GTEST OFF) # Disable GoogleTest installation
- FetchContent_MakeAvailable(googletest)
-endif()
+add_library(beman.elide INTERFACE)
+add_library(beman::elide ALIAS beman.elide)
+
+target_sources(
+ beman.elide
+ PUBLIC FILE_SET HEADERS BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include"
+)
+
+set_target_properties(
+ beman.elide
+ PROPERTIES VERIFY_INTERFACE_HEADER_SETS ${PROJECT_IS_TOP_LEVEL}
+)
+
+add_subdirectory(include/beman/elide)
-add_subdirectory(src/beman/elide)
+beman_install_library(beman.elide TARGETS beman.elide)
+configure_build_telemetry()
if(BEMAN_ELIDE_BUILD_TESTS)
+ enable_testing()
add_subdirectory(tests/beman/elide)
endif()
diff --git a/CMakePresets.json b/CMakePresets.json
index 8fbea46..483e1a3 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -7,7 +7,9 @@
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
- "CMAKE_CXX_STANDARD": "20"
+ "CMAKE_CXX_STANDARD": "20",
+ "CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
+ "CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "./infra/cmake/use-fetch-content.cmake"
}
},
{
@@ -33,7 +35,7 @@
"_debug-base"
],
"cacheVariables": {
- "CMAKE_TOOLCHAIN_FILE": "cmake/gnu-toolchain.cmake"
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/gnu-toolchain.cmake"
}
},
{
@@ -44,29 +46,51 @@
"_release-base"
],
"cacheVariables": {
- "CMAKE_TOOLCHAIN_FILE": "cmake/gnu-toolchain.cmake"
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/gnu-toolchain.cmake"
+ }
+ },
+ {
+ "name": "llvm-debug",
+ "displayName": "Clang Debug Build",
+ "inherits": [
+ "_root-config",
+ "_debug-base"
+ ],
+ "cacheVariables": {
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/llvm-toolchain.cmake"
+ }
+ },
+ {
+ "name": "llvm-release",
+ "displayName": "Clang Release Build",
+ "inherits": [
+ "_root-config",
+ "_release-base"
+ ],
+ "cacheVariables": {
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/llvm-toolchain.cmake"
}
},
{
"name": "appleclang-debug",
- "displayName": "xcode Debug Build",
+ "displayName": "Appleclang Debug Build",
"inherits": [
"_root-config",
"_debug-base"
],
"cacheVariables": {
- "CMAKE_TOOLCHAIN_FILE": "cmake/appleclang-toolchain.cmake"
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/appleclang-toolchain.cmake"
}
},
{
"name": "appleclang-release",
- "displayName": "xcode Release Build",
+ "displayName": "Appleclang Release Build",
"inherits": [
"_root-config",
"_release-base"
],
"cacheVariables": {
- "CMAKE_TOOLCHAIN_FILE": "cmake/appleclang-toolchain.cmake"
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/appleclang-toolchain.cmake"
}
},
{
@@ -77,7 +101,7 @@
"_debug-base"
],
"cacheVariables": {
- "CMAKE_TOOLCHAIN_FILE": "cmake/msvc-toolchain.cmake"
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/msvc-toolchain.cmake"
}
},
{
@@ -88,34 +112,71 @@
"_release-base"
],
"cacheVariables": {
- "CMAKE_TOOLCHAIN_FILE": "cmake/msvc-toolchain.cmake"
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/msvc-toolchain.cmake"
}
}
],
"buildPresets": [
+ {
+ "name": "_root-build",
+ "hidden": true,
+ "jobs": 0
+ },
{
"name": "gcc-debug",
- "configurePreset": "gcc-debug"
+ "configurePreset": "gcc-debug",
+ "inherits": [
+ "_root-build"
+ ]
},
{
"name": "gcc-release",
- "configurePreset": "gcc-release"
+ "configurePreset": "gcc-release",
+ "inherits": [
+ "_root-build"
+ ]
+ },
+ {
+ "name": "llvm-debug",
+ "configurePreset": "llvm-debug",
+ "inherits": [
+ "_root-build"
+ ]
+ },
+ {
+ "name": "llvm-release",
+ "configurePreset": "llvm-release",
+ "inherits": [
+ "_root-build"
+ ]
},
{
"name": "appleclang-debug",
- "configurePreset": "appleclang-debug"
+ "configurePreset": "appleclang-debug",
+ "inherits": [
+ "_root-build"
+ ]
},
{
"name": "appleclang-release",
- "configurePreset": "appleclang-release"
+ "configurePreset": "appleclang-release",
+ "inherits": [
+ "_root-build"
+ ]
},
{
"name": "msvc-debug",
- "configurePreset": "msvc-debug"
+ "configurePreset": "msvc-debug",
+ "inherits": [
+ "_root-build"
+ ]
},
{
"name": "msvc-release",
- "configurePreset": "msvc-release"
+ "configurePreset": "msvc-release",
+ "inherits": [
+ "_root-build"
+ ]
}
],
"testPresets": [
@@ -140,6 +201,16 @@
"inherits": "_test_base",
"configurePreset": "gcc-release"
},
+ {
+ "name": "llvm-debug",
+ "inherits": "_test_base",
+ "configurePreset": "llvm-debug"
+ },
+ {
+ "name": "llvm-release",
+ "inherits": "_test_base",
+ "configurePreset": "llvm-release"
+ },
{
"name": "appleclang-debug",
"inherits": "_test_base",
@@ -196,6 +267,40 @@
}
]
},
+ {
+ "name": "llvm-debug",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "llvm-debug"
+ },
+ {
+ "type": "build",
+ "name": "llvm-debug"
+ },
+ {
+ "type": "test",
+ "name": "llvm-debug"
+ }
+ ]
+ },
+ {
+ "name": "llvm-release",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "llvm-release"
+ },
+ {
+ "type": "build",
+ "name": "llvm-release"
+ },
+ {
+ "type": "test",
+ "name": "llvm-release"
+ }
+ ]
+ },
{
"name": "appleclang-debug",
"steps": [
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..921aef8
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,111 @@
+# Development
+
+## Configure and Build the Project Using CMake Presets
+
+The simplest way of configuring and building the project is to use [CMake
+Presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html). Appropriate
+presets for major compilers have been included by default. You can use `cmake
+--list-presets=workflow` to see all available presets.
+
+Here is an example of invoking the `gcc-debug` preset:
+
+```shell
+cmake --workflow --preset gcc-debug
+```
+
+Generally, there are two kinds of presets, `debug` and `release`.
+
+The `debug` presets are designed to aid development, so they have debuginfo and sanitizers
+enabled.
+
+> [!NOTE]
+>
+> The sanitizers that are enabled vary from compiler to compiler. See the toolchain files
+> under ([`infra/cmake`](infra/cmake/)) to determine the exact configuration used for each
+> preset.
+
+The `release` presets are designed for production use, and
+consequently have the highest optimization turned on (e.g. `O3`).
+
+## Configure and Build Manually
+
+If the presets are not suitable for your use case, a traditional CMake invocation will
+provide more configurability.
+
+To configure, build and test the project manually, you can run this set of commands. Note
+that this requires GoogleTest to be installed.
+
+```bash
+cmake \
+ -B build \
+ -S . \
+ -DCMAKE_CXX_STANDARD=20 \
+ # Your extra arguments here.
+cmake --build build
+ctest --test-dir build
+```
+
+> [!IMPORTANT]
+>
+> Beman projects are [passive projects](
+> https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#cmakepassive_projects),
+> so you need to specify the C++ version via `CMAKE_CXX_STANDARD` when manually
+> configuring the project.
+
+## Dependency Management
+
+### FetchContent
+
+Instead of installing the project's dependencies via a package manager, you can optionally
+configure beman.elide to fetch them automatically via CMake FetchContent.
+
+To do so, specify
+`-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./infra/cmake/use-fetch-content.cmake`. This will
+bring in GoogleTest automatically along with any other dependency the project may require.
+
+Example commands:
+
+```shell
+cmake \
+ -B build \
+ -S . \
+ -DCMAKE_CXX_STANDARD=20 \
+ -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./infra/cmake/use-fetch-content.cmake
+cmake --build build
+ctest --test-dir build
+```
+
+The file `./lockfile.json` configures the list of dependencies and versions that will be
+acquired by FetchContent.
+
+## Project-specific configure arguments
+
+Project-specific options are prefixed with `BEMAN_ELIDE`.
+You can see the list of available options with:
+
+```bash
+cmake -LH -S . -B build | grep "BEMAN_ELIDE" -C 2
+```
+
+
+
+Some project-specific configure arguments
+
+### `BEMAN_ELIDE_BUILD_TESTS`
+
+Enable building tests and test infrastructure. Default: `ON`.
+Values: `{ ON, OFF }`.
+
+### `BEMAN_ELIDE_BUILD_EXAMPLES`
+
+Enable building examples. Default: `ON`. Values: `{ ON, OFF }`.
+
+### `BEMAN_ELIDE_INSTALL_CONFIG_FILE_PACKAGE`
+
+Enable installing the CMake config file package. Default: `ON`.
+Values: `{ ON, OFF }`.
+
+This is required so that users of `beman.elide` can use
+`find_package(beman.elide)` to locate the library.
+
+
diff --git a/README.md b/README.md
index 0fd5b36..a97042d 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,20 @@
+# beman.elide: Implementation of Proposed `std::elide`
+
-# beman.elide: Implementation of Proposed `std::elide`
+
+   [](https://coveralls.io/github/bemanproject/elide?branch=main) 
**Implements**: `std::elide` proposed in [`std::elide` (P3288R3)](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3288r3.html).
**Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/beman_library_maturity_model.md#under-development-and-not-yet-ready-for-production-use)
+## License
+
+`beman.elide` is licensed under the Apache License v2.0 with LLVM Exceptions.
+
## Usage
`std::elide` is an object which:
@@ -18,79 +25,118 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
When combined with emplacement APIs this allows for the creation of instances of immovable types
within storage managed by `std::optional`, `std::list`, et cetera.
-## Building beman.elide
+## Dependencies
+
+### Build Environment
-### Dependencies
+This project requires at least the following to build:
-This project has no C or C++ dependencies,
-however,
-it requires **C++20** or above to compile.
+* A C++ compiler that conforms to the C++20 standard or greater
+* CMake 3.30 or later
+* (Test Only) GoogleTest
-Build-time dependencies:
+You can disable building tests by setting CMake option `BEMAN_ELIDE_BUILD_TESTS` to
+`OFF` when configuring the project.
+
+### Supported Platforms
+
+| Compiler | Version | C++ Standards | Standard Library |
+|------------|---------|---------------|-------------------|
+| GCC | 15-13 | C++26-C++20 | libstdc++ |
+| GCC | 12-11 | C++23, C++20 | libstdc++ |
+| Clang | 22-19 | C++26-C++20 | libstdc++, libc++ |
+| Clang | 18 | C++26-C++20 | libc++ |
+| Clang | 18 | C++23, C++20 | libstdc++ |
+| Clang | 17 | C++26-C++20 | libc++ |
+| Clang | 17 | C++20 | libstdc++ |
+| AppleClang | latest | C++26-C++20 | libc++ |
+| MSVC | latest | C++23 | MSVC STL |
+
+## Development
+
+See the [Contributing Guidelines](CONTRIBUTING.md).
+
+## Integrate beman.elide into your project
-- `cmake`
-- `ninja`, `make`, or another CMake-supported build system
- - CMake defaults to "Unix Makefiles" on POSIX systems
+### Build
-### How to build beman.elide
+You can build elide using a CMake workflow preset:
-```shell
-cmake --workflow --preset gcc-debug
+```bash
cmake --workflow --preset gcc-release
-cmake --install build/gcc-release --prefix /opt/beman.elide
```
-## Integrate beman.elide into your project
+To list available workflow presets, you can invoke:
-
- Use beman.elide directly from C++
-
+```bash
+cmake --list-presets=workflow
+```
-If you want to use `beman.elide` from your project,
-you can include `beman/elide/*.hpp` files from your C++ source files
+For details on building beman.elide without using a CMake preset, refer to the
+[Contributing Guidelines](CONTRIBUTING.md).
-```cpp
-#include
+### Installation
+
+To install beman.elide globally after building with the `gcc-release` preset, you can
+run:
+
+```bash
+sudo cmake --install build/gcc-release
```
-```shell
-# Assume /opt/beman.elide staging directory.
-$ c++ -o identity_usage examples/identity_usage.cpp \
- -I /opt/beman.elide/include/
+Alternatively, to install to a prefix, for example `/opt/beman`, you can run:
+
+```bash
+sudo cmake --install build/gcc-release --prefix /opt/beman
```
-
+This will generate the following directory structure:
+
+```txt
+/opt/beman
+├── include
+│ └── beman
+│ └── elide
+│ ├── elide.hpp
+│ └── ...
+└── lib
+ └── cmake
+ └── beman.elide
+ ├── beman.elide-config-version.cmake
+ ├── beman.elide-config.cmake
+ └── beman.elide-targets.cmake
+```
-
- Use beman.elide directly from CMake
+### CMake Configuration
-
+If you installed beman.elide to a prefix, you can specify that prefix to your CMake
+project using `CMAKE_PREFIX_PATH`; for example, `-DCMAKE_PREFIX_PATH=/opt/beman`.
-For CMake based projects, you will need to use the `beman.elide` CMake module to define the `beman::elide` CMake target:
+You need to bring in the `beman.elide` package to define the `beman::elide` CMake
+target:
```cmake
find_package(beman.elide REQUIRED)
```
-You will also need to add `beman::elide`
-to the link libraries of any libraries or executables that include `beman/elide/*.hpp` in their source or header file.
+You will then need to add `beman::elide` to the link libraries of any libraries or
+executables that include `beman.elide` headers.
```cmake
target_link_libraries(yourlib PUBLIC beman::elide)
```
-
-
-
- Use beman.elide from other build systems
-
-
+### Using beman.elide
-Build systems that support `pkg-config` by providing a `beman.elide.pc` file.
-Build systems that support interoperation via `pkg-config` should be able to detect `beman.elide` for you automatically.
+To use `beman.elide` in your C++ project,
+include an appropriate `beman.elide` header from your source code.
-
-
-## Contributing
+```c++
+#include
+```
-Issues and pull requests are appreciated.
+> [!NOTE]
+>
+> `beman.elide` headers are to be included with the `beman/elide/` prefix.
+> Altering include search paths to spell the include target another way (e.g.
+> `#include `) is unsupported.
diff --git a/include/beman/elide/CMakeLists.txt b/include/beman/elide/CMakeLists.txt
new file mode 100644
index 0000000..60f9bce
--- /dev/null
+++ b/include/beman/elide/CMakeLists.txt
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+target_sources(beman.elide PUBLIC FILE_SET HEADERS FILES elide.hpp deduce.hpp)
diff --git a/include/beman/elide/deduce.hpp b/include/beman/elide/deduce.hpp
index 51cc826..c25d5e0 100644
--- a/include/beman/elide/deduce.hpp
+++ b/include/beman/elide/deduce.hpp
@@ -10,23 +10,20 @@ namespace beman::elide {
namespace detail::deduce {
-template
+template
struct is_elide : std::false_type {};
-template
+template
struct is_elide> : std::true_type {};
-}
+} // namespace detail::deduce
-template
+template
struct deduce : std::remove_cvref {};
-template
- requires
- detail::deduce::is_elide<
- std::remove_cvref_t>::value &&
- std::is_invocable_v
+template
+ requires detail::deduce::is_elide>::value && std::is_invocable_v
struct deduce : std::invoke_result {};
-template
+template
using deduce_t = typename deduce::type;
} // namespace beman::elide
diff --git a/include/beman/elide/elide.hpp b/include/beman/elide/elide.hpp
index 753535e..b634ba2 100644
--- a/include/beman/elide/elide.hpp
+++ b/include/beman/elide/elide.hpp
@@ -13,88 +13,72 @@ namespace beman::elide {
namespace detail::elide {
-template
+template
concept result = !std::same_as;
-template
-concept c =
- std::invocable &&
- result> &&
- std::is_reference_v &&
- (std::is_reference_v && ...);
+template
+concept c = std::invocable && result> && std::is_reference_v &&
+ (std::is_reference_v && ...);
-template
-concept lvalue =
- std::invocable &&
- result>;
+template
+concept lvalue = std::invocable && result>;
struct tombstone {};
-template
+template
struct lvalue_result : std::type_identity {};
-template
- requires lvalue
+template
+ requires lvalue
struct lvalue_result : std::invoke_result {};
-}
+} // namespace detail::elide
-template
- requires detail::elide::c
+template
+ requires detail::elide::c
struct elide {
- elide() = delete;
- elide(const elide&) = delete;
- elide& operator=(const elide&) = delete;
- constexpr explicit elide(T t, Args... args) noexcept
- : t_(std::forward(t)),
- args_(std::forward(args)...)
- {}
-private:
- static constexpr bool rvalue_noexcept_ =
- std::is_nothrow_invocable_v;
- static constexpr bool lvalue_noexcept_ =
- std::is_nothrow_invocable_v;
- using rvalue_result_type_ = std::invoke_result_t;
- using lvalue_result_type_ = typename detail::elide::lvalue_result<
- T,
- Args...>::type;
-public:
- constexpr operator rvalue_result_type_() const&& noexcept(rvalue_noexcept_) {
- return std::apply(
- [&](auto&&... args) noexcept(rvalue_noexcept_) {
- return std::invoke(
- std::forward(t_),
- std::forward(args)...);
- },
- args_);
- }
- constexpr rvalue_result_type_ operator()() const&& noexcept(rvalue_noexcept_)
- {
- return rvalue_result_type_(std::move(*this));
- }
- constexpr operator lvalue_result_type_() const& noexcept(lvalue_noexcept_) {
- if constexpr (detail::elide::lvalue) {
- return std::apply(
- [&](auto&&... args) noexcept(lvalue_noexcept_) {
- return std::invoke(t_, args...);
- },
- args_);
- } else {
- return {};
+ elide() = delete;
+ elide(const elide&) = delete;
+ elide& operator=(const elide&) = delete;
+ constexpr explicit elide(T t, Args... args) noexcept
+ : t_(std::forward(t)), args_(std::forward(args)...) {}
+
+ private:
+ static constexpr bool rvalue_noexcept_ = std::is_nothrow_invocable_v;
+ static constexpr bool lvalue_noexcept_ = std::is_nothrow_invocable_v;
+ using rvalue_result_type_ = std::invoke_result_t;
+ using lvalue_result_type_ = typename detail::elide::lvalue_result::type;
+
+ public:
+ constexpr operator rvalue_result_type_() const&& noexcept(rvalue_noexcept_) {
+ return std::apply(
+ [&](auto&&... args) noexcept(rvalue_noexcept_) {
+ return std::invoke(std::forward(t_), std::forward(args)...);
+ },
+ args_);
+ }
+ constexpr rvalue_result_type_ operator()() const&& noexcept(rvalue_noexcept_) {
+ return rvalue_result_type_(std::move(*this));
}
- }
- constexpr lvalue_result_type_ operator()() const& noexcept(lvalue_noexcept_)
- requires detail::elide::lvalue
- {
- return rvalue_result_type_(*this);
- }
-private:
- [[no_unique_address]]
- T t_;
- [[no_unique_address]]
- std::tuple args_;
+ constexpr operator lvalue_result_type_() const& noexcept(lvalue_noexcept_) {
+ if constexpr (detail::elide::lvalue) {
+ return std::apply([&](auto&&... args) noexcept(lvalue_noexcept_) { return std::invoke(t_, args...); },
+ args_);
+ } else {
+ return {};
+ }
+ }
+ constexpr lvalue_result_type_ operator()() const& noexcept(lvalue_noexcept_)
+ requires detail::elide::lvalue
+ {
+ return rvalue_result_type_(*this);
+ }
+
+ private:
+ [[no_unique_address]] T t_;
+ [[no_unique_address]] std::tuple args_;
};
-template
+template
explicit elide(T&&, Args&&...) -> elide;
} // namespace beman::elide
diff --git a/infra/.beman_submodule b/infra/.beman_submodule
new file mode 100644
index 0000000..56dbbcc
--- /dev/null
+++ b/infra/.beman_submodule
@@ -0,0 +1,3 @@
+[beman_submodule]
+remote=https://github.com/bemanproject/infra.git
+commit_hash=ea3ef79f77fdcc378149ebc7406e81e9ceb04146
diff --git a/infra/.github/CODEOWNERS b/infra/.github/CODEOWNERS
new file mode 100644
index 0000000..4ff90a4
--- /dev/null
+++ b/infra/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @ednolan @neatudarius @rishyak @wusatosi @JeffGarland
diff --git a/.github/workflows/pre-commit.yml b/infra/.github/workflows/pre-commit.yml
similarity index 98%
rename from .github/workflows/pre-commit.yml
rename to infra/.github/workflows/pre-commit.yml
index f3c4332..9646831 100644
--- a/.github/workflows/pre-commit.yml
+++ b/infra/.github/workflows/pre-commit.yml
@@ -5,6 +5,8 @@ on:
# enough permission for reviewdog
pull_request_target:
push:
+ branches:
+ - main
jobs:
pre-commit-push:
diff --git a/infra/.github/workflows/reusable-beman-create-issue-when-fault.yml b/infra/.github/workflows/reusable-beman-create-issue-when-fault.yml
new file mode 100644
index 0000000..024a51f
--- /dev/null
+++ b/infra/.github/workflows/reusable-beman-create-issue-when-fault.yml
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+name: 'Beman issue creation workflow'
+on:
+ workflow_call:
+ workflow_dispatch:
+jobs:
+ create-issue:
+ runs-on: ubuntu-latest
+ steps:
+ # See https://github.com/cli/cli/issues/5075
+ - uses: actions/checkout@v4
+ - name: Create issue
+ run: |
+ issue_num=$(gh issue list -s open -S "[SCHEDULED-BUILD] infra repo CI job failure" -L 1 --json number | jq 'if length == 0 then -1 else .[0].number end')
+ body="**CI job failure Report**
+ - **Time of Failure**: $(date -u '+%B %d, %Y, %H:%M %Z')
+ - **Commit**: [${{ github.sha }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }})
+ - **Action Run**: [View logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
+ The scheduled job triggered by cron has failed.
+ Please investigate the logs and recent changes associated with this commit or rerun the workflow if you believe this is an error."
+ if [[ $issue_num -eq -1 ]]; then
+ gh issue create --repo ${{ github.repository }} --title "[SCHEDULED-BUILD] infra repo CI job failure" --body "$body" --assignee ${{ github.actor }}
+ else
+ gh issue comment --repo ${{ github.repository }} $issue_num --body "$body"
+ fi
+ env:
+ GH_TOKEN: ${{ github.token }}
diff --git a/infra/.gitignore b/infra/.gitignore
new file mode 100644
index 0000000..b7cdbb5
--- /dev/null
+++ b/infra/.gitignore
@@ -0,0 +1,59 @@
+# Prerequisites
+*.d
+
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+*.smod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app
+
+# Python
+__pycache__/
+.pytest_cache/
+*.pyc
+*.pyo
+*.pyd
+*.pyw
+*.pyz
+*.pywz
+*.pyzw
+*.pyzwz
+*.delete_me
+
+# MAC OS
+*.DS_Store
+
+# Editor files
+.vscode/
+.idea/
+
+# Build directories
+infra.egg-info/
+beman_tidy.egg-info/
+*.egg-info/
+build/
+dist/
diff --git a/infra/.pre-commit-config.yaml b/infra/.pre-commit-config.yaml
new file mode 100644
index 0000000..8052e18
--- /dev/null
+++ b/infra/.pre-commit-config.yaml
@@ -0,0 +1,21 @@
+repos:
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v6.0.0
+ hooks:
+ - id: trailing-whitespace
+ - id: end-of-file-fixer
+ - id: check-yaml
+ - id: check-added-large-files
+
+ - repo: https://github.com/codespell-project/codespell
+ rev: v2.4.2
+ hooks:
+ - id: codespell
+
+ # CMake linting and formatting
+ - repo: https://github.com/BlankSpruce/gersemi-pre-commit
+ rev: 0.27.2
+ hooks:
+ - id: gersemi
+ name: CMake linting
+ exclude: ^.*/tests/.*/data/ # Exclude test data directories
diff --git a/infra/LICENSE b/infra/LICENSE
new file mode 100644
index 0000000..f6db814
--- /dev/null
+++ b/infra/LICENSE
@@ -0,0 +1,219 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+---- LLVM Exceptions to the Apache 2.0 License ----
+
+As an exception, if, as a result of your compiling your source code, portions
+of this Software are embedded into an Object form of such source code, you
+may redistribute such embedded portions in such Object form without complying
+with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
+
+In addition, if you combine or link compiled forms of this Software with
+software that is licensed under the GPLv2 ("Combined Software") and if a
+court of competent jurisdiction determines that the patent provision (Section
+3), the indemnity provision (Section 9) or other Section of the License
+conflicts with the conditions of the GPLv2, you may retroactively and
+prospectively choose to deem waived or otherwise exclude such Section(s) of
+the License, but only in their entirety and only with respect to the Combined
+Software.
diff --git a/infra/README.md b/infra/README.md
new file mode 100644
index 0000000..bf9bbb0
--- /dev/null
+++ b/infra/README.md
@@ -0,0 +1,88 @@
+# Beman Project Infrastructure Repository
+
+
+
+This repository contains the infrastructure for The Beman Project. This is NOT a library repository,
+so it does not respect the usual structure of a Beman library repository nor The Beman Standard!
+
+## Description
+
+* `cmake/`: CMake modules and toolchain files used by Beman libraries.
+* `containers/`: Containers used for CI builds and tests in the Beman org.
+
+## Usage
+
+This repository is intended to be used as a beman-submodule in other Beman repositories. See
+[the beman-submodule documentation](https://github.com/bemanproject/beman-submodule) for details.
+
+
+### CMake Modules
+
+
+#### `beman_install_library`
+
+The CMake modules in this repository are intended to be used by Beman libraries. Use the
+`beman_add_install_library_config()` function to install your library, along with header
+files, any metadata files, and a CMake config file for `find_package()` support.
+
+```cmake
+add_library(beman.something)
+add_library(beman::something ALIAS beman.something)
+
+# ... configure your target as needed ...
+
+find_package(beman-install-library REQUIRED)
+beman_install_library(beman.something)
+```
+
+Note that the target must be created before calling `beman_install_library()`. The module
+also assumes that the target is named using the `beman.something` convention, and it
+uses that assumption to derive the names to match other Beman standards and conventions.
+If your target does not follow that convention, raise an issue or pull request to add
+more configurability to the module.
+
+The module will configure the target to install:
+
+* The library target itself
+* Any public headers associated with the target
+* CMake files for `find_package(beman.something)` support
+
+Some options for the project and target will also be supported:
+
+* `BEMAN_INSTALL_CONFIG_FILE_PACKAGES` - a list of package names (e.g., `beman.something`) for which to install the config file
+ (default: all packages)
+* `_INSTALL_CONFIG_FILE_PACKAGE` - a per-project option to enable/disable config file installation (default: `ON` if the project is top-level, `OFF` otherwise). For instance for `beman.something`, the option would be `BEMAN_SOMETHING_INSTALL_CONFIG_FILE_PACKAGE`.
+
+# BuildTelemetry
+
+The cmake modules in this library provide access to CMake instrumentation data in Google Trace format which is visualizable with chrome://tracing and https://ui.perfetto.dev.
+
+Telemetry may be enabled in several ways:
+
+## `include`
+
+```cmake
+include (infra/cmake/BuildTelemetry.cmake)
+configure_build_telemetry()
+```
+
+## `find_package`
+
+```cmake
+find_package(BuildTelemetry)
+configure_build_telemetry()
+```
+
+as long as [BuildTelemetryConfig.cmake](./cmake/BuildTelemetryConfig.cmake) is in your module path.
+
+## `CMAKE_PROJECT_TOP_LEVEL_INCLUDES`
+A non-invasive way to inject this telemetry into a CMake build you do not want to modify.
+Add:
+```sh
+-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=infra/cmake/BuildTelemetry.cmake
+```
+To the cmake invocation.
+
+In any form, CMake will call `telemetry.sh` which will copy the trace data in json format into a `.trace` subdirectory within the build directory.
+
+Multiple calls to `configure_build_telemetry` will only configure the callback hooks once, so it is safe to enable multiple times, including by TOP_LEVEL_INCLUDE.
diff --git a/infra/cmake/BuildTelemetry.cmake b/infra/cmake/BuildTelemetry.cmake
new file mode 100755
index 0000000..c2ff343
--- /dev/null
+++ b/infra/cmake/BuildTelemetry.cmake
@@ -0,0 +1,4 @@
+include_guard(GLOBAL)
+
+include(${CMAKE_CURRENT_LIST_DIR}/BuildTelemetryConfig.cmake)
+configure_build_telemetry()
diff --git a/infra/cmake/BuildTelemetryConfig.cmake b/infra/cmake/BuildTelemetryConfig.cmake
new file mode 100755
index 0000000..15aae48
--- /dev/null
+++ b/infra/cmake/BuildTelemetryConfig.cmake
@@ -0,0 +1,58 @@
+include_guard(GLOBAL)
+
+set(BUILD_TELEMETRY_DIR ${CMAKE_CURRENT_LIST_DIR})
+
+function(configure_build_telemetry)
+ if(NOT BUILD_TELEMETRY_CONFIGURATION)
+ # Check if the CMake version is at least 4.3
+ if(CMAKE_VERSION VERSION_LESS "4.3")
+ message(
+ STATUS
+ "CMake version is less than 4.3, configuring cmake_instrumentation is unavailable."
+ )
+ return()
+ else()
+ message(STATUS "Configuring Build Telemetry")
+ endif()
+
+ # Find bash and jq for the telemetry callback script.
+ # On Windows, Git for Windows provides bash if available.
+ find_program(BEMAN_BASH bash)
+ find_program(BEMAN_JQ jq)
+ if(NOT BEMAN_BASH OR NOT BEMAN_JQ)
+ message(
+ STATUS
+ "bash or jq not found, build telemetry disabled on this platform."
+ )
+ return()
+ endif()
+
+ # Telemetry query
+ cmake_instrumentation(
+ API_VERSION 1
+ DATA_VERSION 1
+ OPTIONS staticSystemInformation dynamicSystemInformation trace
+ HOOKS
+ postGenerate
+ preBuild
+ postBuild
+ preCMakeBuild
+ postCMakeBuild
+ postCMakeInstall
+ postCTest
+ CALLBACK ${BEMAN_BASH}
+ ${BUILD_TELEMETRY_DIR}/telemetry.sh
+ )
+ message(
+ DEBUG
+ "using callback script ${BUILD_TELEMETRY_DIR}/telemetry.sh via ${BEMAN_BASH}"
+ )
+
+ # Mark configuration as done in cache
+ set(BUILD_TELEMETRY_CONFIGURATION
+ TRUE
+ CACHE INTERNAL
+ "Flag to ensure Build Telemetry configured only once"
+ )
+ endif()
+endfunction(configure_build_telemetry)
diff --git a/infra/cmake/Config.cmake.in b/infra/cmake/Config.cmake.in
new file mode 100644
index 0000000..3f1341c
--- /dev/null
+++ b/infra/cmake/Config.cmake.in
@@ -0,0 +1,12 @@
+# cmake/Config.cmake.in -*-makefile-*-
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+include(CMakeFindDependencyMacro)
+
+@BEMAN_INSTALL_FIND_DEPENDENCIES@
+
+@PACKAGE_INIT@
+
+include(${CMAKE_CURRENT_LIST_DIR}/@BEMAN_INSTALL_BASE_PKG_NAME@-targets.cmake)
+
+check_required_components(@BEMAN_INSTALL_BASE_PKG_NAME@)
diff --git a/cmake/appleclang-toolchain.cmake b/infra/cmake/appleclang-toolchain.cmake
similarity index 82%
rename from cmake/appleclang-toolchain.cmake
rename to infra/cmake/appleclang-toolchain.cmake
index bc12103..70ef548 100644
--- a/cmake/appleclang-toolchain.cmake
+++ b/infra/cmake/appleclang-toolchain.cmake
@@ -16,8 +16,10 @@
include_guard(GLOBAL)
-set(CMAKE_C_COMPILER clang)
-set(CMAKE_CXX_COMPILER clang++)
+# Prevent PATH collision with an LLVM clang installation by using the system
+# compiler shims
+set(CMAKE_C_COMPILER cc)
+set(CMAKE_CXX_COMPILER c++)
if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan")
set(SANITIZER_FLAGS
@@ -37,3 +39,6 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
+
+# Add this dir to the module path so that `find_package(beman-install-library)` works
+list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}")
diff --git a/infra/cmake/beman-install-library.cmake b/infra/cmake/beman-install-library.cmake
new file mode 100644
index 0000000..dc5a4d1
--- /dev/null
+++ b/infra/cmake/beman-install-library.cmake
@@ -0,0 +1,323 @@
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+include_guard(GLOBAL)
+
+include(CMakePackageConfigHelpers)
+include(GNUInstallDirs)
+
+# beman_install_library
+# =====================
+#
+# Installs a library (or set of targets) along with headers, C++ modules,
+# and optional CMake package configuration files.
+#
+# Usage:
+# ------
+# beman_install_library(
+# TARGETS [ ...]
+# [DEPENDENCIES [ ...]]
+# [NAMESPACE ]
+# [EXPORT_NAME ]
+# [DESTINATION ]
+# )
+#
+# Arguments:
+# ----------
+#
+# name
+# Logical package name (e.g. "beman.utility").
+# Used to derive config file names and cache variable prefixes.
+#
+# TARGETS (required)
+# List of CMake targets to install.
+#
+# DEPENDENCIES (optional)
+# Semicolon-separated list, one dependency per entry.
+# Each entry is a valid find_dependency() argument list.
+# Note: you must use the bracket form for quoting if not only a package name is used!
+# "[===[beman.inplace_vector 1.0.0]===] [===[beman.scope 0.0.1 EXACT]===] fmt"
+#
+# NAMESPACE (optional)
+# Namespace for exported targets.
+# Defaults to "beman::".
+#
+# EXPORT_NAME (optional)
+# Name of the CMake export set.
+# Defaults to "-targets".
+#
+# DESTINATION (optional)
+# The install destination for CXX_MODULES.
+# Defaults to ${CMAKE_INSTALL_LIBDIR}/cmake/${name}/modules.
+#
+# Brief
+# -----
+#
+# This function installs the specified project TARGETS and its FILE_SET
+# HEADERS to the default CMAKE install destination.
+#
+# It also handles the installation of the CMake config package files if
+# needed. If the given targets has a PUBLIC FILE_SET CXX_MODULE, it will also
+# installed to the given DESTINATION
+#
+# Cache variables:
+# ----------------
+#
+# BEMAN_INSTALL_CONFIG_FILE_PACKAGES
+# List of package names for which config files should be installed.
+#
+# _INSTALL_CONFIG_FILE_PACKAGE
+# Per-package override to enable/disable config file installation.
+# is the uppercased package name with dots replaced by underscores.
+#
+# Caveats
+# -------
+#
+# **Only one `PUBLIC FILE_SET CXX_MODULES` is yet supported to install with this
+# function!**
+#
+# **Only header files contained in a `PUBLIC FILE_SET TYPE HEADERS` will be
+# install with this function!**
+
+function(beman_install_library name)
+ # ----------------------------
+ # Argument parsing
+ # ----------------------------
+ set(oneValueArgs NAMESPACE EXPORT_NAME DESTINATION)
+ set(multiValueArgs TARGETS DEPENDENCIES)
+
+ cmake_parse_arguments(
+ BEMAN_INSTALL
+ "${options}"
+ "${oneValueArgs}"
+ "${multiValueArgs}"
+ ${ARGN}
+ )
+
+ if(NOT BEMAN_INSTALL_TARGETS)
+ message(
+ FATAL_ERROR
+ "beman_install_library(${name}): TARGETS must be specified"
+ )
+ endif()
+
+ if(CMAKE_SKIP_INSTALL_RULES)
+ message(
+ WARNING
+ "beman_install_library(${name}): not installing targets '${BEMAN_INSTALL_TARGETS}' due to CMAKE_SKIP_INSTALL_RULES"
+ )
+ return()
+ endif()
+
+ set(_config_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${name}")
+
+ # ----------------------------
+ # Defaults
+ # ----------------------------
+ if(NOT BEMAN_INSTALL_NAMESPACE)
+ set(BEMAN_INSTALL_NAMESPACE "beman::")
+ endif()
+
+ if(NOT BEMAN_INSTALL_EXPORT_NAME)
+ set(BEMAN_INSTALL_EXPORT_NAME "${name}-targets")
+ endif()
+
+ if(NOT BEMAN_INSTALL_DESTINATION)
+ set(BEMAN_INSTALL_DESTINATION "${_config_install_dir}/modules")
+ endif()
+
+ string(REPLACE "beman." "" install_component_name "${name}")
+ message(
+ VERBOSE
+ "beman-install-library(${name}): COMPONENT '${install_component_name}'"
+ )
+
+ # --------------------------------------------------
+ # Install each target with all of its file sets
+ # --------------------------------------------------
+ foreach(_tgt IN LISTS BEMAN_INSTALL_TARGETS)
+ if(NOT TARGET "${_tgt}")
+ message(
+ WARNING
+ "beman_install_library(${name}): '${_tgt}' is not a target"
+ )
+ continue()
+ endif()
+
+ # Given foo.bar, the component name is bar
+ string(REPLACE "." ";" name_parts "${_tgt}")
+ # fail if the name doesn't look like foo.bar
+ list(LENGTH name_parts name_parts_length)
+ if(NOT name_parts_length EQUAL 2)
+ message(
+ FATAL_ERROR
+ "beman_install_library(${name}): expects a name of the form 'beman.', got '${_tgt}'"
+ )
+ endif()
+ list(GET name_parts -1 component_name)
+ set_target_properties(
+ "${_tgt}"
+ PROPERTIES EXPORT_NAME "${component_name}"
+ )
+ message(
+ VERBOSE
+ "beman_install_library(${name}): EXPORT_NAME ${component_name} for TARGET '${_tgt}'"
+ )
+
+ # Get the list of interface header sets, exact one expected!
+ set(_install_header_set_args)
+ get_target_property(
+ _available_header_sets
+ ${_tgt}
+ INTERFACE_HEADER_SETS
+ )
+ if(_available_header_sets)
+ message(
+ VERBOSE
+ "beman-install-library(${name}): '${_tgt}' has INTERFACE_HEADER_SETS=${_available_header_sets}"
+ )
+ foreach(_install_header_set IN LISTS _available_header_sets)
+ list(
+ APPEND _install_header_set_args
+ FILE_SET
+ "${_install_header_set}"
+ COMPONENT
+ "${install_component_name}_Development"
+ )
+ endforeach()
+ else()
+ set(_install_header_set_args FILE_SET HEADERS) # Note: empty FILE_SET in this case! CK
+ endif()
+
+ # Detect presence of PUBLIC C++ module file sets. Note: exact one is expected!
+ get_target_property(_module_sets "${_tgt}" INTERFACE_CXX_MODULE_SETS)
+ if(_module_sets)
+ message(
+ VERBOSE
+ "beman-install-library(${name}): '${_tgt}' has INTERFACE_CXX_MODULE_SETS=${_module_sets}"
+ )
+ install(
+ TARGETS "${_tgt}"
+ EXPORT ${BEMAN_INSTALL_EXPORT_NAME}
+ ARCHIVE COMPONENT "${install_component_name}_Development"
+ LIBRARY
+ COMPONENT "${install_component_name}_Runtime"
+ NAMELINK_COMPONENT "${install_component_name}_Development"
+ RUNTIME COMPONENT "${install_component_name}_Runtime"
+ ${_install_header_set_args}
+ FILE_SET ${_module_sets}
+ DESTINATION "${BEMAN_INSTALL_DESTINATION}"
+ COMPONENT "${install_component_name}_Development"
+ # NOTE: There's currently no convention for this location! CK
+ CXX_MODULES_BMI
+ DESTINATION
+ ${_config_install_dir}/bmi-${CMAKE_CXX_COMPILER_ID}_$
+ COMPONENT "${install_component_name}_Development"
+ )
+ else()
+ install(
+ TARGETS "${_tgt}"
+ EXPORT ${BEMAN_INSTALL_EXPORT_NAME}
+ ARCHIVE COMPONENT "${install_component_name}_Development"
+ LIBRARY
+ COMPONENT "${install_component_name}_Runtime"
+ NAMELINK_COMPONENT "${install_component_name}_Development"
+ RUNTIME COMPONENT "${install_component_name}_Runtime"
+ ${_install_header_set_args}
+ )
+ endif()
+ endforeach()
+
+ # --------------------------------------------------
+ # Export targets
+ # --------------------------------------------------
+ # gersemi: off
+ install(
+ EXPORT ${BEMAN_INSTALL_EXPORT_NAME}
+ NAMESPACE ${BEMAN_INSTALL_NAMESPACE}
+ CXX_MODULES_DIRECTORY cxx-modules
+ DESTINATION ${_config_install_dir}
+ COMPONENT "${install_component_name}_Development"
+ )
+ # gersemi: on
+
+ # ----------------------------------------
+ # Config file installation logic
+ #
+ # Precedence (highest to lowest):
+ # 1. Per-package variable _INSTALL_CONFIG_FILE_PACKAGE
+ # 2. Allow-list BEMAN_INSTALL_CONFIG_FILE_PACKAGES (if defined)
+ # 3. Default: ON
+ # ----------------------------------------
+ string(TOUPPER "${name}" _pkg_upper)
+ string(REPLACE "." "_" _pkg_prefix "${_pkg_upper}")
+
+ option(
+ ${_pkg_prefix}_INSTALL_CONFIG_FILE_PACKAGE
+ "Enable creating and installing a CMake config-file package. Default: ON. Values: { ON, OFF }."
+ ON
+ )
+
+ set(_pkg_var "${_pkg_prefix}_INSTALL_CONFIG_FILE_PACKAGE")
+
+ # Default: install config files
+ set(_install_config ON)
+
+ # If the allow-list is defined, only install for packages in the list
+ if(DEFINED BEMAN_INSTALL_CONFIG_FILE_PACKAGES)
+ if(NOT "${name}" IN_LIST BEMAN_INSTALL_CONFIG_FILE_PACKAGES)
+ set(_install_config OFF)
+ endif()
+ endif()
+
+ # Per-package override takes highest precedence
+ if(DEFINED ${_pkg_var})
+ set(_install_config ${${_pkg_var}})
+ endif()
+
+ # ----------------------------------------
+ # expand dependencies
+ # ----------------------------------------
+ set(_beman_find_deps "")
+ foreach(dep IN LISTS BEMAN_INSTALL_DEPENDENCIES)
+ message(
+ VERBOSE
+ "beman-install-library(${name}): Add find_dependency(${dep})"
+ )
+ string(APPEND _beman_find_deps "find_dependency(${dep})\n")
+ endforeach()
+ set(BEMAN_INSTALL_FIND_DEPENDENCIES "${_beman_find_deps}")
+
+ # ----------------------------------------
+ # Generate + install config files
+ # ----------------------------------------
+ if(_install_config)
+ set(BEMAN_INSTALL_BASE_PKG_NAME ${name})
+ configure_package_config_file(
+ "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Config.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/${name}-config.cmake"
+ INSTALL_DESTINATION ${_config_install_dir}
+ )
+
+ write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/${name}-config-version.cmake"
+ VERSION ${PROJECT_VERSION}
+ COMPATIBILITY SameMajorVersion
+ )
+
+ install(
+ FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/${name}-config.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/${name}-config-version.cmake"
+ DESTINATION ${_config_install_dir}
+ COMPONENT "${install_component_name}_Development"
+ )
+ else()
+ message(
+ WARNING
+ "beman-install-library(${name}): Not installing a config package for '${name}'"
+ )
+ endif()
+endfunction()
+
+set(CPACK_GENERATOR TGZ)
+include(CPack)
diff --git a/cmake/gnu-toolchain.cmake b/infra/cmake/gnu-toolchain.cmake
similarity index 83%
rename from cmake/gnu-toolchain.cmake
rename to infra/cmake/gnu-toolchain.cmake
index 2e2a2ad..d3b9f92 100644
--- a/cmake/gnu-toolchain.cmake
+++ b/infra/cmake/gnu-toolchain.cmake
@@ -20,7 +20,7 @@ set(CMAKE_CXX_COMPILER g++)
if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan")
set(SANITIZER_FLAGS
- "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined"
+ "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined -fsanitize-undefined-trap-on-error"
)
elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan")
set(SANITIZER_FLAGS "-fsanitize=thread")
@@ -36,3 +36,6 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
+
+# Add this dir to the module path so that `find_package(beman-install-library)` works
+list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}")
diff --git a/infra/cmake/llvm-libc++-toolchain.cmake b/infra/cmake/llvm-libc++-toolchain.cmake
new file mode 100644
index 0000000..76264c6
--- /dev/null
+++ b/infra/cmake/llvm-libc++-toolchain.cmake
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: BSL-1.0
+
+# This toolchain file is not meant to be used directly,
+# but to be invoked by CMake preset and GitHub CI.
+#
+# This toolchain file configures for LLVM family of compiler.
+#
+# BEMAN_BUILDSYS_SANITIZER:
+# This optional CMake parameter is not meant for public use and is subject to
+# change.
+# Possible values:
+# - MaxSan: configures clang and clang++ to use all available non-conflicting
+# sanitizers.
+# - TSan: configures clang and clang++ to enable the use of thread sanitizer.
+
+include(${CMAKE_CURRENT_LIST_DIR}/llvm-toolchain.cmake)
+
+if(NOT CMAKE_CXX_FLAGS MATCHES "-stdlib=libc\\+\\+")
+ string(APPEND CMAKE_CXX_FLAGS " -stdlib=libc++")
+endif()
diff --git a/cmake/llvm-toolchain.cmake b/infra/cmake/llvm-toolchain.cmake
similarity index 84%
rename from cmake/llvm-toolchain.cmake
rename to infra/cmake/llvm-toolchain.cmake
index d783803..f1623b7 100644
--- a/cmake/llvm-toolchain.cmake
+++ b/infra/cmake/llvm-toolchain.cmake
@@ -20,7 +20,7 @@ set(CMAKE_CXX_COMPILER clang++)
if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan")
set(SANITIZER_FLAGS
- "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined"
+ "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined -fsanitize-undefined-trap-on-error"
)
elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan")
set(SANITIZER_FLAGS "-fsanitize=thread")
@@ -36,3 +36,6 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
+
+# Add this dir to the module path so that `find_package(beman-install-library)` works
+list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}")
diff --git a/cmake/msvc-toolchain.cmake b/infra/cmake/msvc-toolchain.cmake
similarity index 90%
rename from cmake/msvc-toolchain.cmake
rename to infra/cmake/msvc-toolchain.cmake
index c2fffa7..bdc24de 100644
--- a/cmake/msvc-toolchain.cmake
+++ b/infra/cmake/msvc-toolchain.cmake
@@ -36,3 +36,6 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
+
+# Add this dir to the module path so that `find_package(beman-install-library)` works
+list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}")
diff --git a/infra/cmake/telemetry.sh b/infra/cmake/telemetry.sh
new file mode 100755
index 0000000..307cc94
--- /dev/null
+++ b/infra/cmake/telemetry.sh
@@ -0,0 +1,118 @@
+#!/usr/bin/env bash
+
+set -o nounset
+set -o errexit
+trap 'echo "Aborting due to errexit on line $LINENO. Exit code: $?" >&2' ERR
+set -o errtrace
+set -o pipefail
+IFS=$'\n\t'
+
+###############################################################################
+# Environment
+###############################################################################
+
+# $_ME
+#
+# This program's basename.
+_ME="$(basename "${0}")"
+
+###############################################################################
+# Help
+###############################################################################
+
+# _print_help()
+#
+# Usage:
+# _print_help
+#
+# Print the program help information.
+_print_help() {
+ cat <]
+ ${_ME} -h | --help
+
+Options:
+ -h --help Show this screen.
+
+Environment:
+ Setting DEBUG_TELEMETRY in the environment will enable DEBUG logging
+HEREDOC
+}
+
+###############################################################################
+# Program Functions
+###############################################################################
+_debug_print() {
+ if [[ -n "${DEBUG_TELEMETRY:-}" ]]; then
+ printf "[DEBUG] $(date +'%H:%M:%S'): %s \n" "$1" >&2
+ fi
+}
+
+_check_file_exists() {
+ local file="$1"
+ if [[ ! -f "${file}" ]]; then
+ echo "Error: File not found: ${file}" >&2
+ exit 1 # Exit the entire script with a non-zero status
+ fi
+}
+
+_process_index() {
+ indexFile=${1:-}
+ _check_file_exists "${indexFile}"
+ _debug_print "$(cat "${indexFile}")"
+
+ local buildDir
+ buildDir=$(jq -r '.buildDir' "${1:-}")
+ _debug_print "$(printf "buildDir is |%q|" "${buildDir}")"
+
+ local dataDir
+ dataDir=$(jq -r '.dataDir' "${1:-}")
+ _debug_print "$(printf "dataDir is |%q|" "${dataDir}")"
+
+ local hook
+ hook=$(jq -r '.hook' "${1:-}")
+ _debug_print "$(printf "hook is |%q|" "${hook}")"
+
+ local trace
+ trace=$(jq -r '.trace' "${1:-}")
+ _debug_print "$(printf "trace is |%q|" "${trace}")"
+
+ local outputDir
+ outputDir="${buildDir}/.trace"
+ _debug_print "$(printf "Copy trace to |%q|" "${outputDir}")"
+ mkdir -p "${outputDir}"
+
+ local traceDestFile
+ traceDestFile="${outputDir}/${hook}-$(basename "${trace}")"
+ _debug_print "$(printf "traceDestFile: |%q|" "${traceDestFile}")"
+ cp "${dataDir}/${trace}" "${outputDir}/${hook}-$(basename "${trace}")"
+}
+
+###############################################################################
+# Main
+###############################################################################
+
+# _main()
+#
+# Usage:
+# _main [] []
+#
+# Description:
+# Entry point for the program, handling basic option parsing and dispatching.
+_main() {
+ # Avoid complex option parsing when only one program option is expected.
+ if [[ "${1:-}" =~ ^-h|--help$ ]]
+ then
+ _print_help
+ else
+ _process_index "$@"
+ fi
+}
+
+# Call `_main` after everything has been defined.
+_main "$@"
diff --git a/infra/cmake/use-fetch-content.cmake b/infra/cmake/use-fetch-content.cmake
new file mode 100644
index 0000000..0564513
--- /dev/null
+++ b/infra/cmake/use-fetch-content.cmake
@@ -0,0 +1,231 @@
+cmake_minimum_required(VERSION 3.24)
+
+include(FetchContent)
+
+if(NOT BEMAN_EXEMPLAR_LOCKFILE)
+ set(BEMAN_EXEMPLAR_LOCKFILE
+ "lockfile.json"
+ CACHE FILEPATH
+ "Path to the dependency lockfile for the Beman Exemplar."
+ )
+endif()
+
+set(BemanExemplar_projectDir "${CMAKE_CURRENT_LIST_DIR}/../..")
+message(TRACE "BemanExemplar_projectDir=\"${BemanExemplar_projectDir}\"")
+
+message(TRACE "BEMAN_EXEMPLAR_LOCKFILE=\"${BEMAN_EXEMPLAR_LOCKFILE}\"")
+file(
+ REAL_PATH "${BEMAN_EXEMPLAR_LOCKFILE}"
+ BemanExemplar_lockfile
+ BASE_DIRECTORY "${BemanExemplar_projectDir}"
+ EXPAND_TILDE
+)
+message(DEBUG "Using lockfile: \"${BemanExemplar_lockfile}\"")
+
+# Force CMake to reconfigure the project if the lockfile changes
+set_property(
+ DIRECTORY "${BemanExemplar_projectDir}"
+ APPEND
+ PROPERTY CMAKE_CONFIGURE_DEPENDS "${BemanExemplar_lockfile}"
+)
+
+# For more on the protocol for this function, see:
+# https://cmake.org/cmake/help/latest/command/cmake_language.html#provider-commands
+function(BemanExemplar_provideDependency method package_name)
+ # Read the lockfile
+ file(READ "${BemanExemplar_lockfile}" BemanExemplar_rootObj)
+
+ # Get the "dependencies" field and store it in BemanExemplar_dependenciesObj
+ string(
+ JSON BemanExemplar_dependenciesObj
+ ERROR_VARIABLE BemanExemplar_error
+ GET "${BemanExemplar_rootObj}"
+ "dependencies"
+ )
+ if(BemanExemplar_error)
+ message(FATAL_ERROR "${BemanExemplar_lockfile}: ${BemanExemplar_error}")
+ endif()
+
+ # Get the length of the libraries array and store it in BemanExemplar_dependenciesObj
+ string(
+ JSON BemanExemplar_numDependencies
+ ERROR_VARIABLE BemanExemplar_error
+ LENGTH "${BemanExemplar_dependenciesObj}"
+ )
+ if(BemanExemplar_error)
+ message(FATAL_ERROR "${BemanExemplar_lockfile}: ${BemanExemplar_error}")
+ endif()
+
+ if(BemanExemplar_numDependencies EQUAL 0)
+ return()
+ endif()
+
+ # Loop over each dependency object
+ math(EXPR BemanExemplar_maxIndex "${BemanExemplar_numDependencies} - 1")
+ foreach(BemanExemplar_index RANGE "${BemanExemplar_maxIndex}")
+ set(BemanExemplar_errorPrefix
+ "${BemanExemplar_lockfile}, dependency ${BemanExemplar_index}"
+ )
+
+ # Get the dependency object at BemanExemplar_index
+ # and store it in BemanExemplar_depObj
+ string(
+ JSON BemanExemplar_depObj
+ ERROR_VARIABLE BemanExemplar_error
+ GET "${BemanExemplar_dependenciesObj}"
+ "${BemanExemplar_index}"
+ )
+ if(BemanExemplar_error)
+ message(
+ FATAL_ERROR
+ "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}"
+ )
+ endif()
+
+ # Get the "name" field and store it in BemanExemplar_name
+ string(
+ JSON BemanExemplar_name
+ ERROR_VARIABLE BemanExemplar_error
+ GET "${BemanExemplar_depObj}"
+ "name"
+ )
+ if(BemanExemplar_error)
+ message(
+ FATAL_ERROR
+ "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}"
+ )
+ endif()
+
+ # Get the "package_name" field and store it in BemanExemplar_pkgName
+ string(
+ JSON BemanExemplar_pkgName
+ ERROR_VARIABLE BemanExemplar_error
+ GET "${BemanExemplar_depObj}"
+ "package_name"
+ )
+ if(BemanExemplar_error)
+ message(
+ FATAL_ERROR
+ "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}"
+ )
+ endif()
+
+ # Get the "git_repository" field and store it in BemanExemplar_repo
+ string(
+ JSON BemanExemplar_repo
+ ERROR_VARIABLE BemanExemplar_error
+ GET "${BemanExemplar_depObj}"
+ "git_repository"
+ )
+ if(BemanExemplar_error)
+ message(
+ FATAL_ERROR
+ "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}"
+ )
+ endif()
+
+ # Get the "git_tag" field and store it in BemanExemplar_tag
+ string(
+ JSON BemanExemplar_tag
+ ERROR_VARIABLE BemanExemplar_error
+ GET "${BemanExemplar_depObj}"
+ "git_tag"
+ )
+ if(BemanExemplar_error)
+ message(
+ FATAL_ERROR
+ "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}"
+ )
+ endif()
+
+ if(method STREQUAL "FIND_PACKAGE")
+ if(package_name STREQUAL BemanExemplar_pkgName)
+ string(
+ APPEND BemanExemplar_debug
+ "Redirecting find_package calls for ${BemanExemplar_pkgName} "
+ "to FetchContent logic.\n"
+ )
+ string(
+ APPEND BemanExemplar_debug
+ "Fetching ${BemanExemplar_repo} at "
+ "${BemanExemplar_tag} according to ${BemanExemplar_lockfile}."
+ )
+ message(DEBUG "${BemanExemplar_debug}")
+ FetchContent_Declare(
+ "${BemanExemplar_name}"
+ GIT_REPOSITORY "${BemanExemplar_repo}"
+ GIT_TAG "${BemanExemplar_tag}"
+ EXCLUDE_FROM_ALL
+ )
+
+ # Apply per-dependency cmake_args from the lockfile
+ string(
+ JSON BemanExemplar_cmakeArgs
+ ERROR_VARIABLE BemanExemplar_cmakeArgsError
+ GET "${BemanExemplar_depObj}"
+ "cmake_args"
+ )
+ if(NOT BemanExemplar_cmakeArgsError)
+ string(
+ JSON BemanExemplar_numCmakeArgs
+ LENGTH "${BemanExemplar_cmakeArgs}"
+ )
+ if(BemanExemplar_numCmakeArgs GREATER 0)
+ math(
+ EXPR
+ BemanExemplar_maxArgIndex
+ "${BemanExemplar_numCmakeArgs} - 1"
+ )
+ foreach(
+ BemanExemplar_argIndex
+ RANGE "${BemanExemplar_maxArgIndex}"
+ )
+ string(
+ JSON BemanExemplar_argKey
+ MEMBER "${BemanExemplar_cmakeArgs}"
+ "${BemanExemplar_argIndex}"
+ )
+ string(
+ JSON BemanExemplar_argValue
+ GET "${BemanExemplar_cmakeArgs}"
+ "${BemanExemplar_argKey}"
+ )
+ message(
+ DEBUG
+ "Setting ${BemanExemplar_argKey}=${BemanExemplar_argValue} for ${BemanExemplar_name}"
+ )
+ set("${BemanExemplar_argKey}"
+ "${BemanExemplar_argValue}"
+ )
+ endforeach()
+ endif()
+ endif()
+
+ FetchContent_MakeAvailable("${BemanExemplar_name}")
+
+ # Catch2's CTest integration module isn't on CMAKE_MODULE_PATH
+ # when brought in via FetchContent. Add it so that
+ # `include(Catch)` works.
+ if(BemanExemplar_pkgName STREQUAL "Catch2")
+ list(
+ APPEND CMAKE_MODULE_PATH
+ "${${BemanExemplar_name}_SOURCE_DIR}/extras"
+ )
+ set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" PARENT_SCOPE)
+ endif()
+
+ # Important! _FOUND tells CMake that `find_package` is
+ # not needed for this package anymore
+ set("${BemanExemplar_pkgName}_FOUND" TRUE PARENT_SCOPE)
+ endif()
+ endif()
+ endforeach()
+endfunction()
+
+cmake_language(
+ SET_DEPENDENCY_PROVIDER BemanExemplar_provideDependency
+ SUPPORTED_METHODS FIND_PACKAGE
+)
+
+# Add this dir to the module path so that `find_package(beman-install-library)` works
+list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}")
diff --git a/lockfile.json b/lockfile.json
new file mode 100644
index 0000000..787b905
--- /dev/null
+++ b/lockfile.json
@@ -0,0 +1,13 @@
+{
+ "dependencies": [
+ {
+ "name": "googletest",
+ "package_name": "GTest",
+ "git_repository": "https://github.com/google/googletest.git",
+ "git_tag": "6910c9d9165801d8827d628cb72eb7ea9dd538c5",
+ "cmake_args": {
+ "INSTALL_GTEST": "OFF"
+ }
+ }
+ ]
+}
diff --git a/src/beman/elide/CMakeLists.txt b/src/beman/elide/CMakeLists.txt
deleted file mode 100644
index be895a9..0000000
--- a/src/beman/elide/CMakeLists.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-add_library(beman.elide INTERFACE)
-add_library(beman::elide ALIAS beman.elide)
-
-target_sources(
- beman.elide
- PUBLIC
- FILE_SET HEADERS
- BASE_DIRS ${PROJECT_SOURCE_DIR}/include
- FILES
- ${PROJECT_SOURCE_DIR}/include/beman/elide/deduce.hpp
- ${PROJECT_SOURCE_DIR}/include/beman/elide/elide.hpp
-)
-
-set_target_properties(beman.elide PROPERTIES VERIFY_INTERFACE_HEADER_SETS ON)
-
-install(
- TARGETS beman.elide
- EXPORT beman.elide
- DESTINATION
- $<$:debug/>${CMAKE_INSTALL_LIBDIR}
- RUNTIME DESTINATION $<$:debug/>${CMAKE_INSTALL_BINDIR}
- FILE_SET HEADERS DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
-)
diff --git a/tests/beman/elide/CMakeLists.txt b/tests/beman/elide/CMakeLists.txt
index 1eaa621..a620323 100644
--- a/tests/beman/elide/CMakeLists.txt
+++ b/tests/beman/elide/CMakeLists.txt
@@ -1,21 +1,21 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-include(GoogleTest)
+find_package(GTest REQUIRED)
add_executable(beman.elide.tests.elide)
target_sources(beman.elide.tests.elide PRIVATE elide.test.cpp)
target_link_libraries(
beman.elide.tests.elide
- PRIVATE beman::elide GTest::gtest GTest::gtest_main
+ PRIVATE beman::elide GTest::gtest_main
)
-gtest_add_tests(beman.elide.tests.elide "" AUTO)
-
add_executable(beman.elide.tests.deduce)
target_sources(beman.elide.tests.deduce PRIVATE deduce.test.cpp)
target_link_libraries(
beman.elide.tests.deduce
- PRIVATE beman::elide GTest::gtest GTest::gtest_main
+ PRIVATE beman::elide GTest::gtest_main
)
-gtest_add_tests(beman.elide.tests.deduce "" AUTO)
+include(GoogleTest)
+gtest_discover_tests(beman.elide.tests.elide)
+gtest_discover_tests(beman.elide.tests.deduce)
diff --git a/tests/beman/elide/deduce.test.cpp b/tests/beman/elide/deduce.test.cpp
index 612e1ba..1f58eba 100644
--- a/tests/beman/elide/deduce.test.cpp
+++ b/tests/beman/elide/deduce.test.cpp
@@ -13,36 +13,32 @@ namespace beman::elide {
namespace {
struct factory {
- int operator()();
+ int operator()();
};
struct no_lvalue_factory {
- int operator()() &&;
+ int operator()() &&;
};
struct split_factory {
- int operator()() &;
- double operator()() &&;
+ int operator()() &;
+ double operator()() &&;
};
-template
+template
struct wrapper {
- template
- explicit wrapper(U&& u) noexcept(
- std::is_nothrow_constructible_v)
- : t_(std::forward(u))
- {}
- constexpr const T& get() const noexcept {
- return t_;
- }
-private:
- T t_;
+ template
+ explicit wrapper(U&& u) noexcept(std::is_nothrow_constructible_v) : t_(std::forward(u)) {}
+ constexpr const T& get() const noexcept { return t_; }
+
+ private:
+ T t_;
};
-template
+template
explicit wrapper(T&&) -> wrapper>;
-}
+} // namespace
static_assert(!detail::deduce::is_elide::value);
static_assert(detail::deduce::is_elide>::value);
@@ -53,82 +49,26 @@ static_assert(std::is_same_v>);
static_assert(std::is_same_v>);
static_assert(std::is_same_v>);
-static_assert(
- std::is_same_v<
- int,
- deduce_t<
- elide>>);
-static_assert(
- std::is_same_v<
- int,
- deduce_t<
- elide&>>);
-static_assert(
- std::is_same_v<
- int,
- deduce_t<
- const elide&>>);
-static_assert(
- std::is_same_v<
- int,
- deduce_t<
- elide&&>>);
-static_assert(
- std::is_same_v<
- int,
- deduce_t<
- const elide&&>>);
-
-static_assert(
- std::is_same_v<
- int,
- deduce_t<
- elide>>);
-static_assert(
- std::is_same_v<
- int,
- deduce_t<
- elide&&>>);
-static_assert(
- std::is_same_v<
- int,
- deduce_t<
- const elide&&>>);
-static_assert(
- std::is_same_v<
- elide,
- deduce_t<
- const elide&>>);
-static_assert(
- std::is_same_v<
- elide,
- deduce_t<
- elide&>>);
-
-static_assert(
- std::is_same_v<
- double,
- deduce_t<
- elide>>);
-static_assert(
- std::is_same_v<
- double,
- deduce_t<
- elide&&>>);
-static_assert(
- std::is_same_v<
- int,
- std::invoke_result_t<
- elide&>>);
-static_assert(
- std::is_same_v<
- int,
- deduce_t<
- elide&>>);
+static_assert(std::is_same_v>>);
+static_assert(std::is_same_v&>>);
+static_assert(std::is_same_v&>>);
+static_assert(std::is_same_v&&>>);
+static_assert(std::is_same_v&&>>);
+
+static_assert(std::is_same_v>>);
+static_assert(std::is_same_v&&>>);
+static_assert(std::is_same_v&&>>);
+static_assert(std::is_same_v, deduce_t&>>);
+static_assert(std::is_same_v, deduce_t&>>);
+
+static_assert(std::is_same_v>>);
+static_assert(std::is_same_v&&>>);
+static_assert(std::is_same_v&>>);
+static_assert(std::is_same_v&>>);
TEST(Deduce, basic) {
- wrapper w(elide([]() noexcept { return 5; }));
- EXPECT_EQ(5, w.get());
+ wrapper w(elide([]() noexcept { return 5; }));
+ EXPECT_EQ(5, w.get());
}
-}
+} // namespace beman::elide
diff --git a/tests/beman/elide/elide.test.cpp b/tests/beman/elide/elide.test.cpp
index a924eb3..d009f52 100644
--- a/tests/beman/elide/elide.test.cpp
+++ b/tests/beman/elide/elide.test.cpp
@@ -17,191 +17,167 @@ namespace beman::elide {
namespace {
struct instrumented {
- struct state_type {
- state_type() = default;
- state_type(const state_type&) = delete;
- state_type& operator=(const state_type&) = delete;
- std::size_t constructed{0};
- std::size_t copy_constructed{0};
- std::size_t move_constructed{0};
- };
- explicit instrumented(state_type& state) noexcept
- : state_(state)
- {
- ++state_.constructed;
- }
- instrumented(const instrumented& other) noexcept
- : state_(other.state_)
- {
- ++state_.copy_constructed;
- }
- instrumented(instrumented&& other) noexcept
- : state_(other.state_)
- {
- ++state_.move_constructed;
- }
-private:
- state_type& state_;
+ struct state_type {
+ state_type() = default;
+ state_type(const state_type&) = delete;
+ state_type& operator=(const state_type&) = delete;
+ std::size_t constructed{0};
+ std::size_t copy_constructed{0};
+ std::size_t move_constructed{0};
+ };
+ explicit instrumented(state_type& state) noexcept : state_(state) { ++state_.constructed; }
+ instrumented(const instrumented& other) noexcept : state_(other.state_) { ++state_.copy_constructed; }
+ instrumented(instrumented&& other) noexcept : state_(other.state_) { ++state_.move_constructed; }
+
+ private:
+ state_type& state_;
};
-template
+template
struct factory {
- struct state_type {
- std::vector> lvalue_arguments;
- std::vector> rvalue_arguments;
- };
- explicit factory(state_type& state, instrumented::state_type& other_state)
- noexcept
- : state_(state),
- other_state_(other_state)
- {}
- template
- requires (std::is_constructible_v && ...)
- instrumented operator()(Us&&... us) const&& {
- state_.rvalue_arguments.emplace_back(std::forward(us)...);
- return instrumented(other_state_);
- }
- template
- requires (std::is_constructible_v && ...)
- instrumented operator()(Us&&... us) const& {
- state_.lvalue_arguments.emplace_back(std::forward(us)...);
- return instrumented(other_state_);
- }
-private:
- state_type& state_;
- instrumented::state_type& other_state_;
+ struct state_type {
+ std::vector> lvalue_arguments;
+ std::vector> rvalue_arguments;
+ };
+ explicit factory(state_type& state, instrumented::state_type& other_state) noexcept
+ : state_(state), other_state_(other_state) {}
+ template
+ requires(std::is_constructible_v && ...)
+ instrumented operator()(Us&&... us) const&& {
+ state_.rvalue_arguments.emplace_back(std::forward(us)...);
+ return instrumented(other_state_);
+ }
+ template
+ requires(std::is_constructible_v && ...)
+ instrumented operator()(Us&&... us) const& {
+ state_.lvalue_arguments.emplace_back(std::forward(us)...);
+ return instrumented(other_state_);
+ }
+
+ private:
+ state_type& state_;
+ instrumented::state_type& other_state_;
};
struct split_factory {
- std::vector operator()() &;
- std::vector operator()() &&;
+ std::vector operator()() &;
+ std::vector operator()() &&;
};
-static_assert(
- std::is_convertible_v<
- elide,
- std::vector>);
-static_assert(
- std::is_convertible_v<
- elide&&,
- std::vector>);
-static_assert(
- std::is_convertible_v<
- elide&,
- std::vector>);
+static_assert(std::is_convertible_v, std::vector>);
+static_assert(std::is_convertible_v&&, std::vector>);
+static_assert(std::is_convertible_v&, std::vector>);
-}
+} // namespace
TEST(Elide, no_arguments_lvalue_invocable) {
- instrumented::state_type state;
- factory<>::state_type factory_state;
- const factory<> f(factory_state, state);
- const elide e(std::move(f));
- static_assert(std::is_convertible_v);
- static_assert(std::is_convertible_v);
- EXPECT_EQ(0, state.constructed);
- EXPECT_EQ(0, state.copy_constructed);
- EXPECT_EQ(0, state.move_constructed);
- EXPECT_EQ(0, factory_state.lvalue_arguments.size());
- EXPECT_EQ(0, factory_state.rvalue_arguments.size());
- (instrumented)e;
- EXPECT_EQ(1, state.constructed);
- EXPECT_EQ(0, state.copy_constructed);
- EXPECT_EQ(0, state.move_constructed);
- EXPECT_EQ(1, factory_state.lvalue_arguments.size());
- EXPECT_EQ(0, factory_state.rvalue_arguments.size());
- (instrumented)e;
- EXPECT_EQ(2, state.constructed);
- EXPECT_EQ(0, state.copy_constructed);
- EXPECT_EQ(0, state.move_constructed);
- EXPECT_EQ(2, factory_state.lvalue_arguments.size());
- EXPECT_EQ(0, factory_state.rvalue_arguments.size());
- {
- instrumented res = e();
- (void)res;
- }
- EXPECT_EQ(3, state.constructed);
- EXPECT_EQ(0, state.copy_constructed);
- EXPECT_EQ(0, state.move_constructed);
- EXPECT_EQ(3, factory_state.lvalue_arguments.size());
- EXPECT_EQ(0, factory_state.rvalue_arguments.size());
- (instrumented)std::move(e);
- EXPECT_EQ(4, state.constructed);
- EXPECT_EQ(0, state.copy_constructed);
- EXPECT_EQ(0, state.move_constructed);
- EXPECT_EQ(3, factory_state.lvalue_arguments.size());
- EXPECT_EQ(1, factory_state.rvalue_arguments.size());
- {
- instrumented res = std::move(e)();
- (void)res;
- }
- EXPECT_EQ(5, state.constructed);
- EXPECT_EQ(0, state.copy_constructed);
- EXPECT_EQ(0, state.move_constructed);
- EXPECT_EQ(3, factory_state.lvalue_arguments.size());
- EXPECT_EQ(2, factory_state.rvalue_arguments.size());
+ instrumented::state_type state;
+ factory<>::state_type factory_state;
+ const factory<> f(factory_state, state);
+ const elide e(std::move(f));
+ static_assert(std::is_convertible_v);
+ static_assert(std::is_convertible_v);
+ EXPECT_EQ(0, state.constructed);
+ EXPECT_EQ(0, state.copy_constructed);
+ EXPECT_EQ(0, state.move_constructed);
+ EXPECT_EQ(0, factory_state.lvalue_arguments.size());
+ EXPECT_EQ(0, factory_state.rvalue_arguments.size());
+ (void)(instrumented)e;
+ EXPECT_EQ(1, state.constructed);
+ EXPECT_EQ(0, state.copy_constructed);
+ EXPECT_EQ(0, state.move_constructed);
+ EXPECT_EQ(1, factory_state.lvalue_arguments.size());
+ EXPECT_EQ(0, factory_state.rvalue_arguments.size());
+ (void)(instrumented)e;
+ EXPECT_EQ(2, state.constructed);
+ EXPECT_EQ(0, state.copy_constructed);
+ EXPECT_EQ(0, state.move_constructed);
+ EXPECT_EQ(2, factory_state.lvalue_arguments.size());
+ EXPECT_EQ(0, factory_state.rvalue_arguments.size());
+ {
+ instrumented res = e();
+ (void)res;
+ }
+ EXPECT_EQ(3, state.constructed);
+ EXPECT_EQ(0, state.copy_constructed);
+ EXPECT_EQ(0, state.move_constructed);
+ EXPECT_EQ(3, factory_state.lvalue_arguments.size());
+ EXPECT_EQ(0, factory_state.rvalue_arguments.size());
+ (void)(instrumented)std::move(e);
+ EXPECT_EQ(4, state.constructed);
+ EXPECT_EQ(0, state.copy_constructed);
+ EXPECT_EQ(0, state.move_constructed);
+ EXPECT_EQ(3, factory_state.lvalue_arguments.size());
+ EXPECT_EQ(1, factory_state.rvalue_arguments.size());
+ {
+ instrumented res = std::move(e)();
+ (void)res;
+ }
+ EXPECT_EQ(5, state.constructed);
+ EXPECT_EQ(0, state.copy_constructed);
+ EXPECT_EQ(0, state.move_constructed);
+ EXPECT_EQ(3, factory_state.lvalue_arguments.size());
+ EXPECT_EQ(2, factory_state.rvalue_arguments.size());
}
TEST(Elide, one_argument_lvalue_invocable) {
- instrumented::state_type state;
- factory::state_type factory_state;
- const factory f(factory_state, state);
- const int i = 5;
- const elide e(std::move(f), i);
- static_assert(std::is_convertible_v);
- static_assert(std::is_convertible_v);
- EXPECT_EQ(0, state.constructed);
- EXPECT_EQ(0, state.copy_constructed);
- EXPECT_EQ(0, state.move_constructed);
- EXPECT_EQ(0, factory_state.lvalue_arguments.size());
- EXPECT_EQ(0, factory_state.rvalue_arguments.size());
- (instrumented)e;
- EXPECT_EQ(1, state.constructed);
- EXPECT_EQ(0, state.copy_constructed);
- EXPECT_EQ(0, state.move_constructed);
- EXPECT_EQ(0, factory_state.rvalue_arguments.size());
- ASSERT_EQ(1, factory_state.lvalue_arguments.size());
- EXPECT_EQ(5, std::get<0>(factory_state.lvalue_arguments.back()));
- (instrumented)e;
- EXPECT_EQ(2, state.constructed);
- EXPECT_EQ(0, state.copy_constructed);
- EXPECT_EQ(0, state.move_constructed);
- EXPECT_EQ(0, factory_state.rvalue_arguments.size());
- EXPECT_EQ(2, factory_state.lvalue_arguments.size());
- EXPECT_EQ(5, std::get<0>(factory_state.lvalue_arguments.back()));
- (instrumented)std::move(e);
- EXPECT_EQ(3, state.constructed);
- EXPECT_EQ(0, state.copy_constructed);
- EXPECT_EQ(0, state.move_constructed);
- EXPECT_EQ(2, factory_state.lvalue_arguments.size());
- ASSERT_EQ(1, factory_state.rvalue_arguments.size());
- EXPECT_EQ(5, std::get<0>(factory_state.rvalue_arguments.back()));
+ instrumented::state_type state;
+ factory::state_type factory_state;
+ const factory f(factory_state, state);
+ const int i = 5;
+ const elide e(std::move(f), i);
+ static_assert(std::is_convertible_v);
+ static_assert(std::is_convertible_v);
+ EXPECT_EQ(0, state.constructed);
+ EXPECT_EQ(0, state.copy_constructed);
+ EXPECT_EQ(0, state.move_constructed);
+ EXPECT_EQ(0, factory_state.lvalue_arguments.size());
+ EXPECT_EQ(0, factory_state.rvalue_arguments.size());
+ (void)(instrumented)e;
+ EXPECT_EQ(1, state.constructed);
+ EXPECT_EQ(0, state.copy_constructed);
+ EXPECT_EQ(0, state.move_constructed);
+ EXPECT_EQ(0, factory_state.rvalue_arguments.size());
+ ASSERT_EQ(1, factory_state.lvalue_arguments.size());
+ EXPECT_EQ(5, std::get<0>(factory_state.lvalue_arguments.back()));
+ (void)(instrumented)e;
+ EXPECT_EQ(2, state.constructed);
+ EXPECT_EQ(0, state.copy_constructed);
+ EXPECT_EQ(0, state.move_constructed);
+ EXPECT_EQ(0, factory_state.rvalue_arguments.size());
+ EXPECT_EQ(2, factory_state.lvalue_arguments.size());
+ EXPECT_EQ(5, std::get<0>(factory_state.lvalue_arguments.back()));
+ (void)(instrumented)std::move(e);
+ EXPECT_EQ(3, state.constructed);
+ EXPECT_EQ(0, state.copy_constructed);
+ EXPECT_EQ(0, state.move_constructed);
+ EXPECT_EQ(2, factory_state.lvalue_arguments.size());
+ ASSERT_EQ(1, factory_state.rvalue_arguments.size());
+ EXPECT_EQ(5, std::get<0>(factory_state.rvalue_arguments.back()));
}
TEST(Elide, one_non_copyable_argument) {
- instrumented::state_type state;
- factory>::state_type factory_state;
- const factory> f(factory_state, state);
- auto ptr = std::make_unique(5);
- const auto expected = ptr.get();
- const elide e(std::move(f), std::move(ptr));
- static_assert(std::is_convertible_v);
- static_assert(!std::is_convertible_v);
- EXPECT_EQ(0, state.constructed);
- EXPECT_EQ(0, state.copy_constructed);
- EXPECT_EQ(0, state.move_constructed);
- EXPECT_EQ(0, factory_state.lvalue_arguments.size());
- EXPECT_EQ(0, factory_state.rvalue_arguments.size());
- (instrumented)std::move(e);
- EXPECT_EQ(1, state.constructed);
- EXPECT_EQ(0, state.copy_constructed);
- EXPECT_EQ(0, state.move_constructed);
- EXPECT_EQ(0, factory_state.lvalue_arguments.size());
- ASSERT_EQ(1, factory_state.rvalue_arguments.size());
- ASSERT_TRUE(std::get<0>(factory_state.rvalue_arguments.front()));
- EXPECT_EQ(
- expected,
- std::get<0>(factory_state.rvalue_arguments.front()).get());
+ instrumented::state_type state;
+ factory>::state_type factory_state;
+ const factory> f(factory_state, state);
+ auto ptr = std::make_unique(5);
+ const auto expected = ptr.get();
+ const elide e(std::move(f), std::move(ptr));
+ static_assert(std::is_convertible_v);
+ static_assert(!std::is_convertible_v);
+ EXPECT_EQ(0, state.constructed);
+ EXPECT_EQ(0, state.copy_constructed);
+ EXPECT_EQ(0, state.move_constructed);
+ EXPECT_EQ(0, factory_state.lvalue_arguments.size());
+ EXPECT_EQ(0, factory_state.rvalue_arguments.size());
+ (void)(instrumented)std::move(e);
+ EXPECT_EQ(1, state.constructed);
+ EXPECT_EQ(0, state.copy_constructed);
+ EXPECT_EQ(0, state.move_constructed);
+ EXPECT_EQ(0, factory_state.lvalue_arguments.size());
+ ASSERT_EQ(1, factory_state.rvalue_arguments.size());
+ ASSERT_TRUE(std::get<0>(factory_state.rvalue_arguments.front()));
+ EXPECT_EQ(expected, std::get<0>(factory_state.rvalue_arguments.front()).get());
}
-}
+} // namespace beman::elide