diff --git a/.drone.jsonnet b/.drone.jsonnet new file mode 100644 index 0000000..656120f --- /dev/null +++ b/.drone.jsonnet @@ -0,0 +1,440 @@ +# Copyright 2022 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +local library = "variant2"; + +local triggers = +{ + branch: [ "master", "develop", "feature/*" ] +}; + +local ubsan = { UBSAN: '1', UBSAN_OPTIONS: 'print_stacktrace=1' }; +local asan = { ASAN: '1' }; + +local linux_pipeline(name, image, environment, packages = "", sources = [], arch = "amd64") = +{ + name: name, + kind: "pipeline", + type: "docker", + trigger: triggers, + platform: + { + os: "linux", + arch: arch + }, + steps: + [ + { + name: "everything", + image: image, + environment: environment, + commands: + [ + 'set -e', + 'uname -a', + 'echo $DRONE_STAGE_MACHINE', + 'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -', + ] + + (if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) + + (if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) + + [ + 'export LIBRARY=' + library, + './.drone/drone.sh', + ] + } + ] +}; + +local macos_pipeline(name, environment, xcode_version = "12.2", osx_version = "catalina", arch = "amd64") = +{ + name: name, + kind: "pipeline", + type: "exec", + trigger: triggers, + platform: { + "os": "darwin", + "arch": arch + }, + node: { + "os": osx_version + }, + steps: [ + { + name: "everything", + environment: environment + { "DEVELOPER_DIR": "/Applications/Xcode-" + xcode_version + ".app/Contents/Developer" }, + commands: + [ + 'export LIBRARY=' + library, + './.drone/drone.sh', + ] + } + ] +}; + +local windows_pipeline(name, image, environment, arch = "amd64") = +{ + name: name, + kind: "pipeline", + type: "docker", + trigger: triggers, + platform: + { + os: "windows", + arch: arch + }, + "steps": + [ + { + name: "everything", + image: image, + environment: environment, + commands: + [ + 'cmd /C .drone\\\\drone.bat ' + library, + ] + } + ] +}; + +[ + linux_pipeline( + "Linux 16.04 GCC 4.8 32/64", + "cppalliance/droneubuntu1604:1", + { TOOLSET: 'gcc', COMPILER: 'g++-4.8', CXXSTD: '11', ADDRMD: '32,64' }, + "g++-4.8-multilib", + ), + + linux_pipeline( + "Linux 16.04 GCC 4.9 32/64", + "cppalliance/droneubuntu1604:1", + { TOOLSET: 'gcc', COMPILER: 'g++-4.9', CXXSTD: '11', ADDRMD: '32,64' }, + "g++-4.9-multilib", + ), + + linux_pipeline( + "Linux 16.04 GCC 5* 32/64", + "cppalliance/droneubuntu1604:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14', ADDRMD: '32,64' }, + ), + + linux_pipeline( + "Linux 18.04 GCC 6 32/64", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++-6', CXXSTD: '11,14', ADDRMD: '32,64' }, + "g++-6-multilib", + ), + + linux_pipeline( + "Linux 18.04 GCC 7* 32/64", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17', ADDRMD: '32,64' }, + ), + + linux_pipeline( + "Linux 18.04 GCC 8 32/64", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '11,14,17', ADDRMD: '32,64' }, + "g++-8-multilib", + ), + + linux_pipeline( + "Linux 20.04 GCC 9* 32/64", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a', ADDRMD: '32,64' }, + ), + + linux_pipeline( + "Linux 20.04 GCC 9* ARM64", + "cppalliance/droneubuntu2004:multiarch", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' }, + arch="arm64", + ), + + linux_pipeline( + "Linux 20.04 GCC 9* S390x", + "cppalliance/droneubuntu2004:multiarch", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' }, + arch="s390x", + ), + + linux_pipeline( + "Linux 20.04 GCC 10 32/64", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '11,14,17,20', ADDRMD: '32,64' }, + "g++-10-multilib", + ), + + linux_pipeline( + "Linux 22.04 GCC 11* 32/64", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a', ADDRMD: '32,64' }, + ), + + linux_pipeline( + "Linux 22.04 GCC 12 32/64", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '11,14,17,20,2b', ADDRMD: '32,64' }, + "g++-12-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 13 32/64", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '11,14,17,20,2b', ADDRMD: '32,64' }, + "g++-13-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 14 32 ASAN", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b', ADDRMD: '32' } + asan, + "g++-14-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 14 64 ASAN", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b', ADDRMD: '64' } + asan, + "g++-14-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 14 32 UBSAN", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b', ADDRMD: '32' } + ubsan, + "g++-14-multilib", + ), + + linux_pipeline( + "Linux 24.04 GCC 14 64 UBSAN", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b', ADDRMD: '64' } + ubsan, + "g++-14-multilib", + ), + + linux_pipeline( + "Linux 16.04 Clang 3.5", + "cppalliance/droneubuntu1604:1", + { TOOLSET: 'clang', COMPILER: 'clang++-3.5', CXXSTD: '11' }, + "clang-3.5", + ), + + linux_pipeline( + "Linux 16.04 Clang 3.6", + "cppalliance/droneubuntu1604:1", + { TOOLSET: 'clang', COMPILER: 'clang++-3.6', CXXSTD: '11,14' }, + "clang-3.6", + ), + + linux_pipeline( + "Linux 16.04 Clang 3.7", + "cppalliance/droneubuntu1604:1", + { TOOLSET: 'clang', COMPILER: 'clang++-3.7', CXXSTD: '11,14' }, + "clang-3.7", + ), + + linux_pipeline( + "Linux 16.04 Clang 3.8", + "cppalliance/droneubuntu1604:1", + { TOOLSET: 'clang', COMPILER: 'clang++-3.8', CXXSTD: '11,14' }, + "clang-3.8", + ), + + linux_pipeline( + "Linux 18.04 Clang 3.9", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'clang', COMPILER: 'clang++-3.9', CXXSTD: '11,14' }, + "clang-3.9", + ), + + linux_pipeline( + "Linux 18.04 Clang 4.0", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'clang', COMPILER: 'clang++-4.0', CXXSTD: '11,14' }, + "clang-4.0", + ), + + linux_pipeline( + "Linux 18.04 Clang 5.0", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'clang', COMPILER: 'clang++-5.0', CXXSTD: '11,14' }, + "clang-5.0", + ), + + linux_pipeline( + "Linux 18.04 Clang 6.0", + "cppalliance/droneubuntu1804:1", + { TOOLSET: 'clang', COMPILER: 'clang++-6.0', CXXSTD: '11,14,17' }, + "clang-6.0", + ), + + linux_pipeline( + "Linux 20.04 Clang 7", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-7', CXXSTD: '11,14,17' }, + "clang-7", + ), + + linux_pipeline( + "Linux 20.04 Clang 8", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-8', CXXSTD: '11,14,17' }, + "clang-8", + ), + + linux_pipeline( + "Linux 20.04 Clang 9", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-9', CXXSTD: '11,14,17,2a' }, + "clang-9", + ), + + linux_pipeline( + "Linux 20.04 Clang 10", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-10', CXXSTD: '11,14,17,2a' }, + "clang-10", + ), + + linux_pipeline( + "Linux 20.04 Clang 11", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-11', CXXSTD: '11,14,17,2a' }, + "clang-11", + ), + + linux_pipeline( + "Linux 20.04 Clang 12", + "cppalliance/droneubuntu2004:1", + { TOOLSET: 'clang', COMPILER: 'clang++-12', CXXSTD: '11,14,17,2a' }, + "clang-12", + ), + + linux_pipeline( + "Linux 22.04 Clang 13", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'clang', COMPILER: 'clang++-13', CXXSTD: '11,14,17,20,2b' }, + "clang-13", + ), + + linux_pipeline( + "Linux 22.04 Clang 14", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '11,14,17,20,2b' }, + "clang-14", + ), + + linux_pipeline( + "Linux 22.04 Clang 15", + "cppalliance/droneubuntu2204:1", + { TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '11,14,17,20,2b' }, + "clang-15", + ), + + linux_pipeline( + "Linux 24.04 Clang 16", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'clang', COMPILER: 'clang++-16', CXXSTD: '11,14,17,20,2b' }, + "clang-16", + ), + + linux_pipeline( + "Linux 24.04 Clang 17 UBSAN", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' } + ubsan, + "clang-17", + ), + + linux_pipeline( + "Linux 24.04 Clang 17 ASAN", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' } + asan, + "clang-17", + ), + + linux_pipeline( + "Linux 24.04 Clang 18 UBSAN", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '11,14,17,20,2b' } + ubsan, + "clang-18", + ), + + linux_pipeline( + "Linux 24.04 Clang 18 ASAN", + "cppalliance/droneubuntu2404:1", + { TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '11,14,17,20,2b' } + asan, + "clang-18", + ), + + linux_pipeline( + "Linux 24.10 Clang 19", + "cppalliance/droneubuntu2410:1", + { TOOLSET: 'clang', COMPILER: 'clang++-19', CXXSTD: '11,14,17,20,2b' } + asan, + "clang-19", + ), + + macos_pipeline( + "MacOS 10.15 Xcode 12.2 UBSAN", + { TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,1z' } + ubsan, + ), + + macos_pipeline( + "MacOS 10.15 Xcode 12.2 ASAN", + { TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,1z' } + asan, + ), + + macos_pipeline( + "MacOS 12.4 Xcode 13.4.1 UBSAN", + { TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,17,20,2b' } + ubsan, + xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64", + ), + + macos_pipeline( + "MacOS 12.4 Xcode 13.4.1 ASAN", + { TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,17,20,2b' } + asan, + xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64", + ), + + windows_pipeline( + "Windows VS2015 msvc-14.0", + "cppalliance/dronevs2015", + { TOOLSET: 'msvc-14.0', CXXSTD: '14,latest', B2_DONT_EMBED_MANIFEST: '1' }, + ), + + windows_pipeline( + "Windows VS2017 msvc-14.1", + "cppalliance/dronevs2017", + { TOOLSET: 'msvc-14.1', CXXSTD: '14,17,latest' }, + ), + + windows_pipeline( + "Windows VS2017 msvc-14.1 permissive-", + "cppalliance/dronevs2017", + { TOOLSET: 'msvc-14.1', CXXSTD: '14,17', CXXFLAGS: '/permissive-' }, + ), + + windows_pipeline( + "Windows VS2019 msvc-14.2", + "cppalliance/dronevs2019", + { TOOLSET: 'msvc-14.2', CXXSTD: '14,17,20,latest' }, + ), + + windows_pipeline( + "Windows VS2019 msvc-14.2 permissive-", + "cppalliance/dronevs2019", + { TOOLSET: 'msvc-14.2', CXXSTD: '14,17', CXXFLAGS: '/permissive-' }, + ), + + windows_pipeline( + "Windows VS2022 msvc-14.3", + "cppalliance/dronevs2022:1", + { TOOLSET: 'msvc-14.3', CXXSTD: '14,17,20,latest' }, + ), + + windows_pipeline( + "Windows VS2022 msvc-14.3 permissive-", + "cppalliance/dronevs2022:1", + { TOOLSET: 'msvc-14.3', CXXSTD: '14,17', CXXFLAGS: '/permissive-' }, + ), +] diff --git a/.drone/drone.bat b/.drone/drone.bat new file mode 100644 index 0000000..4509c7f --- /dev/null +++ b/.drone/drone.bat @@ -0,0 +1,24 @@ +@REM Copyright 2022 Peter Dimov +@REM Distributed under the Boost Software License, Version 1.0. +@REM https://www.boost.org/LICENSE_1_0.txt + +@ECHO ON + +set LIBRARY=%1 +set DRONE_BUILD_DIR=%CD% + +set BOOST_BRANCH=develop +if "%DRONE_BRANCH%" == "master" set BOOST_BRANCH=master +cd .. +git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root +cd boost-root +git submodule update --init tools/boostdep +xcopy /s /e /q %DRONE_BUILD_DIR% libs\%LIBRARY%\ +python tools/boostdep/depinst/depinst.py %LIBRARY% +cmd /c bootstrap +b2 -d0 headers + +if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD% +if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD% +if not "%CXXFLAGS%" == "" set CXXFLAGS=cxxflags=%CXXFLAGS% +b2 -j3 libs/%LIBRARY%/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% %CXXFLAGS% variant=debug,release embed-manifest-via=linker diff --git a/.drone/drone.sh b/.drone/drone.sh new file mode 100755 index 0000000..2f2125d --- /dev/null +++ b/.drone/drone.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Copyright 2022 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +set -ex +export PATH=~/.local/bin:/usr/local/bin:$PATH + +DRONE_BUILD_DIR=$(pwd) + +BOOST_BRANCH=develop +if [ "$DRONE_BRANCH" = "master" ]; then BOOST_BRANCH=master; fi + +cd .. +git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root +cd boost-root +git submodule update --init tools/boostdep +cp -r $DRONE_BUILD_DIR/* libs/$LIBRARY +python tools/boostdep/depinst/depinst.py $LIBRARY +./bootstrap.sh +./b2 -d0 headers + +echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam +./b2 -j3 libs/$LIBRARY/test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release ${ADDRMD:+address-model=$ADDRMD} ${UBSAN:+undefined-sanitizer=norecover debug-symbols=on} ${ASAN:+address-sanitizer=norecover debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81b1e9b..0753bc9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,97 +18,196 @@ jobs: matrix: include: - toolset: gcc-4.8 - cxxstd: "03,11" - os: ubuntu-18.04 + cxxstd: "11" + container: ubuntu:16.04 + os: ubuntu-latest install: g++-4.8 + - toolset: gcc-4.9 + cxxstd: "11" + container: ubuntu:16.04 + os: ubuntu-latest + install: g++-4.9 - toolset: gcc-5 - cxxstd: "03,11,14,1z" - os: ubuntu-18.04 + cxxstd: "11,14,1z" + container: ubuntu:18.04 + os: ubuntu-latest install: g++-5 - toolset: gcc-6 - cxxstd: "03,11,14,1z" - os: ubuntu-18.04 + cxxstd: "11,14,1z" + container: ubuntu:18.04 + os: ubuntu-latest install: g++-6 - toolset: gcc-7 - cxxstd: "03,11,14,17" - os: ubuntu-18.04 + cxxstd: "11,14,17" + container: ubuntu:18.04 + os: ubuntu-latest - toolset: gcc-8 - cxxstd: "03,11,14,17,2a" - os: ubuntu-18.04 + cxxstd: "11,14,17,2a" + os: ubuntu-20.04 install: g++-8 - toolset: gcc-9 - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: ubuntu-20.04 - toolset: gcc-10 - cxxstd: "03,11,14,17,2a" - os: ubuntu-20.04 + cxxstd: "11,14,17,2a" + os: ubuntu-22.04 install: g++-10 - toolset: gcc-11 - cxxstd: "03,11,14,17,2a" - os: ubuntu-20.04 + cxxstd: "11,14,17,2a" + os: ubuntu-22.04 install: g++-11 + - toolset: gcc-12 + cxxstd: "11,14,17,20,2b" + os: ubuntu-22.04 + install: g++-12 + - toolset: gcc-13 + cxxstd: "11,14,17,20,2b" + container: ubuntu:24.04 + os: ubuntu-latest + install: g++-13 + - toolset: gcc-14 + cxxstd: "11,14,17,20,2b" + container: ubuntu:24.04 + os: ubuntu-latest + install: g++-14 - toolset: clang compiler: clang++-3.9 - cxxstd: "03,11,14" - os: ubuntu-18.04 + cxxstd: "11,14" + container: ubuntu:18.04 + os: ubuntu-latest install: clang-3.9 - toolset: clang compiler: clang++-4.0 - cxxstd: "03,11,14" - os: ubuntu-18.04 + cxxstd: "11,14" + container: ubuntu:18.04 + os: ubuntu-latest install: clang-4.0 - toolset: clang compiler: clang++-5.0 - cxxstd: "03,11,14,1z" - os: ubuntu-18.04 + cxxstd: "11,14" + container: ubuntu:18.04 + os: ubuntu-latest install: clang-5.0 - toolset: clang compiler: clang++-6.0 - cxxstd: "03,11,14,17" - os: ubuntu-18.04 + cxxstd: "11,14,17" + os: ubuntu-20.04 install: clang-6.0 - toolset: clang compiler: clang++-7 - cxxstd: "03,11,14,17" - os: ubuntu-18.04 + cxxstd: "11,14,17" + os: ubuntu-20.04 install: clang-7 - toolset: clang compiler: clang++-8 - cxxstd: "03,11,14,17" + cxxstd: "11,14,17" os: ubuntu-20.04 install: clang-8 - toolset: clang compiler: clang++-9 - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: ubuntu-20.04 install: clang-9 - toolset: clang compiler: clang++-10 - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: ubuntu-20.04 install: clang-10 - toolset: clang compiler: clang++-11 - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: ubuntu-20.04 install: clang-11 - toolset: clang compiler: clang++-12 - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: ubuntu-20.04 install: clang-12 - toolset: clang - cxxstd: "03,11,14,17,2a" - os: macos-10.15 + compiler: clang++-13 + cxxstd: "11,14,17,20,2b" + container: ubuntu:22.04 + os: ubuntu-latest + install: clang-13 + - toolset: clang + compiler: clang++-14 + cxxstd: "11,14,17,20,2b" + container: ubuntu:22.04 + os: ubuntu-latest + install: clang-14 + - toolset: clang + compiler: clang++-15 + cxxstd: "11,14,17,20,2b" + container: ubuntu:22.04 + os: ubuntu-latest + install: clang-15 + - toolset: clang + compiler: clang++-16 + cxxstd: "11,14,17,20,2b" + container: ubuntu:24.04 + os: ubuntu-latest + install: clang-16 + - toolset: clang + compiler: clang++-17 + cxxstd: "11,14,17,20,2b" + container: ubuntu:24.04 + os: ubuntu-latest + install: clang-17 + - toolset: clang + compiler: clang++-18 + cxxstd: "11,14,17,20,2b" + container: ubuntu:24.04 + os: ubuntu-latest + install: clang-18 + - toolset: clang + compiler: clang++-19 + cxxstd: "11,14,17,20,2b" + container: ubuntu:24.10 + os: ubuntu-latest + install: clang-19 + - toolset: clang + cxxstd: "11,14,17,20,2b" + os: macos-13 + - toolset: clang + cxxstd: "11,14,17,20,2b" + os: macos-14 + - toolset: clang + cxxstd: "11,14,17,20,2b" + os: macos-15 runs-on: ${{matrix.os}} + container: + image: ${{matrix.container}} + volumes: + - /node20217:/node20217:rw,rshared + - ${{ startsWith(matrix.container, 'ubuntu:1') && '/node20217:/__e/node20:ro,rshared' || ' ' }} + + defaults: + run: + shell: bash + steps: - - uses: actions/checkout@v2 + - name: Setup container environment + if: matrix.container + run: | + apt-get update + apt-get -y install sudo python3 git g++ curl xz-utils + + - name: Install nodejs20glibc2.17 + if: ${{ startsWith( matrix.container, 'ubuntu:1' ) }} + run: | + curl -LO https://archives.boost.io/misc/node/node-v20.9.0-linux-x64-glibc-217.tar.xz + tar -xf node-v20.9.0-linux-x64-glibc-217.tar.xz --strip-components 1 -C /node20217 + ldd /__e/node20/bin/node + + - uses: actions/checkout@v4 - name: Install packages if: matrix.install - run: sudo apt install ${{matrix.install}} + run: | + sudo apt-get update + sudo apt-get -y install ${{matrix.install}} - name: Setup Boost run: | @@ -128,7 +227,7 @@ jobs: cd boost-root cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY git submodule update --init tools/boostdep - python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY + python3 tools/boostdep/depinst/depinst.py $LIBRARY ./bootstrap.sh ./b2 -d0 headers @@ -148,30 +247,30 @@ jobs: matrix: include: - toolset: msvc-14.0 - cxxstd: "14" + cxxstd: "14,latest" addrmd: 32,64 os: windows-2019 - - toolset: msvc-14.1 - cxxstd: "14,17,latest" - addrmd: 32,64 - os: windows-2016 - toolset: msvc-14.2 - cxxstd: "14,17,latest" + cxxstd: "14,17,20,latest" addrmd: 32,64 os: windows-2019 - toolset: msvc-14.3 + cxxstd: "14,17,20,latest" + addrmd: 32,64 + os: windows-2022 + - toolset: clang-win cxxstd: "14,17,latest" addrmd: 32,64 os: windows-2022 - toolset: gcc - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" addrmd: 64 os: windows-2019 runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup Boost shell: cmd @@ -199,25 +298,28 @@ jobs: shell: cmd run: | cd ../boost-root - b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release + b2 -j2 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker posix-cmake-subdir: strategy: fail-fast: false matrix: include: - - os: ubuntu-18.04 - os: ubuntu-20.04 - - os: macos-10.15 + - os: ubuntu-22.04 + - os: ubuntu-24.04 + - os: macos-13 + - os: macos-14 + - os: macos-15 runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install packages if: matrix.install - run: sudo apt install ${{matrix.install}} + run: sudo apt-get -y install ${{matrix.install}} - name: Setup Boost run: | @@ -252,18 +354,21 @@ jobs: fail-fast: false matrix: include: - - os: ubuntu-18.04 - os: ubuntu-20.04 - - os: macos-10.15 + - os: ubuntu-22.04 + - os: ubuntu-24.04 + - os: macos-13 + - os: macos-14 + - os: macos-15 runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install packages if: matrix.install - run: sudo apt install ${{matrix.install}} + run: sudo apt-get -y install ${{matrix.install}} - name: Setup Boost run: | @@ -308,18 +413,21 @@ jobs: fail-fast: false matrix: include: - - os: ubuntu-18.04 - os: ubuntu-20.04 - - os: macos-10.15 + - os: ubuntu-22.04 + - os: ubuntu-24.04 + - os: macos-13 + - os: macos-14 + - os: macos-15 runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install packages if: matrix.install - run: sudo apt install ${{matrix.install}} + run: sudo apt-get -y install ${{matrix.install}} - name: Setup Boost run: | @@ -356,3 +464,183 @@ jobs: run: | cd ../boost-root/__build__ ctest --output-on-failure --no-tests=error + + windows-cmake-subdir: + strategy: + fail-fast: false + matrix: + include: + - os: windows-2019 + - os: windows-2022 + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v4 + + - name: Setup Boost + shell: cmd + run: | + echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY% + for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi + echo LIBRARY: %LIBRARY% + echo LIBRARY=%LIBRARY%>>%GITHUB_ENV% + echo GITHUB_BASE_REF: %GITHUB_BASE_REF% + echo GITHUB_REF: %GITHUB_REF% + if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF% + set BOOST_BRANCH=develop + for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master + echo BOOST_BRANCH: %BOOST_BRANCH% + cd .. + git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\ + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY% + + - name: Use library with add_subdirectory (Debug) + shell: cmd + run: | + cd ../boost-root/libs/%LIBRARY%/test/cmake_subdir_test + mkdir __build__ && cd __build__ + cmake .. + cmake --build . --config Debug + ctest --output-on-failure --no-tests=error -C Debug + + - name: Use library with add_subdirectory (Release) + shell: cmd + run: | + cd ../boost-root/libs/%LIBRARY%/test/cmake_subdir_test/__build__ + cmake --build . --config Release + ctest --output-on-failure --no-tests=error -C Release + + windows-cmake-install: + strategy: + fail-fast: false + matrix: + include: + - os: windows-2019 + - os: windows-2022 + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v4 + + - name: Setup Boost + shell: cmd + run: | + echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY% + for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi + echo LIBRARY: %LIBRARY% + echo LIBRARY=%LIBRARY%>>%GITHUB_ENV% + echo GITHUB_BASE_REF: %GITHUB_BASE_REF% + echo GITHUB_REF: %GITHUB_REF% + if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF% + set BOOST_BRANCH=develop + for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master + echo BOOST_BRANCH: %BOOST_BRANCH% + cd .. + git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\ + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY% + + - name: Configure + shell: cmd + run: | + cd ../boost-root + mkdir __build__ && cd __build__ + cmake -DBOOST_INCLUDE_LIBRARIES=%LIBRARY% -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix .. + + - name: Install (Debug) + shell: cmd + run: | + cd ../boost-root/__build__ + cmake --build . --target install --config Debug + + - name: Install (Release) + shell: cmd + run: | + cd ../boost-root/__build__ + cmake --build . --target install --config Release + + - name: Use the installed library (Debug) + shell: cmd + run: | + cd ../boost-root/libs/%LIBRARY%/test/cmake_install_test && mkdir __build__ && cd __build__ + cmake -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix .. + cmake --build . --config Debug + ctest --output-on-failure --no-tests=error -C Debug + + - name: Use the installed library (Release) + shell: cmd + run: | + cd ../boost-root/libs/%LIBRARY%/test/cmake_install_test/__build__ + cmake --build . --config Release + ctest --output-on-failure --no-tests=error -C Release + + windows-cmake-test: + strategy: + fail-fast: false + matrix: + include: + - os: windows-2019 + - os: windows-2022 + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v4 + + - name: Setup Boost + shell: cmd + run: | + echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY% + for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi + echo LIBRARY: %LIBRARY% + echo LIBRARY=%LIBRARY%>>%GITHUB_ENV% + echo GITHUB_BASE_REF: %GITHUB_BASE_REF% + echo GITHUB_REF: %GITHUB_REF% + if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF% + set BOOST_BRANCH=develop + for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master + echo BOOST_BRANCH: %BOOST_BRANCH% + cd .. + git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\ + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY% + + - name: Configure + shell: cmd + run: | + cd ../boost-root + mkdir __build__ && cd __build__ + cmake -DBOOST_INCLUDE_LIBRARIES=%LIBRARY% -DBUILD_TESTING=ON .. + + - name: Build tests (Debug) + shell: cmd + run: | + cd ../boost-root/__build__ + cmake --build . --target tests --config Debug + + - name: Run tests (Debug) + shell: cmd + run: | + cd ../boost-root/__build__ + ctest --output-on-failure --no-tests=error -C Debug + + - name: Build tests (Release) + shell: cmd + run: | + cd ../boost-root/__build__ + cmake --build . --target tests --config Release + + - name: Run tests (Release) + shell: cmd + run: | + cd ../boost-root/__build__ + ctest --output-on-failure --no-tests=error -C Release diff --git a/CMakeLists.txt b/CMakeLists.txt index 3826577..def59e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,15 @@ target_link_libraries(boost_variant2 Boost::mp11 ) +if(CMAKE_VERSION VERSION_GREATER 3.18 AND CMAKE_GENERATOR MATCHES "Visual Studio") + + file(GLOB_RECURSE boost_variant2_IDEFILES CONFIGURE_DEPENDS include/*.hpp) + source_group(TREE ${PROJECT_SOURCE_DIR}/include FILES ${boost_variant2_IDEFILES} PREFIX "Header Files") + list(APPEND boost_variant2_IDEFILES extra/boost_variant2.natvis) + target_sources(boost_variant2 PRIVATE ${boost_variant2_IDEFILES}) + +endif() + target_compile_features(boost_variant2 INTERFACE cxx_std_11) if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") diff --git a/README.md b/README.md index d49356b..03a75f1 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Supported compilers: * g++ 4.8 or later with `-std=c++11` or above * clang++ 3.9 or later with `-std=c++11` or above -* Visual Studio 2015, 2017, 2019 +* Visual Studio 2015 or later Tested on [Github Actions](https://github.com/boostorg/variant2/actions) and [Appveyor](https://ci.appveyor.com/project/pdimov/variant2-fkab9). diff --git a/appveyor.yml b/appveyor.yml index baa4199..382121c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -21,18 +21,25 @@ environment: TOOLSET: msvc-14.1 ADDRMD: 32,64 CXXSTD: 14,17,latest + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + TOOLSET: msvc-14.1 + ADDRMD: 32,64 + CXXSTD: 14,17,latest + CXXFLAGS: /permissive- - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 TOOLSET: clang-win ADDRMD: 64 CXXSTD: 14,17,latest - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - TOOLSET: msvc-14.2 - ADDRMD: 32,64 - CXXSTD: 14,17,latest - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 TOOLSET: clang-win ADDRMD: 64 CXXSTD: 14,17,latest + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + CMAKE: 1 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + CMAKE_SUBDIR: 1 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + CMAKE_INSTALL: 1 install: - set BOOST_BRANCH=develop @@ -51,4 +58,28 @@ build: off test_script: - if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD% - if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD% - - b2 -j3 libs/variant2/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker + - if not "%CXXFLAGS%" == "" set CXXFLAGS=cxxflags=%CXXFLAGS% + - if "%CMAKE%%CMAKE_SUBDIR%%CMAKE_INSTALL%" == "" b2 -j2 libs/variant2/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% %CXXFLAGS% variant=debug,release embed-manifest-via=linker + + - if not "%CMAKE%" == "" mkdir __build__ && cd __build__ + - if not "%CMAKE%" == "" cmake -DBUILD_TESTING=ON -DBOOST_INCLUDE_LIBRARIES=variant2 -DBoost_VERBOSE=ON .. + - if not "%CMAKE%" == "" cmake --build . --target tests -j 3 --config Debug & ctest --output-on-failure --no-tests=error -j 3 -C Debug + - if not "%CMAKE%" == "" cmake --build . --target tests -j 3 --config Release & ctest --output-on-failure --no-tests=error -j 3 -C Release + - if not "%CMAKE%" == "" cmake --build . --target tests -j 3 --config MinSizeRel & ctest --output-on-failure --no-tests=error -j 3 -C MinSizeRel + - if not "%CMAKE%" == "" cmake --build . --target tests -j 3 --config RelWithDebInfo & ctest --output-on-failure --no-tests=error -j 3 -C RelWithDebInfo + + - if not "%CMAKE_SUBDIR%" == "" cd libs/variant2/test/cmake_subdir_test && mkdir __build__ && cd __build__ + - if not "%CMAKE_SUBDIR%" == "" cmake .. + - if not "%CMAKE_SUBDIR%" == "" cmake --build . --config Debug && cmake --build . --target check --config Debug + - if not "%CMAKE_SUBDIR%" == "" cmake --build . --config Release && cmake --build . --target check --config Release + - if not "%CMAKE_SUBDIR%" == "" cmake --build . --config MinSizeRel && cmake --build . --target check --config MinSizeRel + - if not "%CMAKE_SUBDIR%" == "" cmake --build . --config RelWithDebInfo && cmake --build . --target check --config RelWithDebInfo + + - if not "%CMAKE_INSTALL%" == "" mkdir __build__ && cd __build__ + - if not "%CMAKE_INSTALL%" == "" cmake -DBOOST_INCLUDE_LIBRARIES=variant2 -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix .. + - if not "%CMAKE_INSTALL%" == "" cmake --build . --target install --config Debug + - if not "%CMAKE_INSTALL%" == "" cmake --build . --target install --config Release + - if not "%CMAKE_INSTALL%" == "" cd ../libs/variant2/test/cmake_install_test && mkdir __build__ && cd __build__ + - if not "%CMAKE_INSTALL%" == "" cmake -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix .. + - if not "%CMAKE_INSTALL%" == "" cmake --build . --config Debug && cmake --build . --target check --config Debug + - if not "%CMAKE_INSTALL%" == "" cmake --build . --config Release && cmake --build . --target check --config Release diff --git a/build.jam b/build.jam new file mode 100644 index 0000000..052680f --- /dev/null +++ b/build.jam @@ -0,0 +1,22 @@ +# Copyright 2023-2024 René Ferdinand Rivera Morell +# Copyright 2024 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +require-b2 5.2 ; + +constant boost_dependencies : + /boost/assert//boost_assert + /boost/config//boost_config + /boost/mp11//boost_mp11 + ; + +project /boost/variant2 ; + +explicit + [ alias boost_variant2 : : : : include $(boost_dependencies) ] + [ alias all : boost_variant2 test ] + ; + +call-if : boost-library variant2 + ; diff --git a/doc/variant2/changelog.adoc b/doc/variant2/changelog.adoc index 18d4b4a..9080c21 100644 --- a/doc/variant2/changelog.adoc +++ b/doc/variant2/changelog.adoc @@ -1,5 +1,5 @@ //// -Copyright 2019-2021 Peter Dimov +Copyright 2019-2025 Peter Dimov Distributed under the Boost Software License, Version 1.0. https://www.boost.org/LICENSE_1_0.txt //// @@ -8,6 +8,18 @@ https://www.boost.org/LICENSE_1_0.txt # Revision History :idprefix: changelog_ +## Changes in 1.88.0 + +* Use the smallest appropriate unsigned type for the index. + +## Changes in 1.83.0 + +* Added `uses_double_storage()`. + +## Changes in 1.81.0 + +* Added support for `boost::json::value_from` and `boost::json::value_to`. + ## Changes in 1.79.0 * Added `operator<<` for `monostate`. diff --git a/doc/variant2/implementation.adoc b/doc/variant2/implementation.adoc index 0ccecfa..cbd6740 100644 --- a/doc/variant2/implementation.adoc +++ b/doc/variant2/implementation.adoc @@ -16,7 +16,7 @@ This implementation only depends on Boost.Config, Boost.Assert, and Boost.Mp11. * GCC 4.8 or later with `-std=c++11` or above * Clang 3.9 or later with `-std=c++11` or above -* Visual Studio 2015, 2017, 2019 +* Visual Studio 2015 or later Tested on https://github.com/boostorg/variant2/actions[Github Actions] and https://ci.appveyor.com/project/pdimov/variant2-fkab9[Appveyor]. diff --git a/doc/variant2/reference.adoc b/doc/variant2/reference.adoc index beede7b..fe38344 100644 --- a/doc/variant2/reference.adoc +++ b/doc/variant2/reference.adoc @@ -157,7 +157,7 @@ template // visit_by_index (extension) template - constexpr /*see below*/ visit_by_index(V&& v, F&&.. f); + constexpr /*see below*/ visit_by_index(V&& v, F&&... f); // monostate @@ -250,6 +250,8 @@ public: constexpr bool valueless_by_exception() const noexcept; constexpr size_t index() const noexcept; + static constexpr bool uses_double_storage() noexcept; + // swap void swap( variant& r ) noexcept( /*see below*/ ); @@ -570,6 +572,18 @@ constexpr size_t index() const noexcept; Returns: :: The zero-based index of the active alternative. +``` +static constexpr bool uses_double_storage() noexcept; +``` +[none] +* {blank} ++ +Returns: :: + `true` if the variant uses double storage to meet the never valueless + guarantee because one of the alternatives is not nothrow move constructible, + and `false` otherwise. + + #### Swap ``` @@ -922,7 +936,7 @@ Remarks: :: If `R` is given explicitly, as in `visit`, the return ``` template - constexpr /*see below*/ visit_by_index(V&& v, F&&.. f); + constexpr /*see below*/ visit_by_index(V&& v, F&&... f); ``` [none] * {blank} diff --git a/extra/boost_variant2.natvis b/extra/boost_variant2.natvis new file mode 100644 index 0000000..a8c29b8 --- /dev/null +++ b/extra/boost_variant2.natvis @@ -0,0 +1,178 @@ + + + + + + {{ index=0, value={*($T2*)&st_} }} + {{ index=1, value={*($T3*)&st_} }} + {{ index=2, value={*($T4*)&st_} }} + {{ index=3, value={*($T5*)&st_} }} + {{ index=4, value={*($T6*)&st_} }} + {{ index=5, value={*($T7*)&st_} }} + {{ index=6, value={*($T8*)&st_} }} + {{ index=7, value={*($T9*)&st_} }} + {{ index=8, value={*($T10*)&st_} }} + {{ index=9, value={*($T11*)&st_} }} + {{ index=10, value={*($T12*)&st_} }} + {{ index=11, value={*($T13*)&st_} }} + {{ index=12, value={*($T14*)&st_} }} + {{ index=13, value={*($T15*)&st_} }} + {{ index=14, value={*($T16*)&st_} }} + {{ index=15, value={*($T17*)&st_} }} + {{ index=16, value={*($T18*)&st_} }} + {{ index=17, value={*($T19*)&st_} }} + {{ index=18, value={*($T20*)&st_} }} + {{ index=19, value={*($T21*)&st_} }} + {{ index=10, value={*($T22*)&st_} }} + {{ index=21, value={*($T23*)&st_} }} + {{ index=22, value={*($T24*)&st_} }} + {{ index=23, value={*($T25*)&st_} }} + {{ index=24, value={*($T26*)&st_} }} + {{ index=25, value={*($T27*)&st_} }} + {{ index=26, value={*($T28*)&st_} }} + {{ index=27, value={*($T29*)&st_} }} + {{ index=28, value={*($T30*)&st_} }} + {{ index=29, value={*($T31*)&st_} }} + {{ index=30, value={*($T32*)&st_} }} + {{ index=31, value={*($T33*)&st_} }} + {{ index=32, value={*($T34*)&st_} }} + {{ index=33, value={*($T35*)&st_} }} + {{ index=34, value={*($T36*)&st_} }} + {{ index=35, value={*($T37*)&st_} }} + {{ index=36, value={*($T38*)&st_} }} + {{ index=37, value={*($T39*)&st_} }} + {{ index=38, value={*($T40*)&st_} }} + {{ index=39, value={*($T41*)&st_} }} + + index() + *($T2*)&st_ + *($T3*)&st_ + *($T4*)&st_ + *($T5*)&st_ + *($T6*)&st_ + *($T7*)&st_ + *($T8*)&st_ + *($T9*)&st_ + *($T10*)&st_ + *($T11*)&st_ + *($T12*)&st_ + *($T13*)&st_ + *($T14*)&st_ + *($T15*)&st_ + *($T16*)&st_ + *($T17*)&st_ + *($T18*)&st_ + *($T19*)&st_ + *($T20*)&st_ + *($T21*)&st_ + *($T22*)&st_ + *($T23*)&st_ + *($T24*)&st_ + *($T25*)&st_ + *($T26*)&st_ + *($T27*)&st_ + *($T28*)&st_ + *($T29*)&st_ + *($T30*)&st_ + *($T31*)&st_ + *($T32*)&st_ + *($T33*)&st_ + *($T34*)&st_ + *($T35*)&st_ + *($T36*)&st_ + *($T37*)&st_ + *($T38*)&st_ + *($T39*)&st_ + *($T40*)&st_ + *($T41*)&st_ + + + + + + {{ index=0, value={*($T2*)&st_[ix_%2]} }} + {{ index=1, value={*($T3*)&st_[ix_%2]} }} + {{ index=2, value={*($T4*)&st_[ix_%2]} }} + {{ index=3, value={*($T5*)&st_[ix_%2]} }} + {{ index=4, value={*($T6*)&st_[ix_%2]} }} + {{ index=5, value={*($T7*)&st_[ix_%2]} }} + {{ index=6, value={*($T8*)&st_[ix_%2]} }} + {{ index=7, value={*($T9*)&st_[ix_%2]} }} + {{ index=8, value={*($T10*)&st_[ix_%2]} }} + {{ index=9, value={*($T11*)&st_[ix_%2]} }} + {{ index=10, value={*($T12*)&st_[ix_%2]} }} + {{ index=11, value={*($T13*)&st_[ix_%2]} }} + {{ index=12, value={*($T14*)&st_[ix_%2]} }} + {{ index=13, value={*($T15*)&st_[ix_%2]} }} + {{ index=14, value={*($T16*)&st_[ix_%2]} }} + {{ index=15, value={*($T17*)&st_[ix_%2]} }} + {{ index=16, value={*($T18*)&st_[ix_%2]} }} + {{ index=17, value={*($T19*)&st_[ix_%2]} }} + {{ index=18, value={*($T20*)&st_[ix_%2]} }} + {{ index=19, value={*($T21*)&st_[ix_%2]} }} + {{ index=20, value={*($T22*)&st_[ix_%2]} }} + {{ index=21, value={*($T23*)&st_[ix_%2]} }} + {{ index=22, value={*($T24*)&st_[ix_%2]} }} + {{ index=23, value={*($T25*)&st_[ix_%2]} }} + {{ index=24, value={*($T26*)&st_[ix_%2]} }} + {{ index=25, value={*($T27*)&st_[ix_%2]} }} + {{ index=26, value={*($T28*)&st_[ix_%2]} }} + {{ index=27, value={*($T29*)&st_[ix_%2]} }} + {{ index=28, value={*($T30*)&st_[ix_%2]} }} + {{ index=29, value={*($T31*)&st_[ix_%2]} }} + {{ index=30, value={*($T32*)&st_[ix_%2]} }} + {{ index=31, value={*($T33*)&st_[ix_%2]} }} + {{ index=32, value={*($T34*)&st_[ix_%2]} }} + {{ index=33, value={*($T35*)&st_[ix_%2]} }} + {{ index=34, value={*($T36*)&st_[ix_%2]} }} + {{ index=35, value={*($T37*)&st_[ix_%2]} }} + {{ index=36, value={*($T38*)&st_[ix_%2]} }} + {{ index=37, value={*($T39*)&st_[ix_%2]} }} + {{ index=38, value={*($T40*)&st_[ix_%2]} }} + {{ index=39, value={*($T41*)&st_[ix_%2]} }} + + index() + *($T2*)&st_[ix_%2] + *($T3*)&st_[ix_%2] + *($T4*)&st_[ix_%2] + *($T5*)&st_[ix_%2] + *($T6*)&st_[ix_%2] + *($T7*)&st_[ix_%2] + *($T8*)&st_[ix_%2] + *($T9*)&st_[ix_%2] + *($T10*)&st_[ix_%2] + *($T11*)&st_[ix_%2] + *($T12*)&st_[ix_%2] + *($T13*)&st_[ix_%2] + *($T14*)&st_[ix_%2] + *($T15*)&st_[ix_%2] + *($T16*)&st_[ix_%2] + *($T17*)&st_[ix_%2] + *($T18*)&st_[ix_%2] + *($T19*)&st_[ix_%2] + *($T20*)&st_[ix_%2] + *($T21*)&st_[ix_%2] + *($T22*)&st_[ix_%2] + *($T23*)&st_[ix_%2] + *($T24*)&st_[ix_%2] + *($T25*)&st_[ix_%2] + *($T26*)&st_[ix_%2] + *($T27*)&st_[ix_%2] + *($T28*)&st_[ix_%2] + *($T29*)&st_[ix_%2] + *($T30*)&st_[ix_%2] + *($T31*)&st_[ix_%2] + *($T32*)&st_[ix_%2] + *($T33*)&st_[ix_%2] + *($T34*)&st_[ix_%2] + *($T35*)&st_[ix_%2] + *($T36*)&st_[ix_%2] + *($T37*)&st_[ix_%2] + *($T38*)&st_[ix_%2] + *($T39*)&st_[ix_%2] + *($T40*)&st_[ix_%2] + *($T41*)&st_[ix_%2] + + + + diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 0f14659..ed36b26 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -15,17 +15,18 @@ #include #include +#include #include -#include -#include +#include #include #include #include -#include #include -#include // std::hash -#include +#include // std::hash #include +#include +#include +#include // @@ -83,7 +84,7 @@ struct monostate { }; -#if !BOOST_WORKAROUND(BOOST_MSVC, < 1940) +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1950) constexpr bool operator<(monostate, monostate) noexcept { return false; } constexpr bool operator>(monostate, monostate) noexcept { return false; } @@ -685,7 +686,20 @@ template union variant_storage_impl BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_true, mp11::mp_size_t, A&&... a ) { +#if defined(BOOST_GCC) && (__GNUC__ >= 7) +# pragma GCC diagnostic push +// False positive in at least GCC 7 and GCC 10 ASAN triggered by monostate (via result) +# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#if __GNUC__ >= 12 +// False positive in at least GCC 12 and GCC 13 ASAN and -Og triggered by monostate (via result) +# pragma GCC diagnostic ignored "-Wuninitialized" +#endif +#endif *this = variant_storage_impl( mp11::mp_size_t(), std::forward(a)... ); + +#if defined(BOOST_GCC) && (__GNUC__ >= 7) +# pragma GCC diagnostic pop +#endif } template BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t, A&&... a ) @@ -832,6 +846,26 @@ template using resolve_overload_type = typename decltype( o template using resolve_overload_index = mp11::mp_find, resolve_overload_type>; +// index_type + +template using get_smallest_unsigned_type = mp11::mp_cond< + + mp11::mp_bool< N <= (std::numeric_limits::max)() >, unsigned char, + mp11::mp_bool< N <= (std::numeric_limits::max)() >, unsigned short, + mp11::mp_true, unsigned + +>; + +#if BOOST_WORKAROUND( BOOST_CLANG_VERSION, < 30800 ) + +template using get_index_type = unsigned short; + +#else + +template using get_index_type = get_smallest_unsigned_type< (Double + 1) * sizeof...(T) >; + +#endif + // variant_base template struct variant_base_impl; @@ -842,8 +876,10 @@ struct none {}; // trivially destructible, single buffered template struct variant_base_impl { + using index_type = get_index_type; + variant_storage st_; - unsigned ix_; + index_type ix_; constexpr variant_base_impl(): st_( mp11::mp_size_t<0>() ), ix_( 0 ) { @@ -857,6 +893,8 @@ template struct variant_base_impl template void _replace( I, A&&... a ) { ::new( &st_ ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); + + static_assert( I::value + 1 <= (std::numeric_limits::max)(), "" ); ix_ = I::value + 1; } @@ -867,7 +905,7 @@ template struct variant_base_impl template BOOST_CXX14_CONSTEXPR mp11::mp_at_c, I>& _get_impl( mp11::mp_size_t ) noexcept { - size_t const J = I+1; + std::size_t const J = I+1; BOOST_ASSERT( ix_ == J ); @@ -876,7 +914,7 @@ template struct variant_base_impl template constexpr mp11::mp_at_c, I> const& _get_impl( mp11::mp_size_t ) const noexcept { - // size_t const J = I+1; + // std::size_t const J = I+1; BOOST_VARIANT2_CX14_ASSERT( ix_ == I+1 ) @@ -888,6 +926,8 @@ template struct variant_base_impl static_assert( std::is_nothrow_constructible::value, "Logic error: U must be nothrow constructible from A&&..." ); st_.emplace( mp11::mp_size_t(), std::forward(a)... ); + + static_assert( J <= (std::numeric_limits::max)(), "" ); ix_ = J; } @@ -898,6 +938,8 @@ template struct variant_base_impl U tmp( std::forward(a)... ); st_.emplace( mp11::mp_size_t(), std::move(tmp) ); + + static_assert( J <= (std::numeric_limits::max)(), "" ); ix_ = J; } @@ -908,13 +950,20 @@ template struct variant_base_impl this->emplace_impl( std::is_nothrow_constructible(), std::forward(a)... ); } + + static constexpr bool uses_double_storage() noexcept + { + return false; + } }; // trivially destructible, double buffered template struct variant_base_impl { + using index_type = get_index_type; + variant_storage st_[ 2 ]; - unsigned ix_; + index_type ix_; constexpr variant_base_impl(): st_{ { mp11::mp_size_t<0>() }, { mp11::mp_size_t<0>() } }, ix_( 0 ) { @@ -928,6 +977,8 @@ template struct variant_base_impl template void _replace( I, A&&... a ) { ::new( &st_[ 0 ] ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); + + static_assert( ( I::value + 1 ) * 2 <= (std::numeric_limits::max)(), "" ); ix_ = ( I::value + 1 ) * 2; } @@ -940,7 +991,7 @@ template struct variant_base_impl { BOOST_ASSERT( index() == I ); - size_t const J = I+1; + std::size_t const J = I+1; constexpr mp11::mp_size_t j{}; return st_[ ix_ & 1 ].get( j ); @@ -950,7 +1001,7 @@ template struct variant_base_impl { BOOST_VARIANT2_CX14_ASSERT( index() == I ) - // size_t const J = I+1; + // std::size_t const J = I+1; // constexpr mp_size_t j{}; return st_[ ix_ & 1 ].get( mp11::mp_size_t() ); @@ -958,21 +1009,29 @@ template struct variant_base_impl template BOOST_CXX14_CONSTEXPR void emplace( A&&... a ) { - size_t const J = I+1; + std::size_t const J = I+1; unsigned i2 = 1 - ( ix_ & 1 ); st_[ i2 ].emplace( mp11::mp_size_t(), std::forward(a)... ); - ix_ = J * 2 + i2; + static_assert( J * 2 + 1 <= (std::numeric_limits::max)(), "" ); + ix_ = static_cast( J * 2 + i2 ); + } + + static constexpr bool uses_double_storage() noexcept + { + return true; } }; // not trivially destructible, single buffered template struct variant_base_impl { + using index_type = get_index_type; + variant_storage st_; - unsigned ix_; + index_type ix_; constexpr variant_base_impl(): st_( mp11::mp_size_t<0>() ), ix_( 0 ) { @@ -986,6 +1045,8 @@ template struct variant_base_impl template void _replace( I, A&&... a ) { ::new( &st_ ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); + + static_assert( I::value + 1 <= (std::numeric_limits::max)(), "" ); ix_ = I::value + 1; } @@ -1025,7 +1086,7 @@ template struct variant_base_impl template BOOST_CXX14_CONSTEXPR mp11::mp_at_c, I>& _get_impl( mp11::mp_size_t ) noexcept { - size_t const J = I+1; + std::size_t const J = I+1; BOOST_ASSERT( ix_ == J ); @@ -1034,7 +1095,7 @@ template struct variant_base_impl template constexpr mp11::mp_at_c, I> const& _get_impl( mp11::mp_size_t ) const noexcept { - // size_t const J = I+1; + // std::size_t const J = I+1; BOOST_VARIANT2_CX14_ASSERT( ix_ == I+1 ) @@ -1043,7 +1104,7 @@ template struct variant_base_impl template void emplace( A&&... a ) { - size_t const J = I+1; + std::size_t const J = I+1; using U = mp11::mp_at_c, I>; @@ -1054,19 +1115,28 @@ template struct variant_base_impl _destroy(); st_.emplace( mp11::mp_size_t(), std::move(tmp) ); + + static_assert( J <= (std::numeric_limits::max)(), "" ); ix_ = J; } + + static constexpr bool uses_double_storage() noexcept + { + return false; + } }; // not trivially destructible, double buffered template struct variant_base_impl { + using index_type = get_index_type; + #if defined(__GNUC__) && __GNUC__ < 11 && !defined(__clang__) && !defined(__INTEL_COMPILER) // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63707 :-( variant_storage st1_, st2_; - unsigned ix_; + index_type ix_; constexpr variant_base_impl(): st1_( mp11::mp_size_t<0>() ), st2_( mp11::mp_size_t<0>() ), ix_( 0 ) { @@ -1089,7 +1159,7 @@ template struct variant_base_impl #else variant_storage st_[ 2 ]; - unsigned ix_; + index_type ix_; constexpr variant_base_impl(): st_{ { mp11::mp_size_t<0>() }, { mp11::mp_size_t<0>() } }, ix_( 0 ) { @@ -1115,6 +1185,8 @@ template struct variant_base_impl template void _replace( I, A&&... a ) { ::new( &storage( 0 ) ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); + + static_assert( ( I::value + 1 ) * 2 <= (std::numeric_limits::max)(), "" ); ix_ = ( I::value + 1 ) * 2; } @@ -1137,7 +1209,7 @@ template struct variant_base_impl void _destroy() noexcept { - mp11::mp_with_index<1 + sizeof...(T)>( ix_ / 2, _destroy_L1{ this, ix_ & 1 } ); + mp11::mp_with_index<1 + sizeof...(T)>( ix_ / 2, _destroy_L1{ this, static_cast( ix_ & 1 ) } ); } ~variant_base_impl() noexcept @@ -1154,7 +1226,7 @@ template struct variant_base_impl { BOOST_ASSERT( index() == I ); - size_t const J = I+1; + std::size_t const J = I+1; constexpr mp11::mp_size_t j{}; return storage( ix_ & 1 ).get( j ); @@ -1164,7 +1236,7 @@ template struct variant_base_impl { BOOST_VARIANT2_CX14_ASSERT( index() == I ) - // size_t const J = I+1; + // std::size_t const J = I+1; // constexpr mp_size_t j{}; return storage( ix_ & 1 ).get( mp11::mp_size_t() ); @@ -1172,14 +1244,20 @@ template struct variant_base_impl template void emplace( A&&... a ) { - size_t const J = I+1; + std::size_t const J = I+1; unsigned i2 = 1 - ( ix_ & 1 ); storage( i2 ).emplace( mp11::mp_size_t(), std::forward(a)... ); _destroy(); - ix_ = J * 2 + i2; + static_assert( J * 2 + 1 <= (std::numeric_limits::max)(), "" ); + ix_ = static_cast( J * 2 + i2 ); + } + + static constexpr bool uses_double_storage() noexcept + { + return true; } }; @@ -1601,7 +1679,17 @@ template class variant: private detail::variant_ma_base template::type, class E1 = typename std::enable_if< !std::is_same::value && !std::is_base_of::value && !detail::is_in_place_index::value && !detail::is_in_place_type::value >::type, + +#if BOOST_WORKAROUND(BOOST_MSVC, < 1950) + + class V = mp11::mp_apply_q< mp11::mp_bind_front, variant >, + +#else + class V = detail::resolve_overload_type, + +#endif + class E2 = typename std::enable_if::value>::type > constexpr variant( U&& u ) @@ -1691,6 +1779,8 @@ template class variant: private detail::variant_ma_base using variant_base::index; + using variant_base::uses_double_storage; + // swap private: @@ -2080,7 +2170,7 @@ template struct visit_L1 F&& f; V1&& v1; - template auto operator()( I ) const -> Vret + template constexpr auto operator()( I ) const -> Vret { return std::forward(f)( unsafe_get( std::forward(v1) ) ); } @@ -2285,8 +2375,8 @@ namespace detail inline std::size_t hash_value_impl_( mp11::mp_true, std::size_t index, std::size_t value ) { - boost::ulong_long_type hv = ( boost::ulong_long_type( 0xCBF29CE4 ) << 32 ) + 0x84222325; - boost::ulong_long_type const prime = ( boost::ulong_long_type( 0x00000100 ) << 32 ) + 0x000001B3; + unsigned long long hv = 0xCBF29CE484222325ull; + unsigned long long const prime = 0x100000001B3ull; hv ^= index; hv *= prime; @@ -2392,6 +2482,109 @@ template<> struct hash< ::boost::variant2::monostate > } // namespace std +// JSON support + +namespace boost +{ +namespace json +{ + +class value; + +struct value_from_tag; + +template +void value_from( T&& t, value& jv ); + +template +struct try_value_to_tag; + +template +struct result_for; + +template +typename result_for::type +try_value_to( value const & jv ); + +template +typename result_for::type +result_from_errno( int e, boost::source_location const* loc ) noexcept; + +template struct is_null_like; + +template<> struct is_null_like: std::true_type {}; + +} // namespace json + +namespace variant2 +{ + +namespace detail +{ + +struct tag_invoke_L1 +{ + boost::json::value& v; + +#if defined(BOOST_MSVC) && BOOST_MSVC / 10 == 191 + // msvc-14.1 with /permissive- needs this + explicit tag_invoke_L1( boost::json::value& v_ ): v( v_ ) {} +#endif + + template void operator()( T const& t ) const + { + boost::json::value_from( t, v ); + } +}; + +} // namespace detail + +template + void tag_invoke( boost::json::value_from_tag const&, boost::json::value& v, variant const & w ) +{ + visit( detail::tag_invoke_L1{ v }, w ); +} + +namespace detail +{ + +template struct tag_invoke_L2 +{ + boost::json::value const& v; + typename boost::json::result_for::type& r; + + template void operator()( I /*i*/ ) const + { + if( !r ) + { + using Ti = mp11::mp_at_c; + auto r2 = boost::json::try_value_to( v ); + + if( r2 ) + { + r.emplace( in_place_index_t{}, std::move( *r2 ) ); + } + } + } +}; + +} // namespace detail + +template + typename boost::json::result_for, boost::json::value>::type + tag_invoke( boost::json::try_value_to_tag> const&, boost::json::value const& v ) +{ + static constexpr boost::source_location loc = BOOST_CURRENT_LOCATION; + auto r = boost::json::result_from_errno< variant >( EINVAL, &loc ); + + mp11::mp_for_each>( detail::tag_invoke_L2< variant >{ v, r } ); + + return r; +} + +} // namespace variant2 +} // namespace boost + #undef BOOST_VARIANT2_CX14_ASSERT #if defined(_MSC_VER) && _MSC_VER < 1910 diff --git a/test/Jamfile b/test/Jamfile index 2fbb975..0172afc 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -7,7 +7,8 @@ # http://www.boost.org/LICENSE_1_0.txt import testing ; -import ../../config/checks/config : requires ; +import-search /boost/config/checks ; +import config : requires ; project : default-build @@ -16,11 +17,14 @@ project : requirements - [ requires cxx11_variadic_templates cxx11_template_aliases cxx11_decltype cxx11_constexpr ] + /boost/variant2//boost_variant2 + /boost/core//boost_core + /boost/container_hash//boost_container_hash msvc:on gcc:on clang:on + ; run quick.cpp ; @@ -56,10 +60,10 @@ run variant_in_place_type_construct.cpp ; compile variant_in_place_type_construct_cx.cpp : msvc-14.0:no ; run variant_copy_assign.cpp ; -compile variant_copy_assign_cx.cpp : [ requires cxx14_constexpr ] ; +compile variant_copy_assign_cx.cpp : [ requires cxx14_constexpr ] gcc-5:no gcc-6:no ; run variant_move_assign.cpp ; -compile variant_move_assign_cx.cpp : [ requires cxx14_constexpr ] ; +compile variant_move_assign_cx.cpp : [ requires cxx14_constexpr ] gcc-5:no gcc-6:no ; run variant_value_assign.cpp ; compile variant_value_assign_cx.cpp : [ requires cxx14_constexpr ] ; @@ -126,3 +130,30 @@ run variant_visit_by_index.cpp ; run variant_ostream_insert.cpp ; run is_output_streamable.cpp ; + +local JSON = /boost/json//boost_json/off "msvc-14.0:no" "msvc-14.2:-wd5104" "norecover:static" ; + +run variant_json_value_from.cpp : : : $(JSON) ; +run variant_json_value_to.cpp : : : $(JSON) ; + +compile variant_uses_double_storage.cpp ; + +run variant_derived_construct2.cpp ; + +compile variant_visit_cx.cpp : [ requires cxx14_constexpr ] ; +compile variant_visit_cx_2.cpp : [ requires cxx14_constexpr ] ; +compile variant_visit_r_cx.cpp : [ requires cxx14_constexpr ] ; + +local index-type-reqs = + + release + msvc,32:no + clang,linux:-ftemplate-depth=1024 # for Clang 3.x +; + +local list-sizes = 126 127 128 129 254 255 256 257 ; + +for local list-size in $(list-sizes) +{ + run variant_index_type.cpp : : : $(index-type-reqs) LIST_SIZE=$(list-size) : variant_index_type_$(list-size) ; +} diff --git a/test/cmake_install_test/CMakeLists.txt b/test/cmake_install_test/CMakeLists.txt index 62a1176..a91bc4c 100644 --- a/test/cmake_install_test/CMakeLists.txt +++ b/test/cmake_install_test/CMakeLists.txt @@ -14,4 +14,4 @@ target_link_libraries(quick Boost::variant2) enable_testing() add_test(quick quick) -add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $) +add_custom_target(check VERBATIM COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $) diff --git a/test/cmake_subdir_test/CMakeLists.txt b/test/cmake_subdir_test/CMakeLists.txt index 036030b..c887c7a 100644 --- a/test/cmake_subdir_test/CMakeLists.txt +++ b/test/cmake_subdir_test/CMakeLists.txt @@ -18,4 +18,4 @@ target_link_libraries(quick Boost::variant2) enable_testing() add_test(quick quick) -add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $) +add_custom_target(check VERBATIM COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $) diff --git a/test/variant_derived_construct2.cpp b/test/variant_derived_construct2.cpp new file mode 100644 index 0000000..31488aa --- /dev/null +++ b/test/variant_derived_construct2.cpp @@ -0,0 +1,60 @@ +// Copyright 2024 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include + +struct expr: boost::variant2::variant +{ + using variant::variant; +}; + +int main() +{ + using boost::variant2::get; + + { + expr v{ true }; + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), true ); + } + + { + expr v{ 2 }; + + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 2 ); + } + + { + expr v{ 3.0 }; + + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 3.0 ); + } + + { + expr v( true ); + + BOOST_TEST_EQ( v.index(), 0 ); + BOOST_TEST_EQ( get<0>(v), true ); + } + + { + expr v( 2 ); + + BOOST_TEST_EQ( v.index(), 1 ); + BOOST_TEST_EQ( get<1>(v), 2 ); + } + + { + expr v( 3.0 ); + + BOOST_TEST_EQ( v.index(), 2 ); + BOOST_TEST_EQ( get<2>(v), 3.0 ); + } + + return boost::report_errors(); +} diff --git a/test/variant_emplace_index.cpp b/test/variant_emplace_index.cpp index 340cbcb..6aececa 100644 --- a/test/variant_emplace_index.cpp +++ b/test/variant_emplace_index.cpp @@ -288,5 +288,39 @@ int main() BOOST_TEST_EQ( Z1::instances, 0 ); BOOST_TEST_EQ( Z2::instances, 0 ); + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + + v.emplace<0>(); + BOOST_TEST_EQ( v.index(), 0 ); + + v.emplace<1>(); + BOOST_TEST_EQ( v.index(), 1 ); + + v.emplace<1>(); + BOOST_TEST_EQ( v.index(), 1 ); + + v.emplace<0>(); + BOOST_TEST_EQ( v.index(), 0 ); + } + + { + variant v; + BOOST_TEST_EQ( v.index(), 0 ); + + v.emplace<0>(); + BOOST_TEST_EQ( v.index(), 0 ); + + v.emplace<1>(); + BOOST_TEST_EQ( v.index(), 1 ); + + v.emplace<1>(); + BOOST_TEST_EQ( v.index(), 1 ); + + v.emplace<0>(); + BOOST_TEST_EQ( v.index(), 0 ); + } + return boost::report_errors(); } diff --git a/test/variant_get_by_index_cx.cpp b/test/variant_get_by_index_cx.cpp index 026b9d3..949e39c 100644 --- a/test/variant_get_by_index_cx.cpp +++ b/test/variant_get_by_index_cx.cpp @@ -58,7 +58,7 @@ int main() { constexpr variant v( 3.14f ); - STATIC_ASSERT( get<1>(v) == 3.14f ); + STATIC_ASSERT( get<1>(v) == (float)3.14f ); // see FLT_EVAL_METHOD STATIC_ASSERT_IF( get_if<0>(&v) == nullptr ); STATIC_ASSERT_IF( get_if<1>(&v) == &get<1>(v) ); @@ -87,7 +87,7 @@ int main() { constexpr variant v( 3.14f ); - STATIC_ASSERT( get<2>(v) == 3.14f ); + STATIC_ASSERT( get<2>(v) == (float)3.14f ); STATIC_ASSERT_IF( get_if<0>(&v) == nullptr ); STATIC_ASSERT_IF( get_if<1>(&v) == nullptr ); diff --git a/test/variant_get_by_type_cx.cpp b/test/variant_get_by_type_cx.cpp index 0f9a40c..d2777c8 100644 --- a/test/variant_get_by_type_cx.cpp +++ b/test/variant_get_by_type_cx.cpp @@ -58,7 +58,7 @@ int main() { constexpr variant v( 3.14f ); - STATIC_ASSERT( get(v) == 3.14f ); + STATIC_ASSERT( get(v) == (float)3.14f ); // see FLT_EVAL_METHOD STATIC_ASSERT_IF( get_if(&v) == nullptr ); STATIC_ASSERT_IF( get_if(&v) == &get(v) ); @@ -83,7 +83,7 @@ int main() { constexpr variant v( 3.14f ); - STATIC_ASSERT( get(v) == 3.14f ); + STATIC_ASSERT( get(v) == (float)3.14f ); STATIC_ASSERT_IF( get_if(&v) == &get(v) ); } diff --git a/test/variant_in_place_index_construct_cx.cpp b/test/variant_in_place_index_construct_cx.cpp index ea4b3ab..c8d85fe 100644 --- a/test/variant_in_place_index_construct_cx.cpp +++ b/test/variant_in_place_index_construct_cx.cpp @@ -68,7 +68,7 @@ int main() constexpr variant v( in_place_index_t<1>{}, 3.14f ); STATIC_ASSERT( v.index() == 1 ); - STATIC_ASSERT( get<1>(v) == 3.14f ); + STATIC_ASSERT( get<1>(v) == (float)3.14f ); // see FLT_EVAL_METHOD } { @@ -89,14 +89,14 @@ int main() constexpr variant v( in_place_index_t<2>{}, 3.14f ); STATIC_ASSERT( v.index() == 2 ); - STATIC_ASSERT( get<2>(v) == 3.14f ); + STATIC_ASSERT( get<2>(v) == (float)3.14f ); } { constexpr variant v( in_place_index_t<3>{}, 3.14f ); STATIC_ASSERT( v.index() == 3 ); - STATIC_ASSERT( get<3>(v) == 3.14f ); + STATIC_ASSERT( get<3>(v) == (float)3.14f ); } { diff --git a/test/variant_in_place_type_construct_cx.cpp b/test/variant_in_place_type_construct_cx.cpp index 832de3d..a9a8e4e 100644 --- a/test/variant_in_place_type_construct_cx.cpp +++ b/test/variant_in_place_type_construct_cx.cpp @@ -80,7 +80,7 @@ int main() constexpr variant v( in_place_type_t{}, 3.14f ); STATIC_ASSERT( v.index() == 1 ); - STATIC_ASSERT( get<1>(v) == 3.14f ); + STATIC_ASSERT( get<1>(v) == (float)3.14f ); // see FLT_EVAL_METHOD STATIC_ASSERT( holds_alternative(v) ); } @@ -89,7 +89,7 @@ int main() constexpr variant v( in_place_type_t{}, 3.14f ); STATIC_ASSERT( v.index() == 2 ); - STATIC_ASSERT( get<2>(v) == 3.14f ); + STATIC_ASSERT( get<2>(v) == (float)3.14f ); STATIC_ASSERT( holds_alternative(v) ); } diff --git a/test/variant_index_type.cpp b/test/variant_index_type.cpp new file mode 100644 index 0000000..5e123ad --- /dev/null +++ b/test/variant_index_type.cpp @@ -0,0 +1,86 @@ +// Copyright 2024 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#if defined(_MSC_VER) +# pragma warning( disable: 4503 ) // decorated name length exceeded +#endif + +#include +#include +#include + +using namespace boost::mp11; + +template struct X +{ +}; + +template using Xf = X< N::value >; + +template struct Y +{ + Y() = default; + Y( Y&& ) {} +}; + +template using Yf = Y< N::value >; + +template struct Z +{ + ~Z() {} +}; + +template using Zf = Z< N::value >; + +template struct W +{ + ~W() {} + + W() = default; + W( W&& ) {} +}; + +template using Wf = W< N::value >; + +template class F> void test() +{ + using V = mp_rename< mp_transform, boost::variant2::variant >; + + constexpr std::size_t N = mp_size::value; + + using last_type = F>; + + { + V v( last_type{} ); + BOOST_TEST_EQ( v.index(), N-1 ); + } + + { + V v; + BOOST_TEST_EQ( v.index(), 0 ); + + v.template emplace(); + BOOST_TEST_EQ( v.index(), N-1 ); + } +} + +int main() +{ + constexpr std::size_t N = LIST_SIZE; + using L = mp_iota_c; + + static_assert( !boost::variant2::variant< X<0>, X<1> >::uses_double_storage(), "" ); + test(); + + static_assert( boost::variant2::variant< Y<0>, Y<1> >::uses_double_storage(), "" ); + test(); + + static_assert( !boost::variant2::variant< Z<0>, Z<1> >::uses_double_storage(), "" ); + test(); + + static_assert( boost::variant2::variant< W<0>, W<1> >::uses_double_storage(), "" ); + test(); + + return boost::report_errors(); +} diff --git a/test/variant_json_value_from.cpp b/test/variant_json_value_from.cpp new file mode 100644 index 0000000..be5dc3a --- /dev/null +++ b/test/variant_json_value_from.cpp @@ -0,0 +1,47 @@ +// Copyright 2022 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include + +#if defined(BOOST_GCC) && BOOST_GCC < 50000 +# define BOOST_ALLOW_DEPRECATED +#endif + +#include +#include +#include +#include +#include + +using namespace boost::variant2; +namespace json = boost::json; + +int main() +{ + { + monostate m; + json::value w = json::value_from( m ); + BOOST_TEST_EQ( w, json::value( nullptr ) ); + } + + { + variant v; + json::value w = json::value_from( v ); + BOOST_TEST_EQ( w, json::value( nullptr ) ); + } + + { + variant v( 17 ); + json::value w = json::value_from( v ); + BOOST_TEST_EQ( w, json::value( 17 ) ); + } + + { + variant v( "test" ); + json::value w = json::value_from( v ); + BOOST_TEST_EQ( w, json::value( "test" ) ); + } + + return boost::report_errors(); +} diff --git a/test/variant_json_value_to.cpp b/test/variant_json_value_to.cpp new file mode 100644 index 0000000..5b42cc0 --- /dev/null +++ b/test/variant_json_value_to.cpp @@ -0,0 +1,48 @@ +// Copyright 2022 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include + +#if defined(BOOST_GCC) && BOOST_GCC < 50000 +# define BOOST_ALLOW_DEPRECATED +#endif + +#include +#include +#include +#include + +using namespace boost::variant2; +namespace json = boost::json; + +int main() +{ + { + json::value v; + auto r = json::try_value_to( v ); + BOOST_TEST( r.has_value() ); + } + + using V = variant; + + { + json::value v; + auto r = json::try_value_to( v ); + BOOST_TEST( r.has_value() ) && BOOST_TEST_EQ( *r, V() ); + } + + { + json::value v( 12 ); + auto r = json::try_value_to( v ); + BOOST_TEST( r.has_value() ) && BOOST_TEST_EQ( *r, V(12) ); + } + + { + json::value v( "test" ); + auto r = json::try_value_to( v ); + BOOST_TEST( r.has_value() ) && BOOST_TEST_EQ( *r, V("test") ); + } + + return boost::report_errors(); +} diff --git a/test/variant_uses_double_storage.cpp b/test/variant_uses_double_storage.cpp new file mode 100644 index 0000000..d78efc6 --- /dev/null +++ b/test/variant_uses_double_storage.cpp @@ -0,0 +1,50 @@ +// Copyright 2023 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include + +using namespace boost::variant2; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +struct X1 +{ +}; + +STATIC_ASSERT( std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( std::is_trivially_destructible::value ); + +struct X2 +{ + ~X2() {} +}; + +STATIC_ASSERT( std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( !std::is_trivially_destructible::value ); + +struct X3 +{ + X3( X3&& ) {} +}; + +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( std::is_trivially_destructible::value ); + +struct X4 +{ + ~X4() {} + X4( X4&& ) {} +}; + +STATIC_ASSERT( !std::is_nothrow_move_constructible::value ); +STATIC_ASSERT( !std::is_trivially_destructible::value ); + +// + +STATIC_ASSERT( !variant::uses_double_storage() ); +STATIC_ASSERT( !variant::uses_double_storage() ); +STATIC_ASSERT( !variant::uses_double_storage() ); +STATIC_ASSERT( variant::uses_double_storage() ); +STATIC_ASSERT( variant::uses_double_storage() ); diff --git a/test/variant_value_construct_cx.cpp b/test/variant_value_construct_cx.cpp index 5ffad25..e055569 100644 --- a/test/variant_value_construct_cx.cpp +++ b/test/variant_value_construct_cx.cpp @@ -82,7 +82,7 @@ int main() STATIC_ASSERT( v.index() == 1 ); STATIC_ASSERT( holds_alternative(v) ); - STATIC_ASSERT( get<1>(v) == 3.14f ); + STATIC_ASSERT( get<1>(v) == (float)3.14f ); // see FLT_EVAL_METHOD } { @@ -97,7 +97,7 @@ int main() STATIC_ASSERT( v.index() == 2 ); STATIC_ASSERT( holds_alternative(v) ); - STATIC_ASSERT( get<2>(v) == 3.14f ); + STATIC_ASSERT( get<2>(v) == (float)3.14f ); } { diff --git a/test/variant_visit_cx.cpp b/test/variant_visit_cx.cpp new file mode 100644 index 0000000..4646242 --- /dev/null +++ b/test/variant_visit_cx.cpp @@ -0,0 +1,51 @@ +// Copyright 2017, 2024 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#include +using namespace boost::variant2; + +#if !defined(BOOST_MP11_HAS_CXX14_CONSTEXPR) + +#include + +BOOST_PRAGMA_MESSAGE("Skipping constexpr visit test because BOOST_MP11_HAS_CXX14_CONSTEXPR is not defined") + +int main() {} + +#else + +struct X +{ + constexpr operator int() const { return 2; } +}; + +struct F +{ + constexpr int operator()( int x ) const + { + return x; + } +}; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +int main() +{ + { + constexpr variant v( 1 ); + STATIC_ASSERT( visit( F(), v ) == 1 ); + } + + { + constexpr variant v( 'a' ); + STATIC_ASSERT( visit( F(), v ) == 'a' ); + } + + { + constexpr variant v( X{} ); + STATIC_ASSERT( visit( F(), v ) == 2 ); + } +} + +#endif diff --git a/test/variant_visit_cx_2.cpp b/test/variant_visit_cx_2.cpp new file mode 100644 index 0000000..65c5d30 --- /dev/null +++ b/test/variant_visit_cx_2.cpp @@ -0,0 +1,53 @@ +// Copyright 2017, 2024 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#include +#include + +#if !( defined(__cpp_constexpr) && __cpp_constexpr >= 201603L ) + +BOOST_PRAGMA_MESSAGE("Skipping constexpr visit test because __cpp_constexpr < 201603L") +int main() {} + +#elif !defined(BOOST_MP11_HAS_CXX14_CONSTEXPR) + +BOOST_PRAGMA_MESSAGE("Skipping constexpr visit test because BOOST_MP11_HAS_CXX14_CONSTEXPR is not defined") +int main() {} + +#else + +using namespace boost::variant2; + +struct F +{ + constexpr int operator()( int x1, int x2 ) const + { + return x1 + x2; + } + + constexpr int operator()( int x1, int x2, int x3 ) const + { + return x1 + x2 + x3; + } +}; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +int main() +{ + { + constexpr variant v1( 1 ); + constexpr variant v2( '2' ); + STATIC_ASSERT( visit( F(), v1, v2 ) == 1 + '2' ); + } + + { + constexpr variant v1( 1 ); + constexpr variant v2( 2 ); + constexpr variant v3( '3' ); + STATIC_ASSERT( visit( F(), v1, v2, v3 ) == 1 + 2 + '3' ); + } +} + +#endif diff --git a/test/variant_visit_r.cpp b/test/variant_visit_r.cpp index 15ab60a..5dd01fc 100644 --- a/test/variant_visit_r.cpp +++ b/test/variant_visit_r.cpp @@ -61,18 +61,18 @@ int main() } { - variant const v( 3.14f ); + variant const v( 3.125f ); BOOST_TEST_EQ( visit( F1(), v ), 3 ); - BOOST_TEST_EQ( visit( F1(), v ), 3.14f ); + BOOST_TEST_EQ( visit( F1(), v ), 3.125f ); } { variant v1( 1 ); - variant const v2( 3.14f ); + variant const v2( 3.125f ); BOOST_TEST_EQ( visit( F2(), v1, v2 ), 4 ); - BOOST_TEST_EQ( visit( F2(), v1, v2 ), 1 + 3.14f ); + BOOST_TEST_EQ( visit( F2(), v1, v2 ), 1 + 3.125f ); } { diff --git a/test/variant_visit_r_cx.cpp b/test/variant_visit_r_cx.cpp new file mode 100644 index 0000000..83672b6 --- /dev/null +++ b/test/variant_visit_r_cx.cpp @@ -0,0 +1,52 @@ +// Copyright 2017, 2024 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt + +#include +using namespace boost::variant2; + +#if !defined(BOOST_MP11_HAS_CXX14_CONSTEXPR) + +#include + +BOOST_PRAGMA_MESSAGE("Skipping constexpr visit test because BOOST_MP11_HAS_CXX14_CONSTEXPR is not defined") + +int main() {} + +#else + +struct X +{ + int v; + constexpr operator int() const { return v; } +}; + +struct F +{ + template constexpr T operator()( T x ) const + { + return x; + } +}; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +int main() +{ + { + constexpr variant v( 1 ); + STATIC_ASSERT( visit( F(), v ) == 1 ); + } + + { + constexpr variant v( 'a' ); + STATIC_ASSERT( visit( F(), v ) == 'a' ); + } + + { + constexpr variant v( X{2} ); + STATIC_ASSERT( visit( F(), v ) == 2 ); + } +} + +#endif