commit 406b929fc56912a873fd2556e1ded32f9184af05 Author: Vinnie Falco Date: Mon Sep 9 13:56:14 2019 -0700 Initial commit diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000..01985bd --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,147 @@ +# Copyright 2016, 2017 Peter Dimov +# Copyright (C) 2017 - 2019 James E. King III +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +# +# Generic Appveyor build script for boostorg repositories +# See: https://github.com/boostorg/boost-ci/ +# +# Instructions for customizing this script for your library: +# +# 1. Customize the compilers and language levels you want. +# 2. If you have more than include/, src/, test/, example/, examples/, +# benchmark/ or tools/ directories, set the environment variable DEPINST. +# For example if your build uses code in "bench/" and "fog/" directories: +# - DEPINST: --include bench --include fog +# 3. Enable pull request builds in your boostorg/ account. +# +# That's it - the script will do everything else for you. +# + +version: 1.0.{build}-{branch} + +shallow_clone: true + +branches: + only: + - master + - develop + - /bugfix\/.*/ + - /feature\/.*/ + - /fix\/.*/ + - /pr\/.*/ + +matrix: + # Adding MAYFAIL to any matrix job allows it to fail but the build stays green: + allow_failures: + - MAYFAIL: true + +environment: + global: + # see: http://www.boost.org/build/doc/html/bbv2/overview/invocation.html#bbv2.overview.invocation.properties + # to use the default for a given environment, comment it out; recommend you build debug and release however: + # on Windows it is important to exercise all the possibilities, especially shared vs static, however most + # libraries that care about this exercise it in their Jamfiles... + # B2_ADDRESS_MODEL: address-model=64,32 + # B2_LINK: link=shared,static + # B2_THREADING: threading=multi,single + B2_VARIANT: variant=release + + matrix: + - FLAVOR: Visual Studio 2019 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + B2_ADDRESS_MODEL: address-model=64 + B2_CXXFLAGS: cxxflags=-permissive- + B2_CXXSTD: latest # 2a + B2_TOOLSET: msvc-14.2 + + - FLAVOR: Visual Studio 2017 C++2a Strict + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + B2_ADDRESS_MODEL: address-model=64 + B2_CXXFLAGS: cxxflags=-permissive- + B2_CXXSTD: latest # 2a + B2_TOOLSET: msvc-14.1 + + - FLAVOR: Visual Studio 2017 C++17 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + B2_ADDRESS_MODEL: address-model=64 + B2_CXXSTD: 17 + B2_TOOLSET: msvc-14.1 + B2_VARIANT: variant=debug + + - FLAVOR: Visual Studio 2017 C++14 (Default) + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + B2_ADDRESS_MODEL: address-model=64,32 + B2_TOOLSET: msvc-14.1 + + - FLAVOR: clang-cl + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + B2_ADDRESS_MODEL: address-model=64 + B2_CXXSTD: 11 + B2_TOOLSET: clang-win + + - FLAVOR: Visual Studio 2015 C++14 (Default) + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + B2_ADDRESS_MODEL: address-model=64,32 + B2_TOOLSET: msvc-14.0 + B2_VARIANT: variant=debug + + - FLAVOR: Visual Studio 2010, 2012, 2013 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + B2_TOOLSET: msvc-10.0,msvc-11.0,msvc-12.0 + + - FLAVOR: cygwin (32-bit) + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + ADDPATH: C:\cygwin\bin; + B2_ADDRESS_MODEL: address-model=32 + B2_CXXSTD: 03,11 + # https://github.com/boostorg/test/issues/144 + B2_DEFINES: define=_POSIX_C_SOURCE=200112L + B2_THREADING: threadapi=pthread + B2_TOOLSET: gcc + B2_VARIANT: variant=debug + + - FLAVOR: cygwin (64-bit) + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + ADDPATH: C:\cygwin64\bin; + B2_ADDRESS_MODEL: address-model=64 + B2_CXXSTD: 11,17 + # https://github.com/boostorg/test/issues/144 + B2_DEFINES: define=_POSIX_C_SOURCE=200112L define=__USE_ISOC99 + B2_THREADING: threadapi=pthread + B2_TOOLSET: gcc + + - FLAVOR: mingw32 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + ARCH: i686 + B2_ADDRESS_MODEL: address-model=32 + B2_CXXSTD: 03,11 + SCRIPT: ci\appveyor\mingw.bat + B2_VARIANT: variant=debug + + - FLAVOR: mingw64 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + ARCH: x86_64 + B2_ADDRESS_MODEL: address-model=64 + B2_CXXSTD: 11,17 + B2_DEFINES: define=__USE_ISOC99 + SCRIPT: ci\appveyor\mingw.bat + +install: + - set SELF=%APPVEYOR_PROJECT_NAME:-=_% + - git clone https://github.com/boostorg/boost-ci.git C:\boost-ci + - xcopy /s /e /q /i C:\boost-ci\ci .\ci + - ci\appveyor\install.bat + +build: off + +test_script: + - set SELF=%APPVEYOR_PROJECT_NAME:-=_% + - PATH=%ADDPATH%%PATH% + # The definition of B2_TOOLCXX omits B2_CXXSTD= if it was not defined above + - IF NOT DEFINED B2_CXXSTD (SET B2_TOOLCXX=toolset=%B2_TOOLSET%) ELSE (SET B2_TOOLCXX=toolset=%B2_TOOLSET% cxxstd=%B2_CXXSTD%) + # Echo the complete build command to the build log + - IF NOT DEFINED SCRIPT (ECHO b2 libs/%SELF:\=/% %B2_TOOLCXX% %B2_CXXFLAGS% %B2_DEFINES% %B2_THREADING% %B2_ADDRESS_MODEL% %B2_LINK% %B2_THREADING% %B2_VARIANT% -j3) + # Now go build... + - IF DEFINED SCRIPT (call libs\%SELF%\%SCRIPT%) ELSE (b2 libs/%SELF:\=/% %B2_TOOLCXX% %B2_CXXFLAGS% %B2_DEFINES% %B2_THREADING% %B2_ADDRESS_MODEL% %B2_LINK% %B2_THREADING% %B2_VARIANT% -j3) diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml new file mode 100644 index 0000000..d958e52 --- /dev/null +++ b/.azure-pipelines.yml @@ -0,0 +1,311 @@ +# Copyright 2015-2019 Rene Rivera. +# Copyright 2019 Mateusz Loskot +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +# +# Generic Azure Pipelines build script for boostorg repositories +# See: https://github.com/boostorg/boost-ci/ +# +# Instructions for customizing this script for your library: +# +# 1. Customize the compilers and language levels you want. +# 2. If you have more than include/, src/, test/, example/, examples/, +# benchmark/ or tools/ directories, set the environment variable DEPINST. +# For example if your build uses code in "bench/" and "fog/" directories: +# - DEPINST: --include bench --include fog +# 3. Enable pull request builds in your boostorg/ account. +# +# That's it - the script will do everything else for you. + +trigger: + branches: + include: + - develop + - master + - bugfix/* + - feature/* + - fix/* + - pr/* + +pr: + branches: + include: + - develop + +variables: + - name: B2_VARIANT + value: variant=release,debug + +stages: + +- stage: Test + jobs: + + - job: 'Linux' + pool: + vmImage: 'ubuntu-16.04' + strategy: + matrix: + GCC 8: + B2_TOOLSET: gcc + B2_CXXSTD: 14,17,2a + CXX: g++-8 + PACKAGES: g++-8 + GCC 7: + B2_TOOLSET: gcc + B2_CXXSTD: 11,14,17 + CXX: g++-7 + PACKAGES: g++-7 + GCC 6: + B2_TOOLSET: gcc + B2_CXXSTD: 11,14 + CXX: g++-6 + PACKAGES: g++-6 + GCC 5: + B2_TOOLSET: gcc + B2_CXXSTD: 11 + CXX: g++-5 + PACKAGES: g++-5 + GCC 4.9: + B2_TOOLSET: gcc + B2_CXXSTD: 03,11 + CXX: g++-4.9 + PACKAGES: g++-4.9 + GCC 4.8: + B2_TOOLSET: gcc + B2_CXXSTD: 03,11 + CXX: g++-4.8 + PACKAGES: g++-4.8 + Clang 8: + B2_TOOLSET: clang + B2_CXXSTD: 14,17,2a + CXX: clang++-8 + PACKAGES: clang-8 + LLVM_REPO: llvm-toolchain-xenial-8 + Clang 7: + B2_TOOLSET: clang + B2_CXXSTD: 14,17,2a + CXX: clang++-7 + PACKAGES: clang-7 + LLVM_REPO: llvm-toolchain-xenial-7 + Clang 6: + B2_TOOLSET: clang + B2_CXXSTD: 03,11,14,17,2a + B2_CXXFLAGS: -stdlib=libc++ + CXX: clang++-6.0 + PACKAGES: clang-6.0 + LLVM_REPO: llvm-toolchain-xenial-6.0 + Clang 6: + B2_TOOLSET: clang + B2_CXXSTD: 14,17,2a + CXX: clang++-6.0 + PACKAGES: clang-6.0 + LLVM_REPO: llvm-toolchain-xenial-6.0 + Clang 5: + B2_TOOLSET: clang + B2_CXXSTD: 11,14,17 + PACKAGES: clang-5.0 + CXX: clang++-5.0 + LLVM_REPO: llvm-toolchain-xenial-5.0 + Clang 4: + B2_TOOLSET: clang + B2_CXXSTD: 11,14,17 + CXX: clang++-4.0 + PACKAGES: clang-4.0 + LLVM_REPO: llvm-toolchain-xenial-4.0 + Clang 3.9: + B2_TOOLSET: clang + B2_CXXSTD: 03,11,14 + CXX: clang++-3.9 + PACKAGES: clang-3.9 + Clang 3.8: + B2_TOOLSET: clang + CXX: clang++-3.8 + B2_CXXSTD: 03,11,14 + PACKAGES: clang-3.8 + Clang 3.7: + B2_TOOLSET: clang + B2_CXXSTD: 03,11 + CXX: clang++-3.7 + PACKAGES: clang-3.7 + Clang 3.6: + B2_TOOLSET: clang + B2_CXXSTD: 03,11 + CXX: clang++-3.6 + PACKAGES: clang-3.6 + Clang 3.5: + B2_TOOLSET: clang + B2_CXXSTD: 03,11 + CXX: clang++-3.5 + PACKAGES: clang-3.5 + steps: + - bash: | + set -e + uname -a + sudo -E apt-add-repository -y "ppa:ubuntu-toolchain-r/test" + if test -n "${LLVM_REPO}" ; then + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + sudo -E apt-add-repository "deb http://apt.llvm.org/xenial/ ${LLVM_REPO} main" + fi + sudo -E apt-get update + sudo -E apt-get -yq --no-install-suggests --no-install-recommends install ${PACKAGES} + + git clone --branch master https://github.com/boostorg/boost-ci.git boost-ci + cp -pr boost-ci/ci boost-ci/.codecov.yml . + rm -rf boost-ci + source ci/azure-pipelines/install.sh + + # AzP requires to run special task in order to export + # SELF and BOOST_ROOT as job-scoped variable from a script. + # NOTE: Disable set -x is necessary, see the troubleshooting guide + # on "Variables having ' (single quote) appended": + # https://docs.microsoft.com/en-us/azure/devops/pipelines/troubleshooting + set +x + echo "##vso[task.setvariable variable=SELF]"$SELF + echo "##vso[task.setvariable variable=BOOST_ROOT]"$BOOST_ROOT + set -x + displayName: 'Install' + - bash: | + set -e + echo "SELF=$SELF" + echo "BOOST_ROOT=$BOOST_ROOT" + + cd $BOOST_ROOT/libs/$SELF + ci/azure-pipelines/build.sh --debug-configuration + displayName: 'Build' + + - job: 'Windows' + strategy: + matrix: + VS 2019 C++2a Strict: + B2_TOOLSET: msvc-14.2 + B2_CXXSTD: latest # 2a + B2_CXXFLAGS: cxxflags=-permissive- + B2_ADDRESS_MODEL: address-model=64 + VM_IMAGE: 'windows-2019' + VS 2017 C++2a Strict: + B2_TOOLSET: msvc-14.1 + B2_CXXSTD: latest # 2a + B2_CXXFLAGS: cxxflags=-permissive- + B2_ADDRESS_MODEL: address-model=64 + VM_IMAGE: 'vs2017-win2016' + VS 2017 C++17: + B2_TOOLSET: msvc-14.1 + B2_CXXSTD: 17 + B2_ADDRESS_MODEL: address-model=64,32 + VM_IMAGE: 'vs2017-win2016' + VS 2017 C++14: + B2_TOOLSET: msvc-14.1 + #B2_CXXSTD: 14 # default + B2_ADDRESS_MODEL: address-model=64,32 + VM_IMAGE: 'vs2017-win2016' + VS 2015 C++14: + B2_TOOLSET: msvc-14.0 + #B2_CXXSTD: 14 # default + B2_ADDRESS_MODEL: address-model=64,32 + VM_IMAGE: 'vs2015-win2012r2' + + pool: + vmImage: $(VM_IMAGE) + steps: + - script: | + set SELF=%BUILD_REPOSITORY_NAME:-=_% + for /f "tokens=2 delims=/" %%a in ("%SELF%") do set SELF=%%a + set BOOST_ROOT=%BUILD_SOURCESDIRECTORY%\boost-root + + git clone --branch master https://github.com/boostorg/boost-ci.git boost-ci + xcopy /s /e /q /i boost-ci\ci .\ci + cmd /k ci\azure-pipelines\install.bat + + echo ##vso[task.setvariable variable=SELF]%SELF% + echo ##vso[task.setvariable variable=BOOST_ROOT]%BOOST_ROOT% + displayName: 'Install' + - script: | + PATH=%ADDPATH%%PATH% + REM The definition of B2_TOOLCXX omits B2_CXXSTD= if it was not defined above + IF NOT DEFINED B2_CXXSTD (SET B2_TOOLCXX=toolset=%B2_TOOLSET%) ELSE (SET B2_TOOLCXX=toolset=%B2_TOOLSET% cxxstd=%B2_CXXSTD%) + cd %BOOST_ROOT% + ECHO b2 libs/%SELF:\=/% %B2_TOOLCXX% %B2_CXXFLAGS% %B2_DEFINES% %B2_THREADING% %B2_ADDRESS_MODEL% %B2_LINK% %B2_THREADING% %B2_VARIANT% -j3 + b2 libs/%SELF:\=/% %B2_TOOLCXX% %B2_CXXFLAGS% %B2_DEFINES% %B2_THREADING% %B2_ADDRESS_MODEL% %B2_LINK% %B2_THREADING% %B2_VARIANT% -j3 + displayName: 'Build' + + - job: 'macOS' + pool: + vmImage: 'macOS-10.13' + strategy: + matrix: + Xcode 10.1: + B2_TOOLSET: clang + B2_CXXSTD: 14,17,2a + XCODE_APP: /Applications/Xcode_10.1.app + Xcode 10.0: + B2_TOOLSET: clang + B2_CXXSTD: 14,17,2a + XCODE_APP: /Applications/Xcode_10.app + Xcode 9.4.1: + B2_TOOLSET: clang + B2_CXXSTD: 11,14,17 + XCODE_APP: /Applications/Xcode_9.4.1.app + Xcode 9.4: + B2_TOOLSET: clang + B2_CXXSTD: 11,14,17 + XCODE_APP: /Applications/Xcode_9.4.app + Xcode 9.3.1: + B2_TOOLSET: clang + B2_CXXSTD: 11,14,17 + XCODE_APP: /Applications/Xcode_9.3.1.app + Xcode 9.3: + B2_TOOLSET: clang + B2_CXXSTD: 11,14 + XCODE_APP: /Applications/Xcode_9.3.app + Xcode 9.2: + B2_TOOLSET: clang + B2_CXXSTD: 11,14 + XCODE_APP: /Applications/Xcode_9.2.app + Xcode 9.1: + B2_TOOLSET: clang + B2_CXXSTD: 03,11 + XCODE_APP: /Applications/Xcode_9.1.app + Xcode 9.0.1: + B2_TOOLSET: clang + B2_CXXSTD: 03,11 + XCODE_APP: /Applications/Xcode_9.0.1.app + Xcode 9.0: + B2_TOOLSET: clang + B2_CXXSTD: 03,11 + XCODE_APP: /Applications/Xcode_9.app + Xcode 8.3.3: + B2_TOOLSET: clang + B2_CXXSTD: 03,11 + XCODE_APP: /Applications/Xcode_8.3.3.app + steps: + - bash: | + set -e + uname -a + sudo xcode-select -switch ${XCODE_APP} + which clang++ + + git clone --branch master https://github.com/boostorg/boost-ci.git boost-ci + cp -pr boost-ci/ci boost-ci/.codecov.yml . + rm -rf boost-ci + source ci/azure-pipelines/install.sh + + # AzP requires to run special task in order to export + # SELF and BOOST_ROOT as job-scoped variable from a script. + # NOTE: Disable set -x is necessary, see the troubleshooting guide + # on "Variables having ' (single quote) appended": + # https://docs.microsoft.com/en-us/azure/devops/pipelines/troubleshooting + set +x + echo "##vso[task.setvariable variable=SELF]"$SELF + echo "##vso[task.setvariable variable=BOOST_ROOT]"$BOOST_ROOT + set -x + displayName: Install + - bash: | + set -e + echo "SELF=$SELF" + echo "BOOST_ROOT=$BOOST_ROOT" + + cd $BOOST_ROOT/libs/$SELF + ci/azure-pipelines/build.sh --debug-configuration + displayName: 'Build' diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8d9c734 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,12 @@ +# Set default behaviour, in case users don't have core.autocrlf set. +* text=auto + +# Github +.md text eol=lf + +# Visual Studio +*.sln text eol=crlf +*.vcproj text eol=crlf +*.vcxproj text eol=crlf +*.props text eol=crlf +*.filters text eol=crlf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1740b53 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +bin/ +bin64/ + +# Because of CMake and VS2017 +Win32/ +x64/ + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..9448b7c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,236 @@ +# Copyright 2016 Peter Dimov +# Copyright 2017 - 2019 James E. King III +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +# +# Generic Travis CI build script for boostorg repositories +# See: https://github.com/boostorg/boost-ci +# +# Instructions for customizing this script for your library: +# +# 1. Customize the compilers and language levels you want in the 'jobs'. +# 2. If you have more than include/, src/, test/, example/, examples/, or +# tools/ directories, modify your Travis CI project and add the environment +# variable DEPINST. For example if your build uses code in "bench/" and +# "fog/" directories, then set DEPINST to the following: +# --include bench --include fog +# 3. If you want to enable Coverity Scan, you need to provide the environment +# variables COVERITY_SCAN_TOKEN and COVERITY_SCAN_NOTIFICATION_EMAIL in +# your github settings. +# 4. If you want to enable a big-endian build, you need to uncomment the +# big-endian build job. +# 5. Enable pull request builds in your boostorg/ account. +# +# That's it - the scripts will do everything else for you. + +dist: xenial +language: cpp + +env: + global: + # see: http://www.boost.org/build/doc/html/bbv2/overview/invocation.html#bbv2.overview.invocation.properties + # - B2_ADDRESS_MODEL=address-model=64,32 + # - B2_LINK=link=shared,static + # - B2_THREADING=threading=multi,single + - B2_VARIANT=variant=release + +install: + - git clone https://github.com/boostorg/boost-ci.git boost-ci + - cp -pr boost-ci/ci boost-ci/.codecov.yml . + - source ci/travis/install.sh + +addons: + apt: + packages: + - binutils-gold + - gdb + - libc6-dbg + - qemu-user-static + +services: + - docker + +branches: + only: + - master + - develop + - /bugfix\/.*/ + - /feature\/.*/ + - /fix\/.*/ + - /pr\/.*/ + +script: + - cd $BOOST_ROOT/libs/$SELF + - ci/travis/build.sh + +# +# Default toolsets in Ubuntu +# +# trusty xenial bionic +# 14.04 16.04 18.04 +# ------ ------ ------ +# clang 3.4 3.8 6.0 +# gcc 4.8.2 5.3.1 7.3.0 +# + +anchors: + clang-38: &clang-38 { apt: { packages: [ "clang-3.8", + "libstdc++-6-dev" ], sources: [ "llvm-toolchain-xenial-3.8", + "ubuntu-toolchain-r-test" ] } } + clang-4: &clang-4 { apt: { packages: [ "clang-4.0", + "libstdc++-6-dev" ], sources: [ "llvm-toolchain-xenial-4.0", + "ubuntu-toolchain-r-test" ] } } + clang-5: &clang-5 { apt: { packages: [ "clang-5.0", + "libstdc++-7-dev" ], sources: [ "llvm-toolchain-xenial-5.0", + "ubuntu-toolchain-r-test" ] } } + clang-6: &clang-6 { apt: { packages: [ "clang-6.0", + "libc6-dbg", + "libc++-dev", + "libstdc++-8-dev" ], sources: [ "llvm-toolchain-xenial-6.0", + "ubuntu-toolchain-r-test" ] } } + clang-7: &clang-7 { apt: { packages: [ "clang-7", + "libc6-dbg", + "libc++-dev", + "libstdc++-8-dev" ], sources: [ "llvm-toolchain-xenial-7", + "ubuntu-toolchain-r-test" ] } } + clang-8: &clang-8 { apt: { packages: [ "clang-8", + "libc6-dbg", + "libc++-dev", + "libstdc++-8-dev" ], sources: [ "llvm-toolchain-xenial-8", + "ubuntu-toolchain-r-test" ] } } + gcc-48: &gcc-48 { apt: { packages: [ "g++-4.8" ] } } + gcc-49: &gcc-49 { apt: { packages: [ "g++-4.9" ], sources: [ "ubuntu-toolchain-r-test" ] } } + gcc-5: &gcc-5 { apt: { packages: [ "g++-5" ] } } + gcc-6: &gcc-6 { apt: { packages: [ "g++-6" ], sources: [ "ubuntu-toolchain-r-test" ] } } + gcc-7: &gcc-7 { apt: { packages: [ "g++-7" ], sources: [ "ubuntu-toolchain-r-test" ] } } + gcc-8: &gcc-8 { apt: { packages: [ "g++-8" ], sources: [ "ubuntu-toolchain-r-test" ] } } + gcc-9: &gcc-9 { apt: { packages: [ "g++-9" ], sources: [ "ubuntu-toolchain-r-test" ] } } + +jobs: + allow_failures: + - env: + - COPY="all the environment settings from your job" + + include: + # coverage + - os: linux + env: + - COMMENT=codecov.io + - B2_CXXSTD=11 + - B2_TOOLSET=gcc-8 + - B2_DEFINES="define=BOOST_NO_STRESS_TEST=1" + addons: *gcc-8 + script: + - cd $BOOST_ROOT/libs/$SELF + - ci/travis/codecov.sh + + - os: linux + env: + - COMMENT=asan + - B2_VARIANT=variant=debug + - B2_TOOLSET=gcc-8 + - B2_CXXSTD=11,14 + - B2_CXXFLAGS="address-sanitizer=norecover" + - B2_DEFINES="define=BOOST_NO_STRESS_TEST=1" + addons: *gcc-8 + + - os: linux + env: + - COMMENT=tsan + - B2_VARIANT=variant=debug + - B2_TOOLSET=gcc-8 + - B2_CXXSTD=11,14 + - B2_CXXFLAGS="thread-sanitizer=norecover" + - B2_DEFINES="define=BOOST_NO_STRESS_TEST=1" + addons: *gcc-8 + + - os: linux + env: + - COMMENT=ubsan + - B2_VARIANT=variant=debug + - B2_TOOLSET=gcc-8 + - B2_CXXSTD=11,14 + - B2_CXXFLAGS="undefined-sanitizer=norecover" + - B2_DEFINES="define=BOOST_NO_STRESS_TEST=1" + - B2_LINKFLAGS="linkflags=-fuse-ld=gold" + - UBSAN_OPTIONS=print_stacktrace=1 + addons: *gcc-8 + + - os: linux + env: + - COMMENT=valgrind + - B2_TOOLSET=clang-6.0 + - B2_CXXSTD=11,14 + - B2_DEFINES="define=BOOST_NO_STRESS_TEST=1" + - B2_VARIANT=variant=debug + - B2_TESTFLAGS=testing.launcher=valgrind + - VALGRIND_OPTS=--error-exitcode=1 + addons: *clang-6 + script: + - cd $BOOST_ROOT/libs/$SELF + - ci/travis/valgrind.sh + + # libstdc++ + - { os: "linux", dist: "trusty", # xenial has libstdc++ from gcc 5.4.0 with newer ABI + env: [ "B2_TOOLSET=gcc-4.8", "B2_CXXSTD=11" ], addons: *gcc-48 } + - { os: "linux", dist: "trusty", # xenial has libstdc++ from gcc 5.4.0 with newer ABI + env: [ "B2_TOOLSET=gcc-4.9", "B2_CXXSTD=11" ], addons: *gcc-49 } + - { os: "linux", env: [ "B2_TOOLSET=gcc-5", "B2_CXXSTD=11" ], addons: *gcc-5 } + - { os: "linux", env: [ "B2_TOOLSET=gcc-6", "B2_CXXSTD=11,14" ], addons: *gcc-6 } + - { os: "linux", env: [ "B2_TOOLSET=gcc-7", "B2_CXXSTD=14,17" ], addons: *gcc-7 } + - { os: "linux", env: [ "B2_TOOLSET=gcc-8", "B2_CXXSTD=17,2a" ], addons: *gcc-8 } + - { os: "linux", env: [ "B2_TOOLSET=gcc-9", "B2_CXXSTD=17,2a" ], addons: *gcc-9 } + - { os: "linux", dist: "trusty", # xenial has libstdc++ from gcc 5.4.0 with newer ABI + env: [ "B2_TOOLSET=clang-3.8", "B2_CXXSTD=11" ], addons: *clang-38 } + - { os: "linux", env: [ "B2_TOOLSET=clang-4.0", "B2_CXXSTD=11,14" ], addons: *clang-4 } + - { os: "linux", env: [ "B2_TOOLSET=clang-5.0", "B2_CXXSTD=11,14" ], addons: *clang-5 } + - { os: "linux", env: [ "B2_TOOLSET=clang-6.0", "B2_CXXSTD=14,17" ], addons: *clang-6 } + - { os: "linux", env: [ "B2_TOOLSET=clang-7", "B2_CXXSTD=17,2a" ], addons: *clang-7 } + - { os: "linux", env: [ "B2_TOOLSET=clang-8", "B2_CXXSTD=17,2a" ], addons: *clang-8 } + + # libc++ + - { os: "linux", env: [ "B2_TOOLSET=clang-6.0", "B2_CXXSTD=11,14", + "B2_CXXFLAGS=-stdlib=libc++" ], addons: *clang-6 } + - { os: "osx" , env: [ "B2_TOOLSET=clang", "B2_CXXSTD=11,17" ] } + + # to enable Intel ICC define INTEL_ICC_SERIAL_NUMBER and the following (under development): + # - { os: "linux", env: [ "B2_TOOLSET=intel-linux", "B2_CXXSTD=11,14,17" ], addons: *gcc-7, + # script: cd $BOOST_ROOT/libs/$SELF && ci/travis/intelicc.sh } + + # uncomment to enable a big-endian build job, just note that it is 5-10 times slower + # than a regular build and travis has a 50 minute time limit per job + # - os: linux + # env: + # - COMMENT=big-endian + # - B2_CXXSTD=03 + # - B2_TOOLSET=gcc + # - B2_DEFINES="define=BOOST_NO_STRESS_TEST=1" + # - BDDE_OS=red + # - BDDE_ARCH=ppc64 + # script: + # - cd $BOOST_ROOT/libs/$SELF + # - ci/travis/bdde.sh + + # - os: linux + # env: + # - COMMENT=cppcheck + # script: + # - cd $BOOST_ROOT/libs/$SELF + # - ci/travis/cppcheck.sh + + #################### Jobs to run on pushes to master, develop ################### + + # Coverity Scan + - os: linux + if: (env(COVERITY_SCAN_NOTIFICATION_EMAIL) IS present) AND (branch IN (develop, master)) AND (type IN (cron, push)) + env: + - COMMENT="Coverity Scan" + - B2_TOOLSET=clang + script: + - cd $BOOST_ROOT/libs/$SELF + - ci/travis/coverity.sh + +notifications: + email: + false diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..99b9474 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1 @@ +-------------------------------------------------------------------------------- diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..da12f05 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,152 @@ +# +# Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# +# Official repository: https://github.com/boostorg/fixed_string +# + +cmake_minimum_required (VERSION 3.5.1) + +if (POLICY CMP0074) + cmake_policy (SET CMP0074 NEW) +endif() + +#------------------------------------------------------------------------------- + +function (DoGroupSources curdir rootdir folder) + file (GLOB children RELATIVE ${PROJECT_SOURCE_DIR}/${curdir} ${PROJECT_SOURCE_DIR}/${curdir}/*) + foreach (child ${children}) + if (IS_DIRECTORY ${PROJECT_SOURCE_DIR}/${curdir}/${child}) + DoGroupSources (${curdir}/${child} ${rootdir} ${folder}) + elseif (${child} STREQUAL "CMakeLists.txt") + source_group("" FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child}) + else() + string (REGEX REPLACE ^${rootdir} ${folder} groupname ${curdir}) + string (REPLACE "/" "\\" groupname ${groupname}) + source_group (${groupname} FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child}) + endif() + endforeach() +endfunction() + +function (GroupSources curdir folder) + DoGroupSources (${curdir} ${curdir} ${folder}) +endfunction() + +#------------------------------------------------------------------------------- +# +# FixedString +# +#------------------------------------------------------------------------------- + +project (FixedString VERSION 1) + +set_property (GLOBAL PROPERTY USE_FOLDERS ON) + +if (MSVC) + set (CMAKE_VERBOSE_MAKEFILE FALSE) + + add_definitions ( + -D_WIN32_WINNT=0x0601 + ) + + add_compile_options( + /permissive- # strict C++ + /W4 # enable all warnings + /MP # Multi-processor compilation + ) + + set (Boost_USE_STATIC_LIBS ON) + set (Boost_USE_STATIC_RUNTIME ON) + + set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") + set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /Oi /Ot /GL /MT") + set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Oi /Ot /MT") + + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") + + # for RelWithDebInfo builds, disable incremental linking + # since CMake sets it ON by default for that build type and it + # causes warnings + # + string (REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" replacement_flags + ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}) + set (CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO ${replacement_flags}) + +else() + set (THREADS_PREFER_PTHREAD_FLAG ON) + find_package (Threads) + + set( CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -Wpedantic -Wno-unused-parameter") + + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wrange-loop-analysis") + endif () +endif() + +# Must come before Boost includes, otherwise the +# IDE sees the wrong file due to boost/ symlinks. +include_directories (include) + +#------------------------------------------------------------------------------- +# +# Boost +# +#------------------------------------------------------------------------------- + +get_filename_component (BOOST_ROOT ../../ ABSOLUTE) + +# VFALCO I want static but "b2 stage" builds a minimal set which excludes static +add_definitions (-DBOOST_ALL_STATIC_LINK=1) + +include_directories (${BOOST_ROOT}) + +link_directories(${BOOST_ROOT}/stage/lib) + +#------------------------------------------------------------------------------- + +if ("${VARIANT}" STREQUAL "coverage") + if (MSVC) + else() + set (CMAKE_BUILD_TYPE DEBUG) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.2 --coverage") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage") + endif() + +elseif ("${VARIANT}" STREQUAL "ubasan") + if (MSVC) + else() + set (CMAKE_BUILD_TYPE RELWITHDEBINFO) + set (CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} -msse4.2 -funsigned-char -fno-omit-frame-pointer -fsanitize=address,undefined -fno-sanitize-recover=address,undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/tools/blacklist.supp") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address,undefined -fno-sanitize-recover=address,undefined") + endif() + +elseif ("${VARIANT}" STREQUAL "debug") + set (CMAKE_BUILD_TYPE DEBUG) + +elseif ("${VARIANT}" STREQUAL "release") + set (CMAKE_BUILD_TYPE RELEASE) + +endif() + +#------------------------------------------------------------------------------- + +#GroupSources (test "/") + +#------------------------------------------------------------------------------- +# +# Tests and examples +# + +#include_directories (.) + +file (GLOB_RECURSE PROJECT_FILES + ${PROJECT_SOURCE_DIR}/include/boost/fixed_string/*.hpp + ${PROJECT_SOURCE_DIR}/include/boost/fixed_string/*.ipp +) + +add_subdirectory (test) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..f20c98a --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,9 @@ +# Code of Conduct + +* Be respectful of others + +* Please use professional conduct + +* Treat others the way you want to be treated + +Thank you! diff --git a/Jamfile b/Jamfile new file mode 100644 index 0000000..d72c265 --- /dev/null +++ b/Jamfile @@ -0,0 +1,45 @@ +# +# Copyright (c) 2019 Vinnie Falco (vinnie dot falco at gmail dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# +# Official repository: https://github.com/boostorg/beast +# + +import ac ; +import os ; +import feature ; +import boost ; +import modules ; +import testing ; +import ../../config/checks/config : requires ; + +boost.use-project ; + +local defines = + [ requires + cxx11_constexpr + cxx11_decltype + cxx11_hdr_tuple + cxx11_template_aliases + cxx11_variadic_templates + ] + /boost//headers + . + BOOST_ALL_NO_LIB=1 + msvc-14.1:"/permissive-" + msvc-14.2:"/permissive-" + msvc,release:"/Ob2 /Oi /Ot" + windows:_WIN32_WINNT=0x0601 + ; + +project /boost/fixed_string + : requirements + static + $(defines) + : usage-requirements + $(defines) + ; + +build-project test ; diff --git a/LICENSE_1_0.txt b/LICENSE_1_0.txt new file mode 100644 index 0000000..36b7cd9 --- /dev/null +++ b/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..dd3158b --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# Boost.FixedString + +Branch | Travis | Appveyor | Azure Pipelines | codecov.io | Docs | Matrix | +:-------------: | ------ | -------- | --------------- | ---------- | ---- | ------ | +[`master`](https://github.com/boostorg/fixed_string/tree/master) | [![Build Status](https://travis-ci.org/boostorg/fixed_string.svg?branch=master)](https://travis-ci.org/boostorg/fixed_string) | [![Build status](https://ci.appveyor.com/api/projects/status/github/boostorg/fixed_string?branch=master&svg=true)](https://ci.appveyor.com/project/maintainer/fixed_string-xyzzy/branch/master) | [![Build Status](https://dev.azure.com/maintainer/fixed_string/_apis/build/status/pipeline?branchName=master)](https://dev.azure.com/maintainer/fixed_string/_build/latest?definitionId=6&branchName=master) | [![codecov](https://codecov.io/gh/boostorg/fixed_string/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/fixed_string/branch/master) | [![Documentation](https://img.shields.io/badge/docs-master-brightgreen.svg)](http://www.boost.org/doc/libs/master/doc/html/fixed_string.html) | [![Matrix](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/fixed_string.html) +[`develop`](https://github.com/boostorg/fixed_string/tree/develop) | [![Build Status](https://travis-ci.org/boostorg/fixed_string.svg?branch=develop)](https://travis-ci.org/boostorg/fixed_string) | [![Build status](https://ci.appveyor.com/api/projects/status/github/boostorg/fixed_string?branch=develop&svg=true)](https://ci.appveyor.com/project/maintainer/fixed_string-xyzzy/branch/develop) | [![Build Status](https://dev.azure.com/maintainer/fixed_string/_apis/build/status/pipeline?branchName=develop)](https://dev.azure.com/maintainer/fixed_string/_build/latest?definitionId=6&branchName=master) | [![codecov](https://codecov.io/gh/boostorg/fixed_string/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/fixed_string/branch/develop) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/develop/doc/html/fixed_string.html) | [![Matrix](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/fixed_string.html) + +This is currently **NOT** an official Boost library. diff --git a/include/boost/fixed_string/config.hpp b/include/boost/fixed_string/config.hpp new file mode 100644 index 0000000..834ad5f --- /dev/null +++ b/include/boost/fixed_string/config.hpp @@ -0,0 +1,29 @@ +// +// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/fixed_string +// + +#ifndef BOOST_FIXED_STRING_CONFIG_HPP +#define BOOST_FIXED_STRING_CONFIG_HPP + +#include + +namespace boost { +namespace fixed_string { + +/// The type of `string_view` used by the library +using string_view = boost::string_view; + +/// The type of `basic_string_view` used by the library +template +using basic_string_view = + boost::basic_string_view; + +} // fixed_string +} // boost + +#endif diff --git a/include/boost/fixed_string/detail/fixed_string.hpp b/include/boost/fixed_string/detail/fixed_string.hpp new file mode 100644 index 0000000..5c8863d --- /dev/null +++ b/include/boost/fixed_string/detail/fixed_string.hpp @@ -0,0 +1,133 @@ +// +// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/fixed_string +// + +#ifndef BOOST_FIXED_STRING_DETAIL_FIXED_STRING_HPP +#define BOOST_FIXED_STRING_DETAIL_FIXED_STRING_HPP + +#include +#include +#include +#include + +namespace boost { +namespace fixed_string { +namespace detail { + +// Because k-ballo said so +template +using is_input_iterator = + std::integral_constant::value>; + +template +int +lexicographical_compare( + CharT const* s1, std::size_t n1, + CharT const* s2, std::size_t n2) +{ + if(n1 < n2) + return Traits::compare( + s1, s2, n1) <= 0 ? -1 : 1; + if(n1 > n2) + return Traits::compare( + s1, s2, n2) >= 0 ? 1 : -1; + return Traits::compare(s1, s2, n1); +} + +template +int +lexicographical_compare( + basic_string_view s1, + CharT const* s2, std::size_t n2) +{ + return detail::lexicographical_compare< + CharT, Traits>(s1.data(), s1.size(), s2, n2); +} + +template +int +lexicographical_compare( + basic_string_view s1, + basic_string_view s2) +{ + return detail::lexicographical_compare( + s1.data(), s1.size(), s2.data(), s2.size()); +} + +// Maximum number of characters in the decimal +// representation of a binary number. This includes +// the potential minus sign. +// +inline +std::size_t constexpr +max_digits(std::size_t bytes) +{ + return static_cast( + bytes * 2.41) + 1 + 1; +} + +template +CharT* +raw_to_string( + CharT* buf, Integer x, std::true_type) +{ + if(x == 0) + { + Traits::assign(*--buf, '0'); + return buf; + } + if(x < 0) + { + x = -x; + for(;x > 0; x /= 10) + Traits::assign(*--buf , + "0123456789"[x % 10]); + Traits::assign(*--buf, '-'); + return buf; + } + for(;x > 0; x /= 10) + Traits::assign(*--buf , + "0123456789"[x % 10]); + return buf; +} + +template +CharT* +raw_to_string( + CharT* buf, Integer x, std::false_type) +{ + if(x == 0) + { + *--buf = '0'; + return buf; + } + for(;x > 0; x /= 10) + Traits::assign(*--buf , + "0123456789"[x % 10]); + return buf; +} + +template< + class CharT, + class Integer, + class Traits = std::char_traits> +CharT* +raw_to_string(CharT* last, std::size_t size, Integer i) +{ + boost::ignore_unused(size); + BOOST_ASSERT(size >= max_digits(sizeof(Integer))); + return raw_to_string( + last, i, std::is_signed{}); +} + +} // detail +} // fixed_string +} // boost + +#endif diff --git a/include/boost/fixed_string/fixed_string.hpp b/include/boost/fixed_string/fixed_string.hpp new file mode 100644 index 0000000..d8eb013 --- /dev/null +++ b/include/boost/fixed_string/fixed_string.hpp @@ -0,0 +1,1113 @@ +// +// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/fixed_string +// + +#ifndef BOOST_FIXED_STRING_FIXED_STRING_HPP +#define BOOST_FIXED_STRING_FIXED_STRING_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace fixed_string { + +/** A modifiable string with a fixed-size storage area. + + These objects behave like `std::string` except that the storage + is not dynamically allocated but rather fixed in size. + + These strings offer performance advantages when a protocol + imposes a natural small upper limit on the size of a value. + + @note The stored string is always null-terminated. + + @see to_fixed_string +*/ +template< + std::size_t N, + class CharT = char, + class Traits = std::char_traits> +class fixed_string +{ + template + friend class fixed_string; + + void + term() + { + Traits::assign(s_[n_], 0); + } + + std::size_t n_; + CharT s_[N+1]; + +public: + // + // Member types + // + + using traits_type = Traits; + using value_type = typename Traits::char_type; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + using const_pointer = value_type const*; + using const_reference = value_type const&; + using iterator = value_type*; + using const_iterator = value_type const*; + using reverse_iterator = + std::reverse_iterator; + using const_reverse_iterator = + std::reverse_iterator; + + /// The type of `string_view` returned by the interface + using string_view_type = + basic_string_view; + + // + // Constants + // + + /// Maximum size of the string excluding the null terminator + static std::size_t constexpr max_size_n = N; + + /// A special index + static constexpr size_type npos = size_type(-1); + + // + // (constructor) + // + + /// Default constructor (empty string). + fixed_string(); + + /** Construct with count copies of character `ch`. + + The behavior is undefined if `count >= npos` + */ + fixed_string(size_type count, CharT ch); + + /// Construct with a substring (pos, other.size()) of `other`. + template + fixed_string(fixed_string const& other, + size_type pos); + + /// Construct with a substring (pos, count) of `other`. + template + fixed_string(fixed_string const& other, + size_type pos, size_type count); + + /// Construct with the first `count` characters of `s`, including nulls. + fixed_string(CharT const* s, size_type count); + + /// Construct from a null terminated string. + fixed_string(CharT const* s); + + /// Construct from a range of characters + template + fixed_string(InputIt first, InputIt last); + + /// Copy constructor. + fixed_string(fixed_string const& other); + + /// Copy constructor. + template + fixed_string(fixed_string const& other); + + /// Construct from an initializer list + fixed_string(std::initializer_list init); + + /// Construct from a `string_view` + explicit + fixed_string(string_view_type sv); + + /** Construct from any object convertible to `string_view_type`. + + The range (pos, n) is extracted from the value + obtained by converting `t` to `string_view_type`, + and used to construct the string. + */ +#if BOOST_BEAST_DOXYGEN + template +#else + template::value>::type> +#endif + fixed_string(T const& t, size_type pos, size_type n); + + // + // (assignment) + // + + /// Copy assignment. + fixed_string& + operator=(fixed_string const& str) + { + return assign(str); + } + + /// Copy assignment. + template + fixed_string& + operator=(fixed_string const& str) + { + return assign(str); + } + + /// Assign from null-terminated string. + fixed_string& + operator=(CharT const* s); + + /// Assign from single character. + fixed_string& + operator=(CharT ch) + { + return assign_char(ch, + std::integral_constant0)>{}); + } + + /// Assign from initializer list. + fixed_string& + operator=(std::initializer_list init) + { + return assign(init); + } + + /// Assign from `string_view_type`. + fixed_string& + operator=(string_view_type sv) + { + return assign(sv); + } + + /// Assign `count` copies of `ch`. + fixed_string& + assign(size_type count, CharT ch); + + /// Assign from another `fixed_string` + fixed_string& + assign(fixed_string const& str); + + // VFALCO NOTE this could come in two flavors, + // N>M and NM + + /// Assign from another `fixed_string` + template + fixed_string& + assign(fixed_string const& str) + { + return assign(str.data(), str.size()); + } + + /// Assign `count` characterss starting at `npos` from `other`. + template + fixed_string& + assign(fixed_string const& str, + size_type pos, size_type count = npos); + + /// Assign the first `count` characters of `s`, including nulls. + fixed_string& + assign(CharT const* s, size_type count); + + /// Assign a null terminated string. + fixed_string& + assign(CharT const* s) + { + return assign(s, Traits::length(s)); + } + + /// Assign from an iterator range of characters. + template + fixed_string& + assign(InputIt first, InputIt last); + + /// Assign from initializer list. + fixed_string& + assign(std::initializer_list init) + { + return assign(init.begin(), init.end()); + } + + /// Assign from `string_view_type`. + fixed_string& + assign(string_view_type str) + { + return assign(str.data(), str.size()); + } + + /** Assign from any object convertible to `string_view_type`. + + The range (pos, n) is extracted from the value + obtained by converting `t` to `string_view_type`, + and used to assign the string. + */ + template +#if BOOST_BEAST_DOXYGEN + fixed_string& +#else + typename std::enable_if::value, fixed_string&>::type +#endif + assign(T const& t, + size_type pos, size_type count = npos); + + // + // Element access + // + + /// Access specified character with bounds checking. + reference + at(size_type pos); + + /// Access specified character with bounds checking. + const_reference + at(size_type pos) const; + + /// Access specified character. + reference + operator[](size_type pos) + { + return s_[pos]; + } + + /// Access specified character. + const_reference + operator[](size_type pos) const + { + return s_[pos]; + } + + /// Accesses the first character. + CharT& + front() + { + return s_[0]; + } + + /// Accesses the first character. + CharT const& + front() const + { + return s_[0]; + } + + /// Accesses the last character. + CharT& + back() + { + return s_[n_-1]; + } + + /// Accesses the last character. + CharT const& + back() const + { + return s_[n_-1]; + } + + /// Returns a pointer to the first character of a string. + CharT* + data() + { + return &s_[0]; + } + + /// Returns a pointer to the first character of a string. + CharT const* + data() const + { + return &s_[0]; + } + + /// Returns a non-modifiable standard C character array version of the string. + CharT const* + c_str() const + { + return data(); + } + + /// Convert a static string to a `string_view_type` + operator string_view_type() const + { + return basic_string_view< + CharT, Traits>{data(), size()}; + } + + // + // Iterators + // + + /// Returns an iterator to the beginning. + iterator + begin() + { + return &s_[0]; + } + + /// Returns an iterator to the beginning. + const_iterator + begin() const + { + return &s_[0]; + } + + /// Returns an iterator to the beginning. + const_iterator + cbegin() const + { + return &s_[0]; + } + + /// Returns an iterator to the end. + iterator + end() + { + return &s_[n_]; + } + + /// Returns an iterator to the end. + const_iterator + end() const + { + return &s_[n_]; + } + + /// Returns an iterator to the end. + const_iterator + cend() const + { + return &s_[n_]; + } + + /// Returns a reverse iterator to the beginning. + reverse_iterator + rbegin() + { + return reverse_iterator{end()}; + } + + /// Returns a reverse iterator to the beginning. + const_reverse_iterator + rbegin() const + { + return const_reverse_iterator{cend()}; + } + + /// Returns a reverse iterator to the beginning. + const_reverse_iterator + crbegin() const + { + return const_reverse_iterator{cend()}; + } + + /// Returns a reverse iterator to the end. + reverse_iterator + rend() + { + return reverse_iterator{begin()}; + } + + /// Returns a reverse iterator to the end. + const_reverse_iterator + rend() const + { + return const_reverse_iterator{cbegin()}; + } + + /// Returns a reverse iterator to the end. + const_reverse_iterator + crend() const + { + return const_reverse_iterator{cbegin()}; + } + + // + // Capacity + // + + /// Returns `true` if the string is empty. + bool + empty() const + { + return n_ == 0; + } + + /// Returns the number of characters, excluding the null terminator. + size_type + size() const + { + return n_; + } + + /// Returns the number of characters, excluding the null terminator. + size_type + length() const + { + return size(); + } + + /// Returns the maximum number of characters that can be stored, excluding the null terminator. + size_type constexpr + max_size() const + { + return N; + } + + /** Reserves storage. + + This actually just throws an exception if `n > N`, + otherwise does nothing since the storage is fixed. + */ + void + reserve(std::size_t n); + + /// Returns the number of characters that can be held in currently allocated storage. + size_type constexpr + capacity() const + { + return max_size(); + } + + /** Reduces memory usage by freeing unused memory. + + This actually does nothing, since the storage is fixed. + */ + void + shrink_to_fit() + { + } + + // + // Operations + // + + /// Clears the contents. + void + clear(); + + fixed_string& + insert(size_type index, size_type count, CharT ch); + + fixed_string& + insert(size_type index, CharT const* s) + { + return insert(index, s, Traits::length(s)); + } + + fixed_string& + insert(size_type index, CharT const* s, size_type count); + + template + fixed_string& + insert(size_type index, + fixed_string const& str) + { + return insert(index, str.data(), str.size()); + } + + template + fixed_string& + insert(size_type index, + fixed_string const& str, + size_type index_str, size_type count = npos); + + iterator + insert(const_iterator pos, CharT ch) + { + return insert(pos, 1, ch); + } + + iterator + insert(const_iterator pos, size_type count, CharT ch); + + template +#if BOOST_BEAST_DOXYGEN + iterator +#else + typename std::enable_if< + detail::is_input_iterator::value, + iterator>::type +#endif + insert(const_iterator pos, InputIt first, InputIt last); + + iterator + insert(const_iterator pos, std::initializer_list init) + { + return insert(pos, init.begin(), init.end()); + } + + fixed_string& + insert(size_type index, string_view_type str) + { + return insert(index, str.data(), str.size()); + } + + template +#if BOOST_BEAST_DOXYGEN + fixed_string& +#else + typename std::enable_if< + std::is_convertible::value && + ! std::is_convertible::value, + fixed_string&>::type +#endif + insert(size_type index, T const& t, + size_type index_str, size_type count = npos); + + fixed_string& + erase(size_type index = 0, size_type count = npos); + + iterator + erase(const_iterator pos); + + iterator + erase(const_iterator first, const_iterator last); + + void + push_back(CharT ch); + + void + pop_back() + { + Traits::assign(s_[--n_], 0); + } + + fixed_string& + append(size_type count, CharT ch) + { + insert(end(), count, ch); + return *this; + } + + template + fixed_string& + append(fixed_string const& str) + { + insert(size(), str); + return *this; + } + + template + fixed_string& + append(fixed_string const& str, + size_type pos, size_type count = npos); + + fixed_string& + append(CharT const* s, size_type count) + { + insert(size(), s, count); + return *this; + } + + fixed_string& + append(CharT const* s) + { + insert(size(), s); + return *this; + } + + template +#if BOOST_BEAST_DOXYGEN + fixed_string& +#else + typename std::enable_if< + detail::is_input_iterator::value, + fixed_string&>::type +#endif + append(InputIt first, InputIt last) + { + insert(end(), first, last); + return *this; + } + + fixed_string& + append(std::initializer_list init) + { + insert(end(), init); + return *this; + } + + fixed_string& + append(string_view_type sv) + { + insert(size(), sv); + return *this; + } + + template + typename std::enable_if< + std::is_convertible::value && + ! std::is_convertible::value, + fixed_string&>::type + append(T const& t, size_type pos, size_type count = npos) + { + insert(size(), t, pos, count); + return *this; + } + + template + fixed_string& + operator+=(fixed_string const& str) + { + return append(str.data(), str.size()); + } + + fixed_string& + operator+=(CharT ch) + { + push_back(ch); + return *this; + } + + fixed_string& + operator+=(CharT const* s) + { + return append(s); + } + + fixed_string& + operator+=(std::initializer_list init) + { + return append(init); + } + + fixed_string& + operator+=(string_view_type const& str) + { + return append(str); + } + + template + int + compare(fixed_string const& str) const + { + return detail::lexicographical_compare( + &s_[0], n_, &str.s_[0], str.n_); + } + + template + int + compare(size_type pos1, size_type count1, + fixed_string const& str) const + { + return detail::lexicographical_compare( + substr(pos1, count1), str.data(), str.size()); + } + + template + int + compare(size_type pos1, size_type count1, + fixed_string const& str, + size_type pos2, size_type count2 = npos) const + { + return detail::lexicographical_compare( + substr(pos1, count1), str.substr(pos2, count2)); + } + + int + compare(CharT const* s) const + { + return detail::lexicographical_compare( + &s_[0], n_, s, Traits::length(s)); + } + + int + compare(size_type pos1, size_type count1, + CharT const* s) const + { + return detail::lexicographical_compare( + substr(pos1, count1), s, Traits::length(s)); + } + + int + compare(size_type pos1, size_type count1, + CharT const*s, size_type count2) const + { + return detail::lexicographical_compare( + substr(pos1, count1), s, count2); + } + + int + compare(string_view_type str) const + { + return detail::lexicographical_compare( + &s_[0], n_, str.data(), str.size()); + } + + int + compare(size_type pos1, size_type count1, + string_view_type str) const + { + return detail::lexicographical_compare( + substr(pos1, count1), str); + } + + template +#if BOOST_BEAST_DOXYGEN + int +#else + typename std::enable_if< + std::is_convertible::value && + ! std::is_convertible::value, + int>::type +#endif + compare(size_type pos1, size_type count1, + T const& t, size_type pos2, + size_type count2 = npos) const + { + return compare(pos1, count1, + string_view_type(t).substr(pos2, count2)); + } + + string_view_type + substr(size_type pos = 0, size_type count = npos) const; + + /// Copy a substring (pos, pos+count) to character string pointed to by `dest`. + size_type + copy(CharT* dest, size_type count, size_type pos = 0) const; + + /** Changes the number of characters stored. + + If the resulting string is larger, the new + characters are uninitialized. + */ + void + resize(std::size_t n); + + /** Changes the number of characters stored. + + If the resulting string is larger, the new + characters are initialized to the value of `c`. + */ + void + resize(std::size_t n, CharT c); + + /// Exchange the contents of this string with another. + void + swap(fixed_string& str); + + /// Exchange the contents of this string with another. + template + void + swap(fixed_string& str); + + // + // Search + // + +private: + fixed_string& + assign_char(CharT ch, std::true_type); + + fixed_string& + assign_char(CharT ch, std::false_type); +}; + +// +// Disallowed operations +// + +// These operations are explicitly deleted since +// there is no reasonable implementation possible. + +template +void +operator+( + fixed_stringconst& lhs, + fixed_stringconst& rhs) = delete; + +template +void +operator+(CharT const* lhs, + fixed_stringconst& rhs) = delete; + +template +void +operator+(CharT lhs, + fixed_string const& rhs) = delete; + +template +void +operator+(fixed_string const& lhs, + CharT const* rhs) = delete; + +template +void +operator+(fixed_string const& lhs, + CharT rhs) = delete; + +// +// Non-member functions +// + +template +bool +operator==( + fixed_string const& lhs, + fixed_string const& rhs) +{ + return lhs.compare(rhs) == 0; +} + +template +bool +operator!=( + fixed_string const& lhs, + fixed_string const& rhs) +{ + return lhs.compare(rhs) != 0; +} + +template +bool +operator<( + fixed_string const& lhs, + fixed_string const& rhs) +{ + return lhs.compare(rhs) < 0; +} + +template +bool +operator<=( + fixed_string const& lhs, + fixed_string const& rhs) +{ + return lhs.compare(rhs) <= 0; +} + +template +bool +operator>( + fixed_string const& lhs, + fixed_string const& rhs) +{ + return lhs.compare(rhs) > 0; +} + +template +bool +operator>=( + fixed_string const& lhs, + fixed_string const& rhs) +{ + return lhs.compare(rhs) >= 0; +} + +template +bool +operator==( + CharT const* lhs, + fixed_string const& rhs) +{ + return detail::lexicographical_compare( + lhs, Traits::length(lhs), + rhs.data(), rhs.size()) == 0; +} + +template +bool +operator==( + fixed_string const& lhs, + CharT const* rhs) +{ + return detail::lexicographical_compare( + lhs.data(), lhs.size(), + rhs, Traits::length(rhs)) == 0; +} + +template +bool +operator!=( + CharT const* lhs, + fixed_string const& rhs) +{ + return detail::lexicographical_compare( + lhs, Traits::length(lhs), + rhs.data(), rhs.size()) != 0; +} + +template +bool +operator!=( + fixed_string const& lhs, + CharT const* rhs) +{ + return detail::lexicographical_compare( + lhs.data(), lhs.size(), + rhs, Traits::length(rhs)) != 0; +} + +template +bool +operator<( + CharT const* lhs, + fixed_string const& rhs) +{ + return detail::lexicographical_compare( + lhs, Traits::length(lhs), + rhs.data(), rhs.size()) < 0; +} + +template +bool +operator<( + fixed_string const& lhs, + CharT const* rhs) +{ + return detail::lexicographical_compare( + lhs.data(), lhs.size(), + rhs, Traits::length(rhs)) < 0; +} + +template +bool +operator<=( + CharT const* lhs, + fixed_string const& rhs) +{ + return detail::lexicographical_compare( + lhs, Traits::length(lhs), + rhs.data(), rhs.size()) <= 0; +} + +template +bool +operator<=( + fixed_string const& lhs, + CharT const* rhs) +{ + return detail::lexicographical_compare( + lhs.data(), lhs.size(), + rhs, Traits::length(rhs)) <= 0; +} + +template +bool +operator>( + CharT const* lhs, + fixed_string const& rhs) +{ + return detail::lexicographical_compare( + lhs, Traits::length(lhs), + rhs.data(), rhs.size()) > 0; +} + +template +bool +operator>( + fixed_string const& lhs, + CharT const* rhs) +{ + return detail::lexicographical_compare( + lhs.data(), lhs.size(), + rhs, Traits::length(rhs)) > 0; +} + +template +bool +operator>=( + CharT const* lhs, + fixed_string const& rhs) +{ + return detail::lexicographical_compare( + lhs, Traits::length(lhs), + rhs.data(), rhs.size()) >= 0; +} + +template +bool +operator>=( + fixed_string const& lhs, + CharT const* rhs) +{ + return detail::lexicographical_compare( + lhs.data(), lhs.size(), + rhs, Traits::length(rhs)) >= 0; +} + +// +// swap +// + +template +void +swap( + fixed_string& lhs, + fixed_string& rhs) +{ + lhs.swap(rhs); +} + +template +void +swap( + fixed_string& lhs, + fixed_string& rhs) +{ + lhs.swap(rhs); +} + +// +// Input/Output +// + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, + fixed_string const& str) +{ + return os << static_cast< + basic_string_view>(str); +} + +// +// Numeric conversions +// + +/** Returns a static string representing an integer as a decimal. + + @param x The signed or unsigned integer to convert. + This must be an integral type. + + @return A @ref fixed_string with an implementation defined + maximum size large enough to hold the longest possible decimal + representation of any integer of the given type. +*/ +template< + class Integer +#ifndef BOOST_BEAST_DOXYGEN + ,class = typename std::enable_if< + std::is_integral::value>::type +#endif +> +fixed_string +to_fixed_string(Integer x); + +} // fixed_string +} // boost + +#include + +#endif diff --git a/include/boost/fixed_string/impl/fixed_string.hpp b/include/boost/fixed_string/impl/fixed_string.hpp new file mode 100644 index 0000000..0b1ee6d --- /dev/null +++ b/include/boost/fixed_string/impl/fixed_string.hpp @@ -0,0 +1,585 @@ +// +// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/fixed_string +// + +#ifndef BOOST_FIXED_STRING_IMPL_FIXED_STRING_HPP +#define BOOST_FIXED_STRING_IMPL_FIXED_STRING_HPP + +#include +#include +#include + +namespace boost { +namespace fixed_string { + +// +// (constructor) +// + +template +fixed_string:: +fixed_string() +{ + n_ = 0; + term(); +} + +template +fixed_string:: +fixed_string(size_type count, CharT ch) +{ + assign(count, ch); +} + +template +template +fixed_string:: +fixed_string(fixed_string const& other, + size_type pos) +{ + assign(other, pos); +} + +template +template +fixed_string:: +fixed_string(fixed_string const& other, + size_type pos, size_type count) +{ + assign(other, pos, count); +} + +template +fixed_string:: +fixed_string(CharT const* s, size_type count) +{ + assign(s, count); +} + +template +fixed_string:: +fixed_string(CharT const* s) +{ + auto const count = Traits::length(s); + if(count > max_size()) + BOOST_THROW_EXCEPTION(std::length_error{ + "count > max_size()"}); + n_ = count; + Traits::copy(&s_[0], s, n_ + 1); +} + +template +template +fixed_string:: +fixed_string(InputIt first, InputIt last) +{ + assign(first, last); +} + +template +fixed_string:: +fixed_string(fixed_string const& s) +{ + assign(s); +} + +template +template +fixed_string:: +fixed_string(fixed_string const& s) +{ + assign(s); +} + +template +fixed_string:: +fixed_string(std::initializer_list init) +{ + assign(init.begin(), init.end()); +} + +template +fixed_string:: +fixed_string(string_view_type sv) +{ + assign(sv); +} + +template +template +fixed_string:: +fixed_string(T const& t, size_type pos, size_type n) +{ + assign(t, pos, n); +} + +// +// (assignment) +// + +template +auto +fixed_string:: +operator=(CharT const* s) -> + fixed_string& +{ + auto const count = Traits::length(s); + if(count > max_size()) + BOOST_THROW_EXCEPTION(std::length_error{ + "count > max_size()"}); + n_ = count; + Traits::copy(&s_[0], s, n_ + 1); + return *this; +} + +template +auto +fixed_string:: +assign(size_type count, CharT ch) -> + fixed_string& +{ + if(count > max_size()) + BOOST_THROW_EXCEPTION(std::length_error{ + "count > max_size()"}); + n_ = count; + Traits::assign(&s_[0], n_, ch); + term(); + return *this; +} + +template +auto +fixed_string:: +assign(fixed_string const& str) -> + fixed_string& +{ + n_ = str.n_; + auto const n = n_ + 1; + // VFALCO I can't remember the thinking behind this + //BOOST_BEAST_ASSUME(n != 0); + Traits::copy(&s_[0], &str.s_[0], n); + return *this; +} + +template +template +auto +fixed_string:: +assign(fixed_string const& str, + size_type pos, size_type count) -> + fixed_string& +{ + auto const ss = str.substr(pos, count); + return assign(ss.data(), ss.size()); +} + +template +auto +fixed_string:: +assign(CharT const* s, size_type count) -> + fixed_string& +{ + if(count > max_size()) + BOOST_THROW_EXCEPTION(std::length_error{ + "count > max_size()"}); + n_ = count; + Traits::copy(&s_[0], s, n_); + term(); + return *this; +} + +template +template +auto +fixed_string:: +assign(InputIt first, InputIt last) -> + fixed_string& +{ + std::size_t const n = std::distance(first, last); + if(n > max_size()) + BOOST_THROW_EXCEPTION(std::length_error{ + "n > max_size()"}); + n_ = n; + for(auto it = &s_[0]; first != last; ++it, ++first) + Traits::assign(*it, *first); + term(); + return *this; +} + +template +template +auto +fixed_string:: +assign(T const& t, size_type pos, size_type count) -> + typename std::enable_if::value, fixed_string&>::type +{ + auto const sv = string_view_type(t).substr(pos, count); + if(sv.size() > max_size()) + BOOST_THROW_EXCEPTION(std::length_error{ + "sv.size() > max_size()"}); + n_ = sv.size(); + Traits::copy(&s_[0], &sv[0], n_); + term(); + return *this; +} + +// +// Element access +// + +template +auto +fixed_string:: +at(size_type pos) -> + reference +{ + if(pos >= size()) + BOOST_THROW_EXCEPTION(std::out_of_range{ + "pos >= size()"}); + return s_[pos]; +} + +template +auto +fixed_string:: +at(size_type pos) const -> + const_reference +{ + if(pos >= size()) + BOOST_THROW_EXCEPTION(std::out_of_range{ + "pos >= size()"}); + return s_[pos]; +} + +// +// Capacity +// + +template +void +fixed_string:: +reserve(std::size_t n) +{ + if(n > max_size()) + BOOST_THROW_EXCEPTION(std::length_error{ + "n > max_size()"}); +} + +// +// Operations +// + +template +void +fixed_string:: +clear() +{ + n_ = 0; + term(); +} + +template +auto +fixed_string:: +insert(size_type index, size_type count, CharT ch) -> + fixed_string& +{ + if(index > size()) + BOOST_THROW_EXCEPTION(std::out_of_range{ + "index > size()"}); + insert(begin() + index, count, ch); + return *this; +} + +template +auto +fixed_string:: +insert(size_type index, CharT const* s, size_type count) -> + fixed_string& +{ + if(index > size()) + BOOST_THROW_EXCEPTION(std::out_of_range{ + "index > size()"}); + if(size() + count > max_size()) + BOOST_THROW_EXCEPTION(std::length_error{ + "size() + count > max_size()"}); + Traits::move( + &s_[index + count], &s_[index], size() - index); + n_ += count; + Traits::copy(&s_[index], s, count); + term(); + return *this; +} + +template +template +auto +fixed_string:: +insert(size_type index, + fixed_string const& str, + size_type index_str, size_type count) -> + fixed_string& +{ + auto const ss = str.substr(index_str, count); + return insert(index, ss.data(), ss.size()); +} + +template +auto +fixed_string:: +insert(const_iterator pos, size_type count, CharT ch) -> + iterator +{ + if(size() + count > max_size()) + BOOST_THROW_EXCEPTION(std::length_error{ + "size() + count() > max_size()"}); + auto const index = pos - &s_[0]; + Traits::move( + &s_[index + count], &s_[index], size() - index); + n_ += count; + Traits::assign(&s_[index], count, ch); + term(); + return &s_[index]; +} + +template +template +auto +fixed_string:: +insert(const_iterator pos, InputIt first, InputIt last) -> + typename std::enable_if< + detail::is_input_iterator::value, + iterator>::type +{ + std::size_t const count = std::distance(first, last); + if(size() + count > max_size()) + BOOST_THROW_EXCEPTION(std::length_error{ + "size() + count > max_size()"}); + std::size_t const index = pos - begin(); + Traits::move( + &s_[index + count], &s_[index], size() - index); + n_ += count; + for(auto it = begin() + index; + first != last; ++it, ++first) + Traits::assign(*it, *first); + term(); + return begin() + index; +} + +template +template +auto +fixed_string:: +insert(size_type index, const T& t, + size_type index_str, size_type count) -> + typename std::enable_if::value && + ! std::is_convertible::value, + fixed_string&>::type +{ + auto const str = + string_view_type(t).substr(index_str, count); + return insert(index, str.data(), str.size()); +} + +template +auto +fixed_string:: +erase(size_type index, size_type count) -> + fixed_string& +{ + if(index > size()) + BOOST_THROW_EXCEPTION(std::out_of_range{ + "index > size()"}); + auto const n = (std::min)(count, size() - index); + Traits::move( + &s_[index], &s_[index + n], size() - (index + n) + 1); + n_ -= n; + return *this; +} + +template +auto +fixed_string:: +erase(const_iterator pos) -> + iterator +{ + erase(pos - begin(), 1); + return begin() + (pos - begin()); +} + +template +auto +fixed_string:: +erase(const_iterator first, const_iterator last) -> + iterator +{ + erase(first - begin(), + std::distance(first, last)); + return begin() + (first - begin()); +} + +template +void +fixed_string:: +push_back(CharT ch) +{ + if(size() >= max_size()) + BOOST_THROW_EXCEPTION(std::length_error{ + "size() >= max_size()"}); + Traits::assign(s_[n_++], ch); + term(); +} + +template +template +auto +fixed_string:: +append(fixed_string const& str, + size_type pos, size_type count) -> + fixed_string& +{ + // Valid range is [0, size) + if(pos >= str.size()) + BOOST_THROW_EXCEPTION(std::out_of_range{ + "pos > str.size()"}); + string_view_type const ss{&str.s_[pos], + (std::min)(count, str.size() - pos)}; + insert(size(), ss.data(), ss.size()); + return *this; +} + +template +auto +fixed_string:: +substr(size_type pos, size_type count) const -> + string_view_type +{ + if(pos > size()) + BOOST_THROW_EXCEPTION(std::out_of_range{ + "pos > size()"}); + return{&s_[pos], (std::min)(count, size() - pos)}; +} + +template +auto +fixed_string:: +copy(CharT* dest, size_type count, size_type pos) const -> + size_type +{ + auto const str = substr(pos, count); + Traits::copy(dest, str.data(), str.size()); + return str.size(); +} + +template +void +fixed_string:: +resize(std::size_t n) +{ + if(n > max_size()) + BOOST_THROW_EXCEPTION(std::length_error{ + "n > max_size()"}); + if(n > n_) + Traits::assign(&s_[n_], n - n_, CharT{}); + n_ = n; + term(); +} + +template +void +fixed_string:: +resize(std::size_t n, CharT c) +{ + if(n > max_size()) + BOOST_THROW_EXCEPTION(std::length_error{ + "n > max_size()"}); + if(n > n_) + Traits::assign(&s_[n_], n - n_, c); + n_ = n; + term(); +} + +template +void +fixed_string:: +swap(fixed_string& str) +{ + fixed_string tmp(str); + str.n_ = n_; + Traits::copy(&str.s_[0], &s_[0], n_ + 1); + n_ = tmp.n_; + Traits::copy(&s_[0], &tmp.s_[0], n_ + 1); +} + +template +template +void +fixed_string:: +swap(fixed_string& str) +{ + if(size() > str.max_size()) + BOOST_THROW_EXCEPTION(std::length_error{ + "size() > str.max_size()"}); + if(str.size() > max_size()) + BOOST_THROW_EXCEPTION(std::length_error{ + "str.size() > max_size()"}); + fixed_string tmp(str); + str.n_ = n_; + Traits::copy(&str.s_[0], &s_[0], n_ + 1); + n_ = tmp.n_; + Traits::copy(&s_[0], &tmp.s_[0], n_ + 1); +} + + +template +auto +fixed_string:: +assign_char(CharT ch, std::true_type) -> + fixed_string& +{ + n_ = 1; + Traits::assign(s_[0], ch); + term(); + return *this; +} + +template +auto +fixed_string:: +assign_char(CharT, std::false_type) -> + fixed_string& +{ + BOOST_THROW_EXCEPTION(std::length_error{ + "max_size() == 0"}); +} + +template +fixed_string +to_fixed_string(Integer x) +{ + using CharT = char; + using Traits = std::char_traits; + BOOST_STATIC_ASSERT(std::is_integral::value); + char buf[detail::max_digits(sizeof(Integer))]; + auto last = buf + sizeof(buf); + auto it = detail::raw_to_string< + CharT, Integer, Traits>(last, sizeof(buf), x); + fixed_string s; + s.resize(static_cast(last - it)); + auto p = s.data(); + while(it < last) + Traits::assign(*p++, *it++); + return s; +} + +} // fixed_string +} // boost + +#endif diff --git a/index.html b/index.html new file mode 100644 index 0000000..83e0c4f --- /dev/null +++ b/index.html @@ -0,0 +1,21 @@ + + + Boost.FixedString + + + + Automatic redirection failed, please go to + ./doc/html/index.html +
+ + Boost.Beast
+
+ Copyright (C) 2016 Vinnie Falco
+
+ Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt)
+
+
+ + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..396d3f3 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,23 @@ +# +# Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# +# Official repository: https://github.com/boostorg/fixed_string +# + +GroupSources (include/boost/fixed_string fixed_string) +GroupSources (test "/") + +add_executable (tests + ${PROJECT_FILES} + Jamfile + lib.cpp + fixed_string.cpp +) + +target_link_libraries(tests + ) + +set_property(TARGET tests PROPERTY FOLDER "tests") diff --git a/test/Jamfile b/test/Jamfile new file mode 100644 index 0000000..ce1db0e --- /dev/null +++ b/test/Jamfile @@ -0,0 +1,34 @@ +# +# Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# +# Official repository: https://github.com/boostorg/fixed_string +# + +local SOURCES = + fixed_string.cpp + ; + +local RUN_TESTS ; + +for local f in $(SOURCES) +{ + RUN_TESTS += [ run $(f) lib.cpp ] ; +} + +alias run-tests : $(RUN_TESTS) ; + +exe fat-tests : + $(SOURCES) + lib.cpp + ; + +explicit fat-tests ; + +run $(SOURCES) + lib.cpp + : : : : run-fat-tests ; + +explicit run-fat-tests ; diff --git a/test/fixed_string.cpp b/test/fixed_string.cpp new file mode 100644 index 0000000..500abf4 --- /dev/null +++ b/test/fixed_string.cpp @@ -0,0 +1,1481 @@ +// +// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/fixed_string +// + +// Test that header file is self-contained. +#include + +#include + +namespace boost { +namespace fixed_string { + +class fixed_string_test : public beast::unit_test::suite +{ +public: + void + testConstruct() + { + { + fixed_string<1> s; + BEAST_EXPECT(s.empty()); + BEAST_EXPECT(s.size() == 0); + BEAST_EXPECT(s == ""); + BEAST_EXPECT(*s.end() == 0); + } + { + fixed_string<4> s1(3, 'x'); + BEAST_EXPECT(! s1.empty()); + BEAST_EXPECT(s1.size() == 3); + BEAST_EXPECT(s1 == "xxx"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<2> s2(3, 'x'); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<5> s1("12345"); + BEAST_EXPECT(*s1.end() == 0); + fixed_string<3> s2(s1, 2); + BEAST_EXPECT(s2 == "345"); + BEAST_EXPECT(*s2.end() == 0); + fixed_string<0> s3(s1, 5); + BEAST_EXPECT(s3.empty()); + BEAST_EXPECT(s3.front() == 0); + BEAST_EXPECT(*s3.end() == 0); + } + { + fixed_string<5> s1("12345"); + fixed_string<2> s2(s1, 1, 2); + BEAST_EXPECT(s2 == "23"); + BEAST_EXPECT(*s2.end() == 0); + fixed_string<0> s3(s1, 5, 1); + BEAST_EXPECT(s3.empty()); + BEAST_EXPECT(s3.front() == 0); + BEAST_EXPECT(*s3.end() == 0); + try + { + fixed_string<5> s4(s1, 6); + fail("", __FILE__, __LINE__); + } + catch(std::out_of_range const&) + { + pass(); + } + } + { + fixed_string<5> s1("UVXYZ", 3); + BEAST_EXPECT(s1 == "UVX"); + BEAST_EXPECT(*s1.end() == 0); + fixed_string<5> s2("X\0""Y\0""Z", 3); + BEAST_EXPECT(std::memcmp( + s2.data(), "X\0""Y", 3) == 0); + BEAST_EXPECT(*s2.end() == 0); + } + { + fixed_string<5> s1("12345"); + fixed_string<3> s2( + s1.begin() + 1, s1.begin() + 3); + BEAST_EXPECT(s2 == "23"); + BEAST_EXPECT(*s2.end() == 0); + } + { + fixed_string<5> s1("12345"); + fixed_string<5> s2(s1); + BEAST_EXPECT(s2 == "12345"); + BEAST_EXPECT(*s2.end() == 0); + fixed_string<6> s3(s1); + BEAST_EXPECT(s3 == "12345"); + BEAST_EXPECT(*s3.end() == 0); + try + { + fixed_string<4> s4(s1); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<3> s1({'1', '2', '3'}); + BEAST_EXPECT(s1 == "123"); + BEAST_EXPECT(*s1.end() == 0); + BEAST_EXPECT( + fixed_string<0>({}) == fixed_string<0>()); + try + { + fixed_string<2> s2({'1', '2', '3'}); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<3> s1( + string_view("123")); + BEAST_EXPECT(s1 == "123"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<2> s2( + string_view("123")); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<5> s1( + std::string("12345"), 2, 2); + BEAST_EXPECT(s1 == "34"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<2> s2( + std::string("12345"), 1, 3); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + } + + void + testAssign() + { + { + fixed_string<3> s1("123"); + fixed_string<3> s2; + s2 = s1; + BEAST_EXPECT(s2 == "123"); + BEAST_EXPECT(*s2.end() == 0); + } + { + fixed_string<3> s1("123"); + fixed_string<5> s2; + s2 = s1; + BEAST_EXPECT(s2 == "123"); + BEAST_EXPECT(*s2.end() == 0); + try + { + fixed_string<1> s3; + s3 = s1; + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<3> s1; + s1 = "123"; + BEAST_EXPECT(s1 == "123"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<1> s2; + s2 = "123"; + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<1> s1; + s1 = 'x'; + BEAST_EXPECT(s1 == "x"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<0> s2; + s2 = 'x'; + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<3> s1; + s1 = {'1', '2', '3'}; + BEAST_EXPECT(s1 == "123"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<1> s2; + s2 = {'1', '2', '3'}; + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<3> s1; + s1 = string_view("123"); + BEAST_EXPECT(s1 == "123"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<1> s2; + s2 = string_view("123"); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + + { + fixed_string<4> s1; + s1.assign(3, 'x'); + BEAST_EXPECT(s1 == "xxx"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<2> s2; + s2.assign(3, 'x'); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<5> s1("12345"); + BEAST_EXPECT(*s1.end() == 0); + fixed_string<5> s2; + s2.assign(s1); + BEAST_EXPECT(s2 == "12345"); + BEAST_EXPECT(*s2.end() == 0); + } + { + fixed_string<5> s1("12345"); + BEAST_EXPECT(*s1.end() == 0); + fixed_string<7> s2; + s2.assign(s1); + BEAST_EXPECT(s2 == "12345"); + BEAST_EXPECT(*s2.end() == 0); + try + { + fixed_string<3> s3; + s3.assign(s1); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<5> s1("12345"); + fixed_string<5> s2; + s2.assign(s1, 1); + BEAST_EXPECT(s2 == "2345"); + BEAST_EXPECT(*s2.end() == 0); + s2.assign(s1, 1, 2); + BEAST_EXPECT(s2 == "23"); + BEAST_EXPECT(*s2.end() == 0); + s2.assign(s1, 1, 100); + BEAST_EXPECT(s2 == "2345"); + BEAST_EXPECT(*s2.end() == 0); + try + { + s2.assign(s1, 6); + fail("", __FILE__, __LINE__); + } + catch(std::out_of_range const&) + { + pass(); + } + try + { + fixed_string<3> s3; + s3.assign(s1, 1); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<5> s1; + s1.assign("12"); + BEAST_EXPECT(s1 == "12"); + BEAST_EXPECT(*s1.end() == 0); + s1.assign("12345"); + BEAST_EXPECT(s1 == "12345"); + BEAST_EXPECT(*s1.end() == 0); + } + { + fixed_string<5> s1; + s1.assign("12345", 3); + BEAST_EXPECT(s1 == "123"); + BEAST_EXPECT(*s1.end() == 0); + } + { + fixed_string<5> s1("12345"); + fixed_string<3> s2; + s2.assign(s1.begin(), s1.begin() + 2); + BEAST_EXPECT(s2 == "12"); + BEAST_EXPECT(*s2.end() == 0); + try + { + s2.assign(s1.begin(), s1.end()); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<5> s1; + s1.assign({'1', '2', '3'}); + BEAST_EXPECT(s1 == "123"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<1> s2; + s2.assign({'1', '2', '3'}); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<5> s1; + s1.assign(string_view("123")); + BEAST_EXPECT(s1 == "123"); + BEAST_EXPECT(*s1.end() == 0); + s1.assign(string_view("12345")); + BEAST_EXPECT(s1 == "12345"); + BEAST_EXPECT(*s1.end() == 0); + try + { + s1.assign(string_view("1234567")); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<5> s1; + s1.assign(std::string("12345"), 2, 2); + BEAST_EXPECT(s1 == "34"); + BEAST_EXPECT(*s1.end() == 0); + s1.assign(std::string("12345"), 3); + BEAST_EXPECT(s1 == "45"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<2> s2; + s2.assign( + std::string("12345"), 1, 3); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + } + + void + testAccess() + { + { + fixed_string<5> s("12345"); + BEAST_EXPECT(s.at(1) == '2'); + BEAST_EXPECT(s.at(4) == '5'); + try + { + BEAST_EXPECT(s.at(5) == 0); + fail("", __FILE__, __LINE__); + } + catch(std::out_of_range const&) + { + pass(); + } + } + { + fixed_string<5> const s("12345"); + BEAST_EXPECT(s.at(1) == '2'); + BEAST_EXPECT(s.at(4) == '5'); + try + { + BEAST_EXPECT(s.at(5) == 0); + fail("", __FILE__, __LINE__); + } + catch(std::out_of_range const&) + { + pass(); + } + } + { + fixed_string<5> s("12345"); + BEAST_EXPECT(s[1] == '2'); + BEAST_EXPECT(s[4] == '5'); + s[1] = '_'; + BEAST_EXPECT(s == "1_345"); + } + { + fixed_string<5> const s("12345"); + BEAST_EXPECT(s[1] == '2'); + BEAST_EXPECT(s[4] == '5'); + BEAST_EXPECT(s[5] == 0); + } + { + fixed_string<3> s("123"); + BEAST_EXPECT(s.front() == '1'); + BEAST_EXPECT(s.back() == '3'); + s.front() = '_'; + BEAST_EXPECT(s == "_23"); + s.back() = '_'; + BEAST_EXPECT(s == "_2_"); + } + { + fixed_string<3> const s("123"); + BEAST_EXPECT(s.front() == '1'); + BEAST_EXPECT(s.back() == '3'); + } + { + fixed_string<3> s("123"); + BEAST_EXPECT(std::memcmp( + s.data(), "123", 3) == 0); + } + { + fixed_string<3> const s("123"); + BEAST_EXPECT(std::memcmp( + s.data(), "123", 3) == 0); + } + { + fixed_string<3> s("123"); + BEAST_EXPECT(std::memcmp( + s.c_str(), "123\0", 4) == 0); + } + { + fixed_string<3> s("123"); + string_view sv = s; + BEAST_EXPECT(fixed_string<5>(sv) == "123"); + } + } + + void + testIterators() + { + { + fixed_string<3> s; + BEAST_EXPECT(std::distance( + s.begin(), s.end()) == 0); + BEAST_EXPECT(std::distance( + s.rbegin(), s.rend()) == 0); + s = "123"; + BEAST_EXPECT(std::distance( + s.begin(), s.end()) == 3); + BEAST_EXPECT(std::distance( + s.rbegin(), s.rend()) == 3); + } + { + fixed_string<3> const s("123"); + BEAST_EXPECT(std::distance( + s.begin(), s.end()) == 3); + BEAST_EXPECT(std::distance( + s.cbegin(), s.cend()) == 3); + BEAST_EXPECT(std::distance( + s.rbegin(), s.rend()) == 3); + BEAST_EXPECT(std::distance( + s.crbegin(), s.crend()) == 3); + } + } + + void + testCapacity() + { + fixed_string<3> s; + BEAST_EXPECT(s.empty()); + BEAST_EXPECT(s.size() == 0); + BEAST_EXPECT(s.length() == 0); + BEAST_EXPECT(s.max_size() == 3); + BEAST_EXPECT(s.capacity() == 3); + s = "123"; + BEAST_EXPECT(! s.empty()); + BEAST_EXPECT(s.size() == 3); + BEAST_EXPECT(s.length() == 3); + s.reserve(0); + s.reserve(3); + try + { + s.reserve(4); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + s.shrink_to_fit(); + BEAST_EXPECT(! s.empty()); + BEAST_EXPECT(s.size() == 3); + BEAST_EXPECT(s.length() == 3); + BEAST_EXPECT(*s.end() == 0); + } + + void + testOperations() + { + // + // clear + // + + { + fixed_string<3> s("123"); + s.clear(); + BEAST_EXPECT(s.empty()); + BEAST_EXPECT(*s.end() == 0); + } + + // + // insert + // + + { + // Using 7 as the size causes a miscompile in MSVC14.2 x64 Release + fixed_string<8> s1("12345"); + s1.insert(2, 2, '_'); + BEAST_EXPECT(s1 == "12__345"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<6> s2("12345"); + s2.insert(2, 2, '_'); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + try + { + fixed_string<6> s2("12345"); + s2.insert(6, 2, '_'); + fail("", __FILE__, __LINE__); + } + catch(std::out_of_range const&) + { + pass(); + } + } + { + fixed_string<7> s1("12345"); + s1.insert(2, "__"); + BEAST_EXPECT(s1 == "12__345"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<6> s2("12345"); + s2.insert(2, "__"); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + try + { + fixed_string<6> s2("12345"); + s2.insert(6, "__"); + fail("", __FILE__, __LINE__); + } + catch(std::out_of_range const&) + { + pass(); + } + } + { + fixed_string<7> s1("12345"); + s1.insert(2, "TUV", 2); + BEAST_EXPECT(s1 == "12TU345"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<6> s2("12345"); + s2.insert(2, "TUV", 2); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + try + { + fixed_string<6> s2("12345"); + s2.insert(6, "TUV", 2); + fail("", __FILE__, __LINE__); + } + catch(std::out_of_range const&) + { + pass(); + } + } + { + fixed_string<7> s1("12345"); + s1.insert(2, fixed_string<3>("TU")); + BEAST_EXPECT(s1 == "12TU345"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<6> s2("12345"); + s2.insert(2, fixed_string<3>("TUV")); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + try + { + fixed_string<6> s2("12345"); + s2.insert(6, fixed_string<3>("TUV")); + fail("", __FILE__, __LINE__); + } + catch(std::out_of_range const&) + { + pass(); + } + } + { + fixed_string<7> s1("12345"); + s1.insert(2, fixed_string<3>("TUV"), 1); + BEAST_EXPECT(s1 == "12UV345"); + BEAST_EXPECT(*s1.end() == 0); + s1 = "12345"; + s1.insert(2, fixed_string<3>("TUV"), 1, 1); + BEAST_EXPECT(s1 == "12U345"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<6> s2("12345"); + s2.insert(2, fixed_string<3>("TUV"), 1, 2); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + try + { + fixed_string<6> s2("12345"); + s2.insert(6, fixed_string<3>("TUV"), 1, 2); + fail("", __FILE__, __LINE__); + } + catch(std::out_of_range const&) + { + pass(); + } + } + { + fixed_string<4> s1("123"); + s1.insert(s1.begin() + 1, '_'); + BEAST_EXPECT(s1 == "1_23"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<3> s2("123"); + s2.insert(s2.begin() + 1, '_'); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<4> s1("12"); + s1.insert(s1.begin() + 1, 2, '_'); + BEAST_EXPECT(s1 == "1__2"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<4> s2("123"); + s2.insert(s2.begin() + 1, 2, ' '); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<3> s1("123"); + fixed_string<5> s2("UV"); + s2.insert(s2.begin() + 1, s1.begin(), s1.end()); + BEAST_EXPECT(s2 == "U123V"); + BEAST_EXPECT(*s2.end() == 0); + try + { + fixed_string<4> s3("UV"); + s3.insert(s3.begin() + 1, s1.begin(), s1.end()); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<5> s1("123"); + s1.insert(1, string_view("UV")); + BEAST_EXPECT(s1 == "1UV23"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<4> s2("123"); + s2.insert(1, string_view("UV")); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + try + { + fixed_string<5> s2("123"); + s2.insert(5, string_view("UV")); + fail("", __FILE__, __LINE__); + } + catch(std::out_of_range const&) + { + pass(); + } + } + { + fixed_string<5> s1("123"); + s1.insert(1, std::string("UV")); + BEAST_EXPECT(s1 == "1UV23"); + BEAST_EXPECT(*s1.end() == 0); + try + { + s1.insert(1, std::string("UV")); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<6> s1("123"); + s1.insert(1, std::string("UVX"), 1); + BEAST_EXPECT(s1 == "1VX23"); + BEAST_EXPECT(*s1.end() == 0); + s1.insert(4, std::string("PQR"), 1, 1); + BEAST_EXPECT(s1 == "1VX2Q3"); + BEAST_EXPECT(*s1.end() == 0); + try + { + s1.insert(4, std::string("PQR"), 1, 1); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + + // + // erase + // + + { + fixed_string<9> s1("123456789"); + BEAST_EXPECT(s1.erase(1, 1) == "13456789"); + BEAST_EXPECT(s1 == "13456789"); + BEAST_EXPECT(*s1.end() == 0); + BEAST_EXPECT(s1.erase(5) == "13456"); + BEAST_EXPECT(s1 == "13456"); + BEAST_EXPECT(*s1.end() == 0); + try + { + s1.erase(7); + fail("", __FILE__, __LINE__); + } + catch(std::out_of_range const&) + { + pass(); + } + } + { + fixed_string<9> s1("123456789"); + BEAST_EXPECT(*s1.erase(s1.begin() + 5) == '7'); + BEAST_EXPECT(s1 == "12345789"); + BEAST_EXPECT(*s1.end() == 0); + } + { + fixed_string<9> s1("123456789"); + BEAST_EXPECT(*s1.erase( + s1.begin() + 5, s1.begin() + 7) == '8'); + BEAST_EXPECT(s1 == "1234589"); + BEAST_EXPECT(*s1.end() == 0); + } + + // + // push_back + // + + { + fixed_string<3> s1("12"); + s1.push_back('3'); + BEAST_EXPECT(s1 == "123"); + try + { + s1.push_back('4'); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + fixed_string<0> s2; + try + { + s2.push_back('_'); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + + // + // pop_back + // + + { + fixed_string<3> s1("123"); + s1.pop_back(); + BEAST_EXPECT(s1 == "12"); + BEAST_EXPECT(*s1.end() == 0); + s1.pop_back(); + BEAST_EXPECT(s1 == "1"); + BEAST_EXPECT(*s1.end() == 0); + s1.pop_back(); + BEAST_EXPECT(s1.empty()); + BEAST_EXPECT(*s1.end() == 0); + } + + // + // append + // + + { + fixed_string<3> s1("1"); + s1.append(2, '_'); + BEAST_EXPECT(s1 == "1__"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<2> s2("1"); + s2.append(2, '_'); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<2> s1("__"); + fixed_string<3> s2("1"); + s2.append(s1); + BEAST_EXPECT(s2 == "1__"); + BEAST_EXPECT(*s2.end() == 0); + try + { + fixed_string<2> s3("1"); + s3.append(s1); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<3> s1("XYZ"); + fixed_string<4> s2("12"); + s2.append(s1, 1); + BEAST_EXPECT(s2 == "12YZ"); + BEAST_EXPECT(*s2.end() == 0); + fixed_string<3> s3("12"); + s3.append(s1, 1, 1); + BEAST_EXPECT(s3 == "12Y"); + BEAST_EXPECT(*s3.end() == 0); + try + { + fixed_string<3> s4("12"); + s4.append(s1, 3); + fail("", __FILE__, __LINE__); + } + catch(std::out_of_range const&) + { + pass(); + } + try + { + fixed_string<3> s4("12"); + s4.append(s1, 1); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<4> s1("12"); + s1.append("XYZ", 2); + BEAST_EXPECT(s1 == "12XY"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<3> s3("12"); + s3.append("XYZ", 2); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<5> s1("12"); + s1.append("XYZ"); + BEAST_EXPECT(s1 == "12XYZ"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<4> s2("12"); + s2.append("XYZ"); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<3> s1("XYZ"); + fixed_string<5> s2("12"); + s2.append(s1.begin(), s1.end()); + BEAST_EXPECT(s2 == "12XYZ"); + BEAST_EXPECT(*s2.end() == 0); + try + { + fixed_string<4> s3("12"); + s3.append(s1.begin(), s1.end()); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<5> s1("123"); + s1.append({'X', 'Y'}); + BEAST_EXPECT(s1 == "123XY"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<4> s2("123"); + s2.append({'X', 'Y'}); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + string_view s1("XYZ"); + fixed_string<5> s2("12"); + s2.append(s1); + BEAST_EXPECT(s2 == "12XYZ"); + BEAST_EXPECT(*s2.end() == 0); + try + { + fixed_string<4> s3("12"); + s3.append(s1); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<6> s1("123"); + s1.append(std::string("UVX"), 1); + BEAST_EXPECT(s1 == "123VX"); + BEAST_EXPECT(*s1.end() == 0); + s1.append(std::string("PQR"), 1, 1); + BEAST_EXPECT(s1 == "123VXQ"); + BEAST_EXPECT(*s1.end() == 0); + try + { + fixed_string<3> s2("123"); + s2.append(std::string("PQR"), 1, 1); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + + // + // operator+= + // + + { + fixed_string<2> s1("__"); + fixed_string<3> s2("1"); + s2 += s1; + BEAST_EXPECT(s2 == "1__"); + BEAST_EXPECT(*s2.end() == 0); + try + { + fixed_string<2> s3("1"); + s3 += s1; + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<3> s1("12"); + s1 += '3'; + BEAST_EXPECT(s1 == "123"); + try + { + s1 += '4'; + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<4> s1("12"); + s1 += "34"; + BEAST_EXPECT(s1 == "1234"); + try + { + s1 += "5"; + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + fixed_string<4> s1("12"); + s1 += {'3', '4'}; + BEAST_EXPECT(s1 == "1234"); + try + { + s1 += {'5'}; + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + { + string_view s1("34"); + fixed_string<4> s2("12"); + s2 += s1; + BEAST_EXPECT(s2 == "1234"); + try + { + s2 += s1; + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + } + + void + testCompare() + { + using str1 = fixed_string<1>; + using str2 = fixed_string<2>; + { + str1 s1; + str2 s2; + s1 = "1"; + s2 = "22"; + BEAST_EXPECT(s1.compare(s2) < 0); + BEAST_EXPECT(s2.compare(s1) > 0); + BEAST_EXPECT(s1 < "10"); + BEAST_EXPECT(s2 > "1"); + BEAST_EXPECT("10" > s1); + BEAST_EXPECT("1" < s2); + BEAST_EXPECT(s1 < "20"); + BEAST_EXPECT(s2 > "1"); + BEAST_EXPECT(s2 > "2"); + } + { + str2 s1("x"); + str2 s2("x"); + BEAST_EXPECT(s1 == s2); + BEAST_EXPECT(s1 <= s2); + BEAST_EXPECT(s1 >= s2); + BEAST_EXPECT(! (s1 < s2)); + BEAST_EXPECT(! (s1 > s2)); + BEAST_EXPECT(! (s1 != s2)); + } + { + str1 s1("x"); + str2 s2("x"); + BEAST_EXPECT(s1 == s2); + BEAST_EXPECT(s1 <= s2); + BEAST_EXPECT(s1 >= s2); + BEAST_EXPECT(! (s1 < s2)); + BEAST_EXPECT(! (s1 > s2)); + BEAST_EXPECT(! (s1 != s2)); + } + { + str2 s("x"); + BEAST_EXPECT(s == "x"); + BEAST_EXPECT(s <= "x"); + BEAST_EXPECT(s >= "x"); + BEAST_EXPECT(! (s < "x")); + BEAST_EXPECT(! (s > "x")); + BEAST_EXPECT(! (s != "x")); + BEAST_EXPECT("x" == s); + BEAST_EXPECT("x" <= s); + BEAST_EXPECT("x" >= s); + BEAST_EXPECT(! ("x" < s)); + BEAST_EXPECT(! ("x" > s)); + BEAST_EXPECT(! ("x" != s)); + } + { + str2 s("x"); + BEAST_EXPECT(s <= "y"); + BEAST_EXPECT(s < "y"); + BEAST_EXPECT(s != "y"); + BEAST_EXPECT(! (s == "y")); + BEAST_EXPECT(! (s >= "y")); + BEAST_EXPECT(! (s > "x")); + BEAST_EXPECT("y" >= s); + BEAST_EXPECT("y" > s); + BEAST_EXPECT("y" != s); + BEAST_EXPECT(! ("y" == s)); + BEAST_EXPECT(! ("y" <= s)); + BEAST_EXPECT(! ("y" < s)); + } + { + str1 s1("x"); + str2 s2("y"); + BEAST_EXPECT(s1 <= s2); + BEAST_EXPECT(s1 < s2); + BEAST_EXPECT(s1 != s2); + BEAST_EXPECT(! (s1 == s2)); + BEAST_EXPECT(! (s1 >= s2)); + BEAST_EXPECT(! (s1 > s2)); + } + { + str1 s1("x"); + str2 s2("xx"); + BEAST_EXPECT(s1 < s2); + BEAST_EXPECT(s2 > s1); + } + { + str1 s1("x"); + str2 s2("yy"); + BEAST_EXPECT(s1 < s2); + BEAST_EXPECT(s2 > s1); + } + } + + void + testSwap() + { + { + fixed_string<3> s1("123"); + fixed_string<3> s2("XYZ"); + swap(s1, s2); + BEAST_EXPECT(s1 == "XYZ"); + BEAST_EXPECT(*s1.end() == 0); + BEAST_EXPECT(s2 == "123"); + BEAST_EXPECT(*s2.end() == 0); + fixed_string<3> s3("UV"); + swap(s2, s3); + BEAST_EXPECT(s2 == "UV"); + BEAST_EXPECT(*s2.end() == 0); + BEAST_EXPECT(s3 == "123"); + BEAST_EXPECT(*s3.end() == 0); + } + { + fixed_string<5> s1("123"); + fixed_string<7> s2("XYZ"); + swap(s1, s2); + BEAST_EXPECT(s1 == "XYZ"); + BEAST_EXPECT(*s1.end() == 0); + BEAST_EXPECT(s2 == "123"); + BEAST_EXPECT(*s2.end() == 0); + fixed_string<3> s3("UV"); + swap(s2, s3); + BEAST_EXPECT(s2 == "UV"); + BEAST_EXPECT(*s2.end() == 0); + BEAST_EXPECT(s3 == "123"); + BEAST_EXPECT(*s3.end() == 0); + try + { + fixed_string<5> s4("12345"); + fixed_string<3> s5("XYZ"); + swap(s4, s5); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + try + { + fixed_string<3> s4("XYZ"); + fixed_string<5> s5("12345"); + swap(s4, s5); + fail("", __FILE__, __LINE__); + } + catch(std::length_error const&) + { + pass(); + } + } + } + + void + testGeneral() + { + using str1 = fixed_string<1>; + using str2 = fixed_string<2>; + { + str1 s1; + BEAST_EXPECT(s1 == ""); + BEAST_EXPECT(s1.empty()); + BEAST_EXPECT(s1.size() == 0); + BEAST_EXPECT(s1.max_size() == 1); + BEAST_EXPECT(s1.capacity() == 1); + BEAST_EXPECT(s1.begin() == s1.end()); + BEAST_EXPECT(s1.cbegin() == s1.cend()); + BEAST_EXPECT(s1.rbegin() == s1.rend()); + BEAST_EXPECT(s1.crbegin() == s1.crend()); + try + { + BEAST_EXPECT(s1.at(0) == 0); + fail(); + } + catch(std::exception const&) + { + pass(); + } + BEAST_EXPECT(s1.data()[0] == 0); + BEAST_EXPECT(*s1.c_str() == 0); + BEAST_EXPECT(std::distance(s1.begin(), s1.end()) == 0); + BEAST_EXPECT(std::distance(s1.cbegin(), s1.cend()) == 0); + BEAST_EXPECT(std::distance(s1.rbegin(), s1.rend()) == 0); + BEAST_EXPECT(std::distance(s1.crbegin(), s1.crend()) == 0); + BEAST_EXPECT(s1.compare(s1) == 0); + } + { + str1 const s1; + BEAST_EXPECT(s1 == ""); + BEAST_EXPECT(s1.empty()); + BEAST_EXPECT(s1.size() == 0); + BEAST_EXPECT(s1.max_size() == 1); + BEAST_EXPECT(s1.capacity() == 1); + BEAST_EXPECT(s1.begin() == s1.end()); + BEAST_EXPECT(s1.cbegin() == s1.cend()); + BEAST_EXPECT(s1.rbegin() == s1.rend()); + BEAST_EXPECT(s1.crbegin() == s1.crend()); + try + { + BEAST_EXPECT(s1.at(0) == 0); + fail(); + } + catch(std::exception const&) + { + pass(); + } + BEAST_EXPECT(s1.data()[0] == 0); + BEAST_EXPECT(*s1.c_str() == 0); + BEAST_EXPECT(std::distance(s1.begin(), s1.end()) == 0); + BEAST_EXPECT(std::distance(s1.cbegin(), s1.cend()) == 0); + BEAST_EXPECT(std::distance(s1.rbegin(), s1.rend()) == 0); + BEAST_EXPECT(std::distance(s1.crbegin(), s1.crend()) == 0); + BEAST_EXPECT(s1.compare(s1) == 0); + } + { + str1 s1; + str1 s2("x"); + BEAST_EXPECT(s2 == "x"); + BEAST_EXPECT(s2[0] == 'x'); + BEAST_EXPECT(s2.at(0) == 'x'); + BEAST_EXPECT(s2.front() == 'x'); + BEAST_EXPECT(s2.back() == 'x'); + str1 const s3(s2); + BEAST_EXPECT(s3 == "x"); + BEAST_EXPECT(s3[0] == 'x'); + BEAST_EXPECT(s3.at(0) == 'x'); + BEAST_EXPECT(s3.front() == 'x'); + BEAST_EXPECT(s3.back() == 'x'); + s2 = "y"; + BEAST_EXPECT(s2 == "y"); + BEAST_EXPECT(s3 == "x"); + s1 = s2; + BEAST_EXPECT(s1 == "y"); + s1.clear(); + BEAST_EXPECT(s1.empty()); + BEAST_EXPECT(s1.size() == 0); + } + { + str2 s1("x"); + str1 s2(s1); + BEAST_EXPECT(s2 == "x"); + str1 s3; + s3 = s2; + BEAST_EXPECT(s3 == "x"); + s1 = "xy"; + BEAST_EXPECT(s1.size() == 2); + BEAST_EXPECT(s1[0] == 'x'); + BEAST_EXPECT(s1[1] == 'y'); + BEAST_EXPECT(s1.at(0) == 'x'); + BEAST_EXPECT(s1.at(1) == 'y'); + BEAST_EXPECT(s1.front() == 'x'); + BEAST_EXPECT(s1.back() == 'y'); + auto const s4 = s1; + BEAST_EXPECT(s4[0] == 'x'); + BEAST_EXPECT(s4[1] == 'y'); + BEAST_EXPECT(s4.at(0) == 'x'); + BEAST_EXPECT(s4.at(1) == 'y'); + BEAST_EXPECT(s4.front() == 'x'); + BEAST_EXPECT(s4.back() == 'y'); + try + { + s3 = s1; + fail(); + } + catch(std::exception const&) + { + pass(); + } + try + { + str1 s5(s1); + fail(); + } + catch(std::exception const&) + { + pass(); + } + } + { + str1 s1("x"); + str2 s2; + s2 = s1; + try + { + s1.resize(2); + fail(); + } + catch(std::length_error const&) + { + pass(); + } + } + pass(); + } + + void + testToStaticString() + { + BEAST_EXPECT(to_fixed_string(0) == "0"); + BEAST_EXPECT(to_fixed_string(1) == "1"); + BEAST_EXPECT(to_fixed_string(0xffff) == "65535"); + BEAST_EXPECT(to_fixed_string(0x10000) == "65536"); + BEAST_EXPECT(to_fixed_string(0xffffffff) == "4294967295"); + + BEAST_EXPECT(to_fixed_string(-1) == "-1"); + BEAST_EXPECT(to_fixed_string(-65535) == "-65535"); + BEAST_EXPECT(to_fixed_string(-65536) == "-65536"); + BEAST_EXPECT(to_fixed_string(-4294967295ll) == "-4294967295"); + + BEAST_EXPECT(to_fixed_string(0) == "0"); + BEAST_EXPECT(to_fixed_string(1) == "1"); + BEAST_EXPECT(to_fixed_string(0xffff) == "65535"); + BEAST_EXPECT(to_fixed_string(0x10000) == "65536"); + BEAST_EXPECT(to_fixed_string(0xffffffff) == "4294967295"); + } + + void + run() override + { + testConstruct(); + testAssign(); + testAccess(); + testIterators(); + testCapacity(); + testOperations(); + testCompare(); + testSwap(); + + testGeneral(); + testToStaticString(); + } +}; + +BEAST_DEFINE_TESTSUITE(boost,fixed_string,fixed_string); + +} // fixed_string +} // boost diff --git a/test/lib.cpp b/test/lib.cpp new file mode 100644 index 0000000..25703a1 --- /dev/null +++ b/test/lib.cpp @@ -0,0 +1,11 @@ +// +// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/fixed_string +// + +#include +