diff --git a/CHANGELOG.md b/CHANGELOG.md index 17e53921e..2179a18c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ # Unreleased + - Changes from 5.23.0 + - Infrastructure + - CHANGED: Bundled protozero updated to v1.7.0. [#5858](https://github.com/Project-OSRM/osrm-backend/pull/5858) # 5.23.0 - Changes from 5.22.0 diff --git a/third_party/protozero/.clang-tidy b/third_party/protozero/.clang-tidy index 1ba914c7c..2bf058632 100644 --- a/third_party/protozero/.clang-tidy +++ b/third_party/protozero/.clang-tidy @@ -1,14 +1,33 @@ --- -Checks: '*,-cert-dcl21-cpp,-cert-err60-cpp,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-type-reinterpret-cast,-fuchsia-*,-google-runtime-references,-hicpp-no-array-decay' +Checks: '*,-bugprone-signed-char-misuse,-cert-dcl21-cpp,-cert-err58-cpp,-cert-err60-cpp,-cppcoreguidelines-avoid-c-arrays,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-macro-usage,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-type-reinterpret-cast,-fuchsia-*,-google-runtime-references,-hicpp-avoid-c-arrays,-hicpp-no-array-decay,-hicpp-vararg,-modernize-avoid-c-arrays,-modernize-use-trailing-return-type,-readability-implicit-bool-conversion,-readability-magic-numbers' # # Disabled checks: # +# bugprone-signed-char-misuse +# Lots of warnings in varint.hpp otherwise. +# # cert-dcl21-cpp # It is unclear whether this is still a good recommendation in modern C++. # +# cert-err58-cpp +# Due to the Catch2 test framework. +# # cert-err60-cpp # Reports std::runtime_error as broken which we can't do anything about. # +# cppcoreguidelines-avoid-c-arrays +# hicpp-avoid-c-arrays +# modernize-avoid-c-arrays +# Makes sense for some array, but especially for char arrays using +# std::array isn't a good solution. +# +# cppcoreguidelines-avoid-magic-numbers +# readability-magic-numbers +# Good idea, but it goes too far to force this everywhere. +# +# cppcoreguidelines-macro-usage +# There are cases where macros are simply needed. +# # cppcoreguidelines-pro-bounds-array-to-pointer-decay # Limited use and many false positives including for all asserts. # @@ -28,6 +47,12 @@ Checks: '*,-cert-dcl21-cpp,-cert-err60-cpp,-cppcoreguidelines-pro-bounds-pointer # hicpp-no-array-decay # Limited use and many false positives including for all asserts. # +# modernize-use-trailing-return-type +# We are not quite that modern. +# +# readability-implicit-bool-conversion +# Not necessarily more readable. +# WarningsAsErrors: '*' HeaderFilterRegex: '\/include\/' AnalyzeTemporaryDtors: false diff --git a/third_party/protozero/.travis.yml b/third_party/protozero/.travis.yml index 891e59bba..e0e94d8e7 100644 --- a/third_party/protozero/.travis.yml +++ b/third_party/protozero/.travis.yml @@ -6,10 +6,6 @@ language: generic -sudo: false - -dist: trusty - #----------------------------------------------------------------------------- # Save common build configurations as shortcuts, so we can reference them later. @@ -17,147 +13,265 @@ addons_shortcuts: addons_clang35: &clang35 apt: sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.5' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-3.5' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-3.5' ] addons_clang38: &clang38 apt: - sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.8' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-3.8' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-3.8' ] addons_clang39: &clang39 apt: - sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-3.9' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-3.9' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-3.9' ] addons_clang40: &clang40 apt: - sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-4.0' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-4.0' ] + sources: [ 'ubuntu-toolchain-r-test' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-4.0' ] addons_clang50: &clang50 apt: - sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'clang-5.0', 'clang-tidy-5.0' ] - addons_gcc47: &gcc47 + sources: [ 'ubuntu-toolchain-r-test' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-5.0' ] + addons_clang60: &clang60 apt: sources: [ 'ubuntu-toolchain-r-test' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-4.7', 'gcc-4.7' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-6.0' ] + addons_clang7: &clang7 + apt: + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-7' ] + addons_clang8: &clang8 + apt: + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-8' ] + addons_clang9: &clang9 + apt: + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'clang-9', 'clang-tidy-9' ] addons_gcc48: &gcc48 apt: sources: [ 'ubuntu-toolchain-r-test' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-4.8', 'gcc-4.8' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'g++-4.8', 'gcc-4.8' ] addons_gcc49: &gcc49 apt: sources: [ 'ubuntu-toolchain-r-test' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-4.9', 'gcc-4.9' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'g++-4.9', 'gcc-4.9' ] addons_gcc5: &gcc5 apt: sources: [ 'ubuntu-toolchain-r-test' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-5', 'gcc-5' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'g++-5', 'gcc-5' ] addons_gcc6: &gcc6 apt: sources: [ 'ubuntu-toolchain-r-test' ] - packages: [ 'libprotobuf-dev','protobuf-compiler', 'g++-6', 'gcc-6' ] + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'g++-6', 'gcc-6' ] + addons_gcc7: &gcc7 + apt: + packages: [ 'libprotobuf-dev', 'protobuf-compiler' ] + addons_gcc8: &gcc8 + apt: + packages: [ 'libprotobuf-dev', 'protobuf-compiler', 'g++-8', 'gcc-8' ] #----------------------------------------------------------------------------- -matrix: +jobs: include: - os: linux + dist: trusty compiler: "clang-3.5" - env: BUILD='Debug' CC=clang-3.5 CXX=clang++-3.5 + env: BUILD=Debug CC=clang-3.5 CXX=clang++-3.5 addons: *clang35 + - os: linux + dist: xenial compiler: "clang-3.8" - env: BUILD='Debug' CC=clang-3.8 CXX=clang++-3.8 + env: BUILD=Debug CC=clang-3.8 CXX=clang++-3.8 addons: *clang38 + - os: linux + dist: xenial compiler: "clang-3.9" - env: BUILD='Debug' CC=clang-3.9 CXX=clang++-3.9 + env: BUILD=Debug CC=clang-3.9 CXX=clang++-3.9 addons: *clang39 + - os: linux + dist: xenial compiler: "clang-4.0" - env: BUILD='Debug' CC=clang-4.0 CXX=clang++-4.0 + env: BUILD=Debug CC=clang-4.0 CXX=clang++-4.0 addons: *clang40 + - os: linux + dist: xenial compiler: "clang-5.0" - env: BUILD='Debug' CC=clang-5.0 CXX=clang++-5.0 - CLANG_TIDY=clang-tidy-5.0 + env: BUILD=Debug CC=clang-5.0 CXX=clang++-5.0 addons: *clang50 + - os: linux - compiler: "clang-5.0" - env: BUILD='Release' CC=clang-5.0 CXX=clang++-5.0 - addons: *clang50 + dist: xenial + compiler: "clang-6.0" + env: BUILD=Debug CC=clang-6.0 CXX=clang++-6.0 + addons: *clang60 + - os: linux - compiler: "clang-5.0" - env: BUILD='Debug' CC=clang-5.0 CXX=clang++-5.0 + dist: bionic + compiler: "clang-7" + env: BUILD=Debug CC=clang-7 CXX=clang++-7 + addons: *clang7 + + - os: linux + dist: bionic + compiler: "clang-8" + env: BUILD=Debug CC=clang-8 CXX=clang++-8 + addons: *clang8 + + - os: linux + dist: bionic + compiler: "clang-9" + env: BUILD=Debug CC=clang-9 CXX=clang++-9 + CLANG_TIDY=clang-tidy-9 + addons: *clang9 + + - os: linux + dist: bionic + compiler: "clang-9" + env: BUILD=Debug CC=clang-9 CXX=clang++-9 CXXFLAGS="-fsanitize=address,undefined,integer -fno-sanitize-recover=all -fno-omit-frame-pointer" LDFLAGS="-fsanitize=address,undefined,integer" - # LSAN doesn't work on container-based system - sudo: required - addons: *clang50 + addons: *clang9 + - os: linux - compiler: "gcc-4.7" - env: BUILD='Debug' CC=gcc-4.7 CXX=g++-4.7 - addons: *gcc47 + dist: bionic + compiler: "clang-9" + env: BUILD=Release CC=clang-9 CXX=clang++-9 + addons: *clang9 + - os: linux + arch: arm64 + dist: bionic + compiler: "clang-9" + env: BUILD=Debug CC=clang-9 CXX=clang++-9 + CXXFLAGS="-fsanitize=address,undefined,integer -fno-sanitize-recover=all -fno-omit-frame-pointer" + LDFLAGS="-fsanitize=address,undefined,integer" + addons: *clang9 + + - os: linux + arch: ppc64le + dist: bionic + compiler: "clang-9" + env: BUILD=Debug CC=clang-9 CXX=clang++-9 + CXXFLAGS="-fsanitize=address,undefined,integer -fno-sanitize-recover=all -fno-omit-frame-pointer" + LDFLAGS="-fsanitize=address,undefined,integer" + addons: *clang9 + + - os: linux + arch: s390x + dist: bionic + compiler: "clang-9" + env: BUILD=Debug CC=clang-9 CXX=clang++-9 + CXXFLAGS="-fsanitize=address,undefined,integer -fno-sanitize-recover=all -fno-omit-frame-pointer" + LDFLAGS="-fsanitize=address,undefined,integer" + addons: *clang9 + + - os: linux + dist: trusty compiler: "gcc-4.8" - env: BUILD='Debug' CC=gcc-4.8 CXX=g++-4.8 + env: BUILD=Debug CC=gcc-4.8 CXX=g++-4.8 addons: *gcc48 + - os: linux + dist: trusty compiler: "gcc-4.9" - env: BUILD='Debug' CC=gcc-4.9 CXX=g++-4.9 - COVERAGE=gcov-4.9 - CXXFLAGS="--coverage" LDFLAGS="--coverage" + env: BUILD=Debug CC=gcc-4.9 CXX=g++-4.9 addons: *gcc49 + - os: linux + dist: trusty compiler: "gcc-5" - env: BUILD='Debug' CC=gcc-5 CXX=g++-5 + env: BUILD=Debug CC=gcc-5 CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0" addons: *gcc5 + - os: linux + dist: xenial compiler: "gcc-5" - env: BUILD='Debug' CC=gcc-5 CXX=g++-5 + env: BUILD=Debug CC=gcc-5 CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=1" addons: *gcc5 + - os: linux + dist: xenial compiler: "gcc-6" - env: BUILD='Debug' CC=gcc-6 CXX=g++-6 + env: BUILD=Debug CC=gcc-6 CXX=g++-6 addons: *gcc6 + - os: linux - compiler: "gcc-6" - env: BUILD='Debug' CC=gcc-6 CXX=g++-6 - PROTOZERO_DATA_VIEW=std::experimental::string_view - addons: *gcc6 + dist: bionic + compiler: "gcc-7" + env: BUILD=Debug CC=gcc-7 CXX=g++-7 + addons: *gcc7 + - os: linux - compiler: "gcc-6" - env: BUILD='Release' CC=gcc-6 CXX=g++-6 - addons: *gcc6 + dist: bionic + compiler: "gcc-8" + env: BUILD=Debug CC=gcc-8 CXX=g++-8 + addons: *gcc8 + + - os: linux + dist: bionic + compiler: "gcc-8" + env: BUILD=Debug CC=gcc-8 CXX=g++-8 + COVERAGE=gcov-8 + CXXFLAGS="--coverage" LDFLAGS="--coverage" + addons: *gcc8 + + - os: linux + dist: bionic + compiler: "gcc-8" + env: BUILD=Debug CC=gcc-8 CXX=g++-8 + PROTOZERO_DATA_VIEW=std::string_view + addons: *gcc8 + + - os: linux + dist: bionic + compiler: "gcc-8" + env: BUILD=Release CC=gcc-8 CXX=g++-8 + addons: *gcc8 + + - os: linux + arch: arm64 + dist: bionic + compiler: "gcc-8" + env: BUILD=Debug CC=gcc-8 CXX=g++-8 + addons: *gcc8 + + - os: linux + arch: ppc64le + dist: bionic + compiler: "gcc-8" + env: BUILD=Debug CC=gcc-8 CXX=g++-8 + addons: *gcc8 + + - os: linux + arch: s390x + dist: bionic + compiler: "gcc-8" + env: BUILD=Debug CC=gcc-8 CXX=g++-8 + addons: *gcc8 + - os: osx - osx_image: xcode6.4 + osx_image: xcode9.4 compiler: clang - env: BUILD='Debug' + env: BUILD=Debug + - os: osx - osx_image: xcode7.3 + osx_image: xcode10.3 compiler: clang - env: BUILD='Debug' + env: BUILD=Debug + - os: osx - osx_image: xcode8.3 + osx_image: xcode11.4 compiler: clang - env: BUILD='Debug' + env: BUILD=Debug + - os: osx - osx_image: xcode9.1 + osx_image: xcode11.4 compiler: clang - env: BUILD='Debug' - - os: osx - osx_image: xcode9.1 - compiler: clang - env: BUILD='Release' + env: BUILD=Release #----------------------------------------------------------------------------- -install: - - if [[ $(uname -s) == 'Darwin' ]]; then - brew update; - brew install protobuf; - fi - script: - mkdir build - cd build diff --git a/third_party/protozero/CHANGELOG.md b/third_party/protozero/CHANGELOG.md index d43f422b6..cfdb6a647 100644 --- a/third_party/protozero/CHANGELOG.md +++ b/third_party/protozero/CHANGELOG.md @@ -5,7 +5,6 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) This project adheres to [Semantic Versioning](http://semver.org/). - ## [unreleased] - ### Added @@ -15,6 +14,87 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed +## [1.7.0] - 2020-06-08 + +### Added + +- Support for buffer types other that `std::string`. `pbf_writer` is now + just a typedef for `basic_pbf_writer`. Other buffer types + can be used with `basic_pbf_writer`. See `doc/advanced.md` for details. + +### Changed + +- Switched to *catch2* for testing. +- Some minor tweaks. + +### Fixed + +- Removed some undefined behaviour. + + +## [1.6.8] - 2019-08-15 + +### Changed + +- Various code cleanups due to clang-tidy warnings. + +### Fixed + +- Made `data_view::compare` noexcept. + + +## [1.6.7] - 2018-02-21 + +### Fixed + +- Signed-unsigned comparison on 32 bit systems. + + +## [1.6.6] - 2018-02-20 + +### Fixed + +- Fixed several place with possible undefined behaviour. + + +## [1.6.5] - 2018-02-05 + +### Fixed + +- Avoid UB: Do not calculate pointer outside array bounds. +- Specify proto2 syntax in .proto files to appease protoc. + + +## [1.6.4] - 2018-11-08 + +### Added + +- Add function `data()` to get the not yet read data from a `pbf_reader`. +- New `add_packed_fixed()` template function for `pbf_writer`. +- New `length_of_varint()` helper function calculates how long a varint + would be for a specified value. + +### Changed + +- More consistent implementation of operators as free friend functions. + +### Fixed + +- Fixed some zigzag encoding tests on MSVC. +- Add extra cast so we do an xor with unsigned ints. +- No more bitwise operations on signed integers in varint decoder. +- No more bitwise operations on signed integers in zigzag encoder/decoder. + + +## [1.6.3] - 2018-07-17 + +### Changed + +- Moved `byteswap_inplace` functions from detail into protozero namespace. + They can be useful outsize protozero. +- More asserts and unit tests and small cleanups. + + ## [1.6.2] - 2018-03-09 ### Changed @@ -301,7 +381,14 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Make pbf reader and writer code endianess-aware. -[unreleased]: https://github.com/osmcode/libosmium/compare/v1.6.2...HEAD +[unreleased]: https://github.com/osmcode/libosmium/compare/v1.7.0...HEAD +[1.7.0]: https://github.com/osmcode/libosmium/compare/v1.6.8...v1.7.0 +[1.6.8]: https://github.com/osmcode/libosmium/compare/v1.6.7...v1.6.8 +[1.6.7]: https://github.com/osmcode/libosmium/compare/v1.6.6...v1.6.7 +[1.6.6]: https://github.com/osmcode/libosmium/compare/v1.6.5...v1.6.6 +[1.6.5]: https://github.com/osmcode/libosmium/compare/v1.6.4...v1.6.5 +[1.6.4]: https://github.com/osmcode/libosmium/compare/v1.6.3...v1.6.4 +[1.6.3]: https://github.com/osmcode/libosmium/compare/v1.6.2...v1.6.3 [1.6.2]: https://github.com/osmcode/libosmium/compare/v1.6.1...v1.6.2 [1.6.1]: https://github.com/osmcode/libosmium/compare/v1.6.0...v1.6.1 [1.6.0]: https://github.com/osmcode/libosmium/compare/v1.5.3...v1.6.0 diff --git a/third_party/protozero/CMakeLists.txt b/third_party/protozero/CMakeLists.txt index 24e293d73..f9702d603 100644 --- a/third_party/protozero/CMakeLists.txt +++ b/third_party/protozero/CMakeLists.txt @@ -13,8 +13,8 @@ cmake_minimum_required(VERSION 2.8 FATAL_ERROR) project(protozero) set(PROTOZERO_VERSION_MAJOR 1) -set(PROTOZERO_VERSION_MINOR 6) -set(PROTOZERO_VERSION_PATCH 2) +set(PROTOZERO_VERSION_MINOR 7) +set(PROTOZERO_VERSION_PATCH 0) set(PROTOZERO_VERSION "${PROTOZERO_VERSION_MAJOR}.${PROTOZERO_VERSION_MINOR}.${PROTOZERO_VERSION_PATCH}") @@ -26,7 +26,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) option(WERROR "Add -Werror flag to build (turns warnings into errors)" ON) if(MSVC) - add_definitions(-std=c++11 /W3) + add_definitions(/W3) add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) else() add_definitions(-std=c++11 -Wall -Wextra -pedantic -Wsign-compare -Wunused-parameter -Wno-float-equal -Wno-covered-switch-default) @@ -58,7 +58,7 @@ find_package(Protobuf) # #----------------------------------------------------------------------------- message(STATUS "Looking for clang-tidy") -find_program(CLANG_TIDY NAMES clang-tidy clang-tidy-6.0 clang-tidy-5.0) +find_program(CLANG_TIDY NAMES clang-tidy clang-tidy-10 clang-tidy-9 clang-tidy-8 clang-tidy-7 clang-tidy-6.0 clang-tidy-5.0) if(CLANG_TIDY) message(STATUS "Looking for clang-tidy - found ${CLANG_TIDY}") @@ -66,7 +66,8 @@ if(CLANG_TIDY) ${CLANG_TIDY} -p ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/test/*.cpp - ${CMAKE_SOURCE_DIR}/test/t/*/*.cpp + ${CMAKE_SOURCE_DIR}/test/t/*/reader_test_cases.cpp + ${CMAKE_SOURCE_DIR}/test/t/*/writer_test_cases.cpp ${CMAKE_SOURCE_DIR}/test/unit/*.cpp ${CMAKE_SOURCE_DIR}/tools/*.cpp ) diff --git a/third_party/protozero/README.md b/third_party/protozero/README.md index 63972e0a6..d6e982751 100644 --- a/third_party/protozero/README.md +++ b/third_party/protozero/README.md @@ -56,9 +56,9 @@ You have to have a working knowledge of how * Read the [upgrading instructions](UPGRADING.md) if you are upgrading from an older version of Protozero. -The build process will also build the Doxygen-based reference documentation -if you have [Doxygen](http://www.stack.nl/~dimitri/doxygen/) installed. Then -open `doc/html/index.html` in your browser to read it. +The build process will also build the Doxygen-based reference documentation if +you have Doxygen installed. Then open `doc/html/index.html` in your browser to +read it. ## Endianness diff --git a/third_party/protozero/UPGRADING.md b/third_party/protozero/UPGRADING.md index 9a5db8ee9..bf9040809 100644 --- a/third_party/protozero/UPGRADING.md +++ b/third_party/protozero/UPGRADING.md @@ -13,6 +13,11 @@ macro `PROTOZERO_STRICT_API` in which case Protozero will compile without the code used for backwards compatibilty. You will then get compile errors for older API usages. +## Upgrading from *v1.6* to *v1.7* + +* The `pbf_writer` class is now a typedef for `basic_pbf_writer` + If you have forward declared it in your code, it might have to change. + ## Upgrading from *v1.5* to *v1.6.0* * The `data_view` class moved from `types.hpp` into its own header file diff --git a/third_party/protozero/appveyor.yml b/third_party/protozero/appveyor.yml index 3c3dc7bce..4f3cb4a21 100644 --- a/third_party/protozero/appveyor.yml +++ b/third_party/protozero/appveyor.yml @@ -24,6 +24,9 @@ environment: autocrlf: false - config: RelWithDebInfo autocrlf: false + - config: Debug + autocrlf: false + platform: x86 #----------------------------------------------------------------------------- @@ -36,22 +39,32 @@ init: # halts: "msys2-runtime and catgets are in conflict. Remove catgets?" # See also: https://github.com/Alexpux/MSYS2-packages/issues/1141 install: - - if [%config%]==[MSYS2] ( - C:\msys64\usr\bin\pacman --noconfirm --sync --refresh --refresh --sysupgrade --sysupgrade --ask=20 - && C:\msys64\usr\bin\pacman -Rc --noconfirm mingw-w64-x86_64-gcc-libs + - if "%config%"=="MSYS2" ( + set "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%" && + pacman --noconfirm --sync --refresh --refresh --sysupgrade --sysupgrade --ask=20 && + pacman -Rc --noconfirm mingw-w64-x86_64-gcc-libs && + pacman -S --needed --noconfirm mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-doxygen mingw-w64-x86_64-protobuf ) build_script: - - if [%config%]==[MSYS2] ( - build-msys2.bat + - cd c:\projects\protozero + - mkdir build + - cd build + - if "%platform%"=="x64" ( + set vcvarsall_arg=amd64 ) else ( - build-appveyor.bat + set vcvarsall_arg=x86 + ) + - if "%config%"=="MSYS2" ( + cmake .. -LA -G "MSYS Makefiles" && + make VERBOSE=1 + ) else ( + "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall" %vcvarsall_arg% && + cmake .. -LA -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=%config% && + nmake VERBOSE=1 ) -# remove garbage VS messages -# http://help.appveyor.com/discussions/problems/4569-the-target-_convertpdbfiles-listed-in-a-beforetargets-attribute-at-c-does-not-exist-in-the-project-and-will-be-ignored -before_build: - - del "C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.targets\ImportAfter\Xamarin.Common.targets" - +test_script: + - ctest --output-on-failure #----------------------------------------------------------------------------- diff --git a/third_party/protozero/build-appveyor.bat b/third_party/protozero/build-appveyor.bat deleted file mode 100644 index 76e848c29..000000000 --- a/third_party/protozero/build-appveyor.bat +++ /dev/null @@ -1,65 +0,0 @@ -@ECHO OFF -SETLOCAL -SET EL=0 - -ECHO ~~~~~~ %~f0 ~~~~~~ - -::show all available env vars -SET -ECHO cmake on AppVeyor -cmake -version - -ECHO activating VS cmd prompt && CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64 -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -SET protobuf_sdk=protozero-dep-protobuf-2.6.1.7z -IF EXIST %protobuf_sdk% (ECHO protobuf already downloaded) ELSE (ECHO downloading protobuf ... && powershell Invoke-WebRequest https://mapbox.s3.amazonaws.com/windows-builds/windows-build-deps/$env:protobuf_sdk -OutFile $pwd\$env:protobuf_sdk) -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -IF EXIST deps\protobuf (ECHO protobuf already extracted) ELSE (CALL 7z x -y %protobuf_sdk% | %windir%\system32\FIND "ing archive") -IF %ERRORLEVEL% NEQ 0 GOTO ERROR -SET PATH=%~dp0deps\protobuf;%PATH% - -IF EXIST build ECHO deleting build dir... && RD /Q /S build -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -MKDIR build -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -CD build -ECHO config^: %config% - -::This will produce lots of LNK4099 warnings which can be ignored. -::Unfortunately they can't be disabled, see -::http://stackoverflow.com/questions/661606/visual-c-how-to-disable-specific-linker-warnings -SET CMAKE_CMD=cmake .. ^ --LA -G "Visual Studio 14 Win64" - -ECHO calling^: %CMAKE_CMD% -%CMAKE_CMD% -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -SET avlogger= -IF /I "%APPVEYOR%"=="True" SET avlogger=/logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" - -msbuild protozero.sln ^ -/p:Configuration=%config% ^ -/toolsversion:14.0 ^ -/p:Platform=x64 ^ -/p:PlatformToolset=v140 %avlogger% -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -ctest --output-on-failure ^ --C %config% ^ -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -GOTO DONE - -:ERROR -ECHO ~~~~~~ ERROR %~f0 ~~~~~~ -SET EL=%ERRORLEVEL% - -:DONE -IF %EL% NEQ 0 ECHO. && ECHO !!! ERRORLEVEL^: %EL% !!! && ECHO. -ECHO ~~~~~~ DONE %~f0 ~~~~~~ - -EXIT /b %EL% diff --git a/third_party/protozero/build-local.bat b/third_party/protozero/build-local.bat deleted file mode 100644 index 62db254ac..000000000 --- a/third_party/protozero/build-local.bat +++ /dev/null @@ -1,29 +0,0 @@ -@ECHO OFF -SETLOCAL -SET EL=0 - -ECHO =========== %~f0 =========== - -SET VERBOSITY_MSBUILD=diagnostic -IF NOT "%1"=="" SET VERBOSITY_MSBUILD=%1 -SET platform=x64 -SET configuration=Release -CALL build-appveyor.bat %VERBOSITY_MSBUILD% -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -SET platform=x86 -SET configuration=Debug -CALL build-appveyor.bat %VERBOSITY_MSBUILD% -IF %ERRORLEVEL% NEQ 0 GOTO ERROR - -GOTO DONE - -:ERROR -ECHO =========== ERROR %~f0 =========== -ECHO ERRORLEVEL^: %ERRORLEVEL% -SET EL=%ERRORLEVEL% - -:DONE -ECHO =========== DONE %~f0 =========== - -EXIT /b %EL% diff --git a/third_party/protozero/build-msys2.bat b/third_party/protozero/build-msys2.bat deleted file mode 100644 index 1a02156b5..000000000 --- a/third_party/protozero/build-msys2.bat +++ /dev/null @@ -1,18 +0,0 @@ -echo "Adding MSYS2 to path..." -SET "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%" -echo %PATH% - -echo "Installing MSYS2 packages..." -bash -lc "pacman -S --needed --noconfirm mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-doxygen mingw-w64-x86_64-protobuf" - -echo "Generating makefiles" -mkdir build -cd build -cmake .. -LA -G "MSYS Makefiles" - -echo "Building" -make VERBOSE=1 - -echo "Testing" -ctest --output-on-failure - diff --git a/third_party/protozero/doc/Doxyfile.in b/third_party/protozero/doc/Doxyfile.in index 148190551..a23ad7f74 100644 --- a/third_party/protozero/doc/Doxyfile.in +++ b/third_party/protozero/doc/Doxyfile.in @@ -2046,7 +2046,7 @@ EXTERNAL_PAGES = YES # interpreter (i.e. the result of 'which perl'). # The default file (with absolute path) is: /usr/bin/perl. -PERL_PATH = /usr/bin/perl +#PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool @@ -2068,7 +2068,7 @@ CLASS_DIAGRAMS = YES # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. -MSCGEN_PATH = +#MSCGEN_PATH = # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The diff --git a/third_party/protozero/doc/advanced.md b/third_party/protozero/doc/advanced.md index f5a0e1120..d579538d0 100644 --- a/third_party/protozero/doc/advanced.md +++ b/third_party/protozero/doc/advanced.md @@ -269,3 +269,58 @@ still considerably cheaper than decoding the varints. You have to benchmark your use case to see whether the `reserve()` (or whatever you are using the `size()` for) is worth it. + +## Using a different buffer class than std::string + +Normally you are using the `pbf_writer` or `pbf_builder` classes which use a +`std::string` that you supply as their buffer for building the actual protocol +buffers message into. But you can use a different buffer implementation +instead. This might be useful if you want to use a fixed-size buffer for +instance. + +The `pbf_writer` and `pbf_builder` classes are actually only aliases for the +`basic_pbf_writer` and `basic_pbf_builder` template classes: + +```cpp +using pbf_writer = basic_pbf_writer; + +template +using pbf_builder = basic_pbf_builder; +``` + +If you want to use a different buffer type, use the `basic_*` form of the +class and use the buffer class as template parameter. When instantiating the +`basic_pbf_writer` or `basic_pbf_builder`, the only parameter to the +constructor must always be a reference to an object of the buffer class. + +```cpp +some_buffer_class buffer; +basic_pbf_writer writer{buffer}; +``` + +For this to work you must supply template specializations for some static +functions in the `protozero::buffer_customization` struct, see +`buffer_tmpl.hpp` for details. + +Protozero already supports two buffer types: +* `std::string` (to use include `protozero/buffer_string.hpp`) +* `std::vector` (to use include `protozero/buffer_vector.hpp`) + +There is a class `protozero::fixed_size_buffer_adaptor` you can use as adaptor +for any fixed-sized buffer you might have. Include `protozero/buffer_fixed.hpp` +to use it: + +```cpp +#include + +your_buffer_class some_buffer; +protozero::fixed_size_buffer_adaptor buffer_adaptor{some_buffer.data(), some_buffer.size()}; +basic_pbf_writer writer{buffer_adaptor}; +``` + +The buffer adaptor can be initialized with any container if it supports the +`data()` and `size()` member functions: + +```cpp +protozero::fixed_size_buffer_adaptor buffer_adaptor{some_buffer}; +``` diff --git a/third_party/protozero/include/protozero/basic_pbf_builder.hpp b/third_party/protozero/include/protozero/basic_pbf_builder.hpp new file mode 100644 index 000000000..0ede726fa --- /dev/null +++ b/third_party/protozero/include/protozero/basic_pbf_builder.hpp @@ -0,0 +1,266 @@ +#ifndef PROTOZERO_BASIC_PBF_BUILDER_HPP +#define PROTOZERO_BASIC_PBF_BUILDER_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +/** + * @file basic_pbf_builder.hpp + * + * @brief Contains the basic_pbf_builder template class. + */ + +#include "basic_pbf_writer.hpp" +#include "types.hpp" + +#include + +namespace protozero { + +/** + * The basic_pbf_builder is used to write PBF formatted messages into a buffer. + * It is based on the basic_pbf_writer class and has all the same methods. The + * difference is that while the pbf_writer class takes an integer tag, + * this template class takes a tag of the template type T. The idea is that + * T will be an enumeration value and this helps reduce the possibility of + * programming errors. + * + * Almost all methods in this class can throw an std::bad_alloc exception if + * the underlying buffer class wants to resize. + * + * Read the tutorial to understand how this class is used. In most cases you + * want to use the pbf_builder class which uses a std::string as buffer type. + */ +template +class basic_pbf_builder : public basic_pbf_writer { + + static_assert(std::is_same::type>::value, + "T must be enum with underlying type protozero::pbf_tag_type"); + +public: + + /// The type of messages this class will build. + using enum_type = T; + + basic_pbf_builder() = default; + + /** + * Create a builder using the given string as a data store. The object + * stores a reference to that string and adds all data to it. The string + * doesn't have to be empty. The pbf_message object will just append data. + */ + explicit basic_pbf_builder(TBuffer& data) noexcept : + basic_pbf_writer{data} { + } + + /** + * Construct a pbf_builder for a submessage from the pbf_message or + * pbf_writer of the parent message. + * + * @param parent_writer The parent pbf_message or pbf_writer + * @param tag Tag of the field that will be written + */ + template + basic_pbf_builder(basic_pbf_writer& parent_writer, P tag) noexcept : + basic_pbf_writer{parent_writer, pbf_tag_type(tag)} { + } + +/// @cond INTERNAL +#define PROTOZERO_WRITER_WRAP_ADD_SCALAR(name, type) \ + void add_##name(T tag, type value) { \ + basic_pbf_writer::add_##name(pbf_tag_type(tag), value); \ + } + + PROTOZERO_WRITER_WRAP_ADD_SCALAR(bool, bool) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(enum, int32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(int32, int32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(sint32, int32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(uint32, uint32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(int64, int64_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(sint64, int64_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(uint64, uint64_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(fixed32, uint32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(sfixed32, int32_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(fixed64, uint64_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(sfixed64, int64_t) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(float, float) + PROTOZERO_WRITER_WRAP_ADD_SCALAR(double, double) + +#undef PROTOZERO_WRITER_WRAP_ADD_SCALAR +/// @endcond + + /** + * Add "bytes" field to data. + * + * @param tag Tag of the field + * @param value Pointer to value to be written + * @param size Number of bytes to be written + */ + void add_bytes(T tag, const char* value, std::size_t size) { + basic_pbf_writer::add_bytes(pbf_tag_type(tag), value, size); + } + + /** + * Add "bytes" field to data. + * + * @param tag Tag of the field + * @param value Value to be written + */ + void add_bytes(T tag, const data_view& value) { + basic_pbf_writer::add_bytes(pbf_tag_type(tag), value); + } + + /** + * Add "bytes" field to data. + * + * @param tag Tag of the field + * @param value Value to be written + */ + void add_bytes(T tag, const std::string& value) { + basic_pbf_writer::add_bytes(pbf_tag_type(tag), value); + } + + /** + * Add "bytes" field to data. Bytes from the value are written until + * a null byte is encountered. The null byte is not added. + * + * @param tag Tag of the field + * @param value Pointer to zero-delimited value to be written + */ + void add_bytes(T tag, const char* value) { + basic_pbf_writer::add_bytes(pbf_tag_type(tag), value); + } + + /** + * Add "bytes" field to data using vectored input. All the data in the + * 2nd and further arguments is "concatenated" with only a single copy + * into the final buffer. + * + * This will work with objects of any type supporting the data() and + * size() methods like std::string or protozero::data_view. + * + * Example: + * @code + * std::string data1 = "abc"; + * std::string data2 = "xyz"; + * builder.add_bytes_vectored(1, data1, data2); + * @endcode + * + * @tparam Ts List of types supporting data() and size() methods. + * @param tag Tag of the field + * @param values List of objects of types Ts with data to be appended. + */ + template + void add_bytes_vectored(T tag, Ts&&... values) { + basic_pbf_writer::add_bytes_vectored(pbf_tag_type(tag), std::forward(values)...); + } + + /** + * Add "string" field to data. + * + * @param tag Tag of the field + * @param value Pointer to value to be written + * @param size Number of bytes to be written + */ + void add_string(T tag, const char* value, std::size_t size) { + basic_pbf_writer::add_string(pbf_tag_type(tag), value, size); + } + + /** + * Add "string" field to data. + * + * @param tag Tag of the field + * @param value Value to be written + */ + void add_string(T tag, const data_view& value) { + basic_pbf_writer::add_string(pbf_tag_type(tag), value); + } + + /** + * Add "string" field to data. + * + * @param tag Tag of the field + * @param value Value to be written + */ + void add_string(T tag, const std::string& value) { + basic_pbf_writer::add_string(pbf_tag_type(tag), value); + } + + /** + * Add "string" field to data. Bytes from the value are written until + * a null byte is encountered. The null byte is not added. + * + * @param tag Tag of the field + * @param value Pointer to value to be written + */ + void add_string(T tag, const char* value) { + basic_pbf_writer::add_string(pbf_tag_type(tag), value); + } + + /** + * Add "message" field to data. + * + * @param tag Tag of the field + * @param value Pointer to message to be written + * @param size Length of the message + */ + void add_message(T tag, const char* value, std::size_t size) { + basic_pbf_writer::add_message(pbf_tag_type(tag), value, size); + } + + /** + * Add "message" field to data. + * + * @param tag Tag of the field + * @param value Value to be written. The value must be a complete message. + */ + void add_message(T tag, const data_view& value) { + basic_pbf_writer::add_message(pbf_tag_type(tag), value); + } + + /** + * Add "message" field to data. + * + * @param tag Tag of the field + * @param value Value to be written. The value must be a complete message. + */ + void add_message(T tag, const std::string& value) { + basic_pbf_writer::add_message(pbf_tag_type(tag), value); + } + +/// @cond INTERNAL +#define PROTOZERO_WRITER_WRAP_ADD_PACKED(name) \ + template \ + void add_packed_##name(T tag, InputIterator first, InputIterator last) { \ + basic_pbf_writer::add_packed_##name(pbf_tag_type(tag), first, last); \ + } + + PROTOZERO_WRITER_WRAP_ADD_PACKED(bool) + PROTOZERO_WRITER_WRAP_ADD_PACKED(enum) + PROTOZERO_WRITER_WRAP_ADD_PACKED(int32) + PROTOZERO_WRITER_WRAP_ADD_PACKED(sint32) + PROTOZERO_WRITER_WRAP_ADD_PACKED(uint32) + PROTOZERO_WRITER_WRAP_ADD_PACKED(int64) + PROTOZERO_WRITER_WRAP_ADD_PACKED(sint64) + PROTOZERO_WRITER_WRAP_ADD_PACKED(uint64) + PROTOZERO_WRITER_WRAP_ADD_PACKED(fixed32) + PROTOZERO_WRITER_WRAP_ADD_PACKED(sfixed32) + PROTOZERO_WRITER_WRAP_ADD_PACKED(fixed64) + PROTOZERO_WRITER_WRAP_ADD_PACKED(sfixed64) + PROTOZERO_WRITER_WRAP_ADD_PACKED(float) + PROTOZERO_WRITER_WRAP_ADD_PACKED(double) + +#undef PROTOZERO_WRITER_WRAP_ADD_PACKED +/// @endcond + +}; // class basic_pbf_builder + +} // end namespace protozero + +#endif // PROTOZERO_BASIC_PBF_BUILDER_HPP diff --git a/third_party/protozero/include/protozero/basic_pbf_writer.hpp b/third_party/protozero/include/protozero/basic_pbf_writer.hpp new file mode 100644 index 000000000..f167c4d1d --- /dev/null +++ b/third_party/protozero/include/protozero/basic_pbf_writer.hpp @@ -0,0 +1,1054 @@ +#ifndef PROTOZERO_BASIC_PBF_WRITER_HPP +#define PROTOZERO_BASIC_PBF_WRITER_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +/** + * @file basic_pbf_writer.hpp + * + * @brief Contains the basic_pbf_writer template class. + */ + +#include "buffer_tmpl.hpp" +#include "config.hpp" +#include "data_view.hpp" +#include "types.hpp" +#include "varint.hpp" + +#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace protozero { + +namespace detail { + + template class packed_field_varint; + template class packed_field_svarint; + template class packed_field_fixed; + +} // end namespace detail + +/** + * The basic_pbf_writer is used to write PBF formatted messages into a buffer. + * + * This uses TBuffer as the type for the underlaying buffer. In typical uses + * this is std::string, but you can use a different type that must support + * the right interface. Please see the documentation for details. + * + * Almost all methods in this class can throw an std::bad_alloc exception if + * the underlying buffer class wants to resize. + */ +template +class basic_pbf_writer { + + // A pointer to a buffer holding the data already written to the PBF + // message. For default constructed writers or writers that have been + // rolled back, this is a nullptr. + TBuffer* m_data = nullptr; + + // A pointer to a parent writer object if this is a submessage. If this + // is a top-level writer, it is a nullptr. + basic_pbf_writer* m_parent_writer = nullptr; + + // This is usually 0. If there is an open submessage, this is set in the + // parent to the rollback position, ie. the last position before the + // submessage was started. This is the position where the header of the + // submessage starts. + std::size_t m_rollback_pos = 0; + + // This is usually 0. If there is an open submessage, this is set in the + // parent to the position where the data of the submessage is written to. + std::size_t m_pos = 0; + + void add_varint(uint64_t value) { + protozero_assert(m_pos == 0 && "you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage"); + protozero_assert(m_data); + add_varint_to_buffer(m_data, value); + } + + void add_field(pbf_tag_type tag, pbf_wire_type type) { + protozero_assert(((tag > 0 && tag < 19000) || (tag > 19999 && tag <= ((1U << 29U) - 1))) && "tag out of range"); + const uint32_t b = (tag << 3U) | uint32_t(type); + add_varint(b); + } + + void add_tagged_varint(pbf_tag_type tag, uint64_t value) { + add_field(tag, pbf_wire_type::varint); + add_varint(value); + } + + template + void add_fixed(T value) { + protozero_assert(m_pos == 0 && "you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage"); + protozero_assert(m_data); +#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN + byteswap_inplace(&value); +#endif + buffer_customization::append(m_data, reinterpret_cast(&value), sizeof(T)); + } + + template + void add_packed_fixed(pbf_tag_type tag, It first, It last, std::input_iterator_tag /*unused*/) { + if (first == last) { + return; + } + + basic_pbf_writer sw{*this, tag}; + + while (first != last) { + sw.add_fixed(*first++); + } + } + + template + void add_packed_fixed(pbf_tag_type tag, It first, It last, std::forward_iterator_tag /*unused*/) { + if (first == last) { + return; + } + + const auto length = std::distance(first, last); + add_length_varint(tag, sizeof(T) * pbf_length_type(length)); + reserve(sizeof(T) * std::size_t(length)); + + while (first != last) { + add_fixed(*first++); + } + } + + template + void add_packed_varint(pbf_tag_type tag, It first, It last) { + if (first == last) { + return; + } + + basic_pbf_writer sw{*this, tag}; + + while (first != last) { + sw.add_varint(uint64_t(*first++)); + } + } + + template + void add_packed_svarint(pbf_tag_type tag, It first, It last) { + if (first == last) { + return; + } + + basic_pbf_writer sw{*this, tag}; + + while (first != last) { + sw.add_varint(encode_zigzag64(*first++)); + } + } + + // The number of bytes to reserve for the varint holding the length of + // a length-delimited field. The length has to fit into pbf_length_type, + // and a varint needs 8 bit for every 7 bit. + enum : int { + reserve_bytes = sizeof(pbf_length_type) * 8 / 7 + 1 + }; + + // If m_rollpack_pos is set to this special value, it means that when + // the submessage is closed, nothing needs to be done, because the length + // of the submessage has already been written correctly. + enum : std::size_t { + size_is_known = std::numeric_limits::max() + }; + + void open_submessage(pbf_tag_type tag, std::size_t size) { + protozero_assert(m_pos == 0); + protozero_assert(m_data); + if (size == 0) { + m_rollback_pos = buffer_customization::size(m_data); + add_field(tag, pbf_wire_type::length_delimited); + buffer_customization::append_zeros(m_data, std::size_t(reserve_bytes)); + } else { + m_rollback_pos = size_is_known; + add_length_varint(tag, pbf_length_type(size)); + reserve(size); + } + m_pos = buffer_customization::size(m_data); + } + + void rollback_submessage() { + protozero_assert(m_pos != 0); + protozero_assert(m_rollback_pos != size_is_known); + protozero_assert(m_data); + buffer_customization::resize(m_data, m_rollback_pos); + m_pos = 0; + } + + void commit_submessage() { + protozero_assert(m_pos != 0); + protozero_assert(m_rollback_pos != size_is_known); + protozero_assert(m_data); + const auto length = pbf_length_type(buffer_customization::size(m_data) - m_pos); + + protozero_assert(buffer_customization::size(m_data) >= m_pos - reserve_bytes); + const auto n = add_varint_to_buffer(buffer_customization::at_pos(m_data, m_pos - reserve_bytes), length); + + buffer_customization::erase_range(m_data, m_pos - reserve_bytes + n, m_pos); + m_pos = 0; + } + + void close_submessage() { + protozero_assert(m_data); + if (m_pos == 0 || m_rollback_pos == size_is_known) { + return; + } + if (buffer_customization::size(m_data) - m_pos == 0) { + rollback_submessage(); + } else { + commit_submessage(); + } + } + + void add_length_varint(pbf_tag_type tag, pbf_length_type length) { + add_field(tag, pbf_wire_type::length_delimited); + add_varint(length); + } + +public: + + /** + * Create a writer using the specified buffer as a data store. The + * basic_pbf_writer stores a pointer to that buffer and adds all data to + * it. The buffer doesn't have to be empty. The basic_pbf_writer will just + * append data. + */ + explicit basic_pbf_writer(TBuffer& buffer) noexcept : + m_data{&buffer} { + } + + /** + * Create a writer without a data store. In this form the writer can not + * be used! + */ + basic_pbf_writer() noexcept = default; + + /** + * Construct a basic_pbf_writer for a submessage from the basic_pbf_writer + * of the parent message. + * + * @param parent_writer The basic_pbf_writer + * @param tag Tag (field number) of the field that will be written + * @param size Optional size of the submessage in bytes (use 0 for unknown). + * Setting this allows some optimizations but is only possible in + * a few very specific cases. + */ + basic_pbf_writer(basic_pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size = 0) : + m_data{parent_writer.m_data}, + m_parent_writer{&parent_writer} { + m_parent_writer->open_submessage(tag, size); + } + + /// A basic_pbf_writer object can not be copied + basic_pbf_writer(const basic_pbf_writer&) = delete; + + /// A basic_pbf_writer object can not be copied + basic_pbf_writer& operator=(const basic_pbf_writer&) = delete; + + /** + * A basic_pbf_writer object can be moved. After this the other + * basic_pbf_writer will be invalid. + */ + basic_pbf_writer(basic_pbf_writer&& other) noexcept : + m_data{other.m_data}, + m_parent_writer{other.m_parent_writer}, + m_rollback_pos{other.m_rollback_pos}, + m_pos{other.m_pos} { + other.m_data = nullptr; + other.m_parent_writer = nullptr; + other.m_rollback_pos = 0; + other.m_pos = 0; + } + + /** + * A basic_pbf_writer object can be moved. After this the other + * basic_pbf_writer will be invalid. + */ + basic_pbf_writer& operator=(basic_pbf_writer&& other) noexcept { + m_data = other.m_data; + m_parent_writer = other.m_parent_writer; + m_rollback_pos = other.m_rollback_pos; + m_pos = other.m_pos; + other.m_data = nullptr; + other.m_parent_writer = nullptr; + other.m_rollback_pos = 0; + other.m_pos = 0; + return *this; + } + + ~basic_pbf_writer() noexcept { + try { + if (m_parent_writer != nullptr) { + m_parent_writer->close_submessage(); + } + } catch (...) { + // This try/catch is used to make the destructor formally noexcept. + // close_submessage() is not noexcept, but will not throw the way + // it is called here, so we are good. But to be paranoid, call... + std::terminate(); + } + } + + /** + * Check if this writer is valid. A writer is invalid if it was default + * constructed, moved from, or if commit() has been called on it. + * Otherwise it is valid. + */ + bool valid() const noexcept { + return m_data != nullptr; + } + + /** + * Swap the contents of this object with the other. + * + * @param other Other object to swap data with. + */ + void swap(basic_pbf_writer& other) noexcept { + using std::swap; + swap(m_data, other.m_data); + swap(m_parent_writer, other.m_parent_writer); + swap(m_rollback_pos, other.m_rollback_pos); + swap(m_pos, other.m_pos); + } + + /** + * Reserve size bytes in the underlying message store in addition to + * whatever the message store already holds. So unlike + * the `std::string::reserve()` method this is not an absolute size, + * but additional memory that should be reserved. + * + * @param size Number of bytes to reserve in underlying message store. + */ + void reserve(std::size_t size) { + protozero_assert(m_data); + buffer_customization::reserve_additional(m_data, size); + } + + /** + * Commit this submessage. This does the same as when the basic_pbf_writer + * goes out of scope and is destructed. + * + * @pre Must be a basic_pbf_writer of a submessage, ie one opened with the + * basic_pbf_writer constructor taking a parent message. + * @post The basic_pbf_writer is invalid and can't be used any more. + */ + void commit() { + protozero_assert(m_parent_writer && "you can't call commit() on a basic_pbf_writer without a parent"); + protozero_assert(m_pos == 0 && "you can't call commit() on a basic_pbf_writer that has an open nested submessage"); + m_parent_writer->close_submessage(); + m_parent_writer = nullptr; + m_data = nullptr; + } + + /** + * Cancel writing of this submessage. The complete submessage will be + * removed as if it was never created and no fields were added. + * + * @pre Must be a basic_pbf_writer of a submessage, ie one opened with the + * basic_pbf_writer constructor taking a parent message. + * @post The basic_pbf_writer is invalid and can't be used any more. + */ + void rollback() { + protozero_assert(m_parent_writer && "you can't call rollback() on a basic_pbf_writer without a parent"); + protozero_assert(m_pos == 0 && "you can't call rollback() on a basic_pbf_writer that has an open nested submessage"); + m_parent_writer->rollback_submessage(); + m_parent_writer = nullptr; + m_data = nullptr; + } + + ///@{ + /** + * @name Scalar field writer functions + */ + + /** + * Add "bool" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_bool(pbf_tag_type tag, bool value) { + add_field(tag, pbf_wire_type::varint); + protozero_assert(m_pos == 0 && "you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage"); + protozero_assert(m_data); + m_data->push_back(char(value)); + } + + /** + * Add "enum" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_enum(pbf_tag_type tag, int32_t value) { + add_tagged_varint(tag, uint64_t(value)); + } + + /** + * Add "int32" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_int32(pbf_tag_type tag, int32_t value) { + add_tagged_varint(tag, uint64_t(value)); + } + + /** + * Add "sint32" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_sint32(pbf_tag_type tag, int32_t value) { + add_tagged_varint(tag, encode_zigzag32(value)); + } + + /** + * Add "uint32" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_uint32(pbf_tag_type tag, uint32_t value) { + add_tagged_varint(tag, value); + } + + /** + * Add "int64" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_int64(pbf_tag_type tag, int64_t value) { + add_tagged_varint(tag, uint64_t(value)); + } + + /** + * Add "sint64" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_sint64(pbf_tag_type tag, int64_t value) { + add_tagged_varint(tag, encode_zigzag64(value)); + } + + /** + * Add "uint64" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_uint64(pbf_tag_type tag, uint64_t value) { + add_tagged_varint(tag, value); + } + + /** + * Add "fixed32" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_fixed32(pbf_tag_type tag, uint32_t value) { + add_field(tag, pbf_wire_type::fixed32); + add_fixed(value); + } + + /** + * Add "sfixed32" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_sfixed32(pbf_tag_type tag, int32_t value) { + add_field(tag, pbf_wire_type::fixed32); + add_fixed(value); + } + + /** + * Add "fixed64" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_fixed64(pbf_tag_type tag, uint64_t value) { + add_field(tag, pbf_wire_type::fixed64); + add_fixed(value); + } + + /** + * Add "sfixed64" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_sfixed64(pbf_tag_type tag, int64_t value) { + add_field(tag, pbf_wire_type::fixed64); + add_fixed(value); + } + + /** + * Add "float" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_float(pbf_tag_type tag, float value) { + add_field(tag, pbf_wire_type::fixed32); + add_fixed(value); + } + + /** + * Add "double" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_double(pbf_tag_type tag, double value) { + add_field(tag, pbf_wire_type::fixed64); + add_fixed(value); + } + + /** + * Add "bytes" field to data. + * + * @param tag Tag (field number) of the field + * @param value Pointer to value to be written + * @param size Number of bytes to be written + */ + void add_bytes(pbf_tag_type tag, const char* value, std::size_t size) { + protozero_assert(m_pos == 0 && "you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage"); + protozero_assert(m_data); + protozero_assert(size <= std::numeric_limits::max()); + add_length_varint(tag, pbf_length_type(size)); + buffer_customization::append(m_data, value, size); + } + + /** + * Add "bytes" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_bytes(pbf_tag_type tag, const data_view& value) { + add_bytes(tag, value.data(), value.size()); + } + + /** + * Add "bytes" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_bytes(pbf_tag_type tag, const std::string& value) { + add_bytes(tag, value.data(), value.size()); + } + + /** + * Add "bytes" field to data. Bytes from the value are written until + * a null byte is encountered. The null byte is not added. + * + * @param tag Tag (field number) of the field + * @param value Pointer to zero-delimited value to be written + */ + void add_bytes(pbf_tag_type tag, const char* value) { + add_bytes(tag, value, std::strlen(value)); + } + + /** + * Add "bytes" field to data using vectored input. All the data in the + * 2nd and further arguments is "concatenated" with only a single copy + * into the final buffer. + * + * This will work with objects of any type supporting the data() and + * size() methods like std::string or protozero::data_view. + * + * Example: + * @code + * std::string data1 = "abc"; + * std::string data2 = "xyz"; + * writer.add_bytes_vectored(1, data1, data2); + * @endcode + * + * @tparam Ts List of types supporting data() and size() methods. + * @param tag Tag (field number) of the field + * @param values List of objects of types Ts with data to be appended. + */ + template + void add_bytes_vectored(pbf_tag_type tag, Ts&&... values) { + protozero_assert(m_pos == 0 && "you can't add fields to a parent basic_pbf_writer if there is an existing basic_pbf_writer for a submessage"); + protozero_assert(m_data); + size_t sum_size = 0; + (void)std::initializer_list{sum_size += values.size()...}; + protozero_assert(sum_size <= std::numeric_limits::max()); + add_length_varint(tag, pbf_length_type(sum_size)); + buffer_customization::reserve_additional(m_data, sum_size); + (void)std::initializer_list{(buffer_customization::append(m_data, values.data(), values.size()), 0)...}; + } + + /** + * Add "string" field to data. + * + * @param tag Tag (field number) of the field + * @param value Pointer to value to be written + * @param size Number of bytes to be written + */ + void add_string(pbf_tag_type tag, const char* value, std::size_t size) { + add_bytes(tag, value, size); + } + + /** + * Add "string" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_string(pbf_tag_type tag, const data_view& value) { + add_bytes(tag, value.data(), value.size()); + } + + /** + * Add "string" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written + */ + void add_string(pbf_tag_type tag, const std::string& value) { + add_bytes(tag, value.data(), value.size()); + } + + /** + * Add "string" field to data. Bytes from the value are written until + * a null byte is encountered. The null byte is not added. + * + * @param tag Tag (field number) of the field + * @param value Pointer to value to be written + */ + void add_string(pbf_tag_type tag, const char* value) { + add_bytes(tag, value, std::strlen(value)); + } + + /** + * Add "message" field to data. + * + * @param tag Tag (field number) of the field + * @param value Pointer to message to be written + * @param size Length of the message + */ + void add_message(pbf_tag_type tag, const char* value, std::size_t size) { + add_bytes(tag, value, size); + } + + /** + * Add "message" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written. The value must be a complete message. + */ + void add_message(pbf_tag_type tag, const data_view& value) { + add_bytes(tag, value.data(), value.size()); + } + + /** + * Add "message" field to data. + * + * @param tag Tag (field number) of the field + * @param value Value to be written. The value must be a complete message. + */ + void add_message(pbf_tag_type tag, const std::string& value) { + add_bytes(tag, value.data(), value.size()); + } + + ///@} + + ///@{ + /** + * @name Repeated packed field writer functions + */ + + /** + * Add "repeated packed bool" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to bool. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_bool(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_varint(tag, first, last); + } + + /** + * Add "repeated packed enum" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to int32_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_enum(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_varint(tag, first, last); + } + + /** + * Add "repeated packed int32" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to int32_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_int32(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_varint(tag, first, last); + } + + /** + * Add "repeated packed sint32" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to int32_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_sint32(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_svarint(tag, first, last); + } + + /** + * Add "repeated packed uint32" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to uint32_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_uint32(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_varint(tag, first, last); + } + + /** + * Add "repeated packed int64" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to int64_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_int64(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_varint(tag, first, last); + } + + /** + * Add "repeated packed sint64" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to int64_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_sint64(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_svarint(tag, first, last); + } + + /** + * Add "repeated packed uint64" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to uint64_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_uint64(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_varint(tag, first, last); + } + + /** + * Add a "repeated packed" fixed-size field to data. The following + * fixed-size fields are available: + * + * uint32_t -> repeated packed fixed32 + * int32_t -> repeated packed sfixed32 + * uint64_t -> repeated packed fixed64 + * int64_t -> repeated packed sfixed64 + * double -> repeated packed double + * float -> repeated packed float + * + * @tparam ValueType One of the following types: (u)int32/64_t, double, float. + * @tparam InputIterator A type satisfying the InputIterator concept. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_fixed(pbf_tag_type tag, InputIterator first, InputIterator last) { + static_assert(std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value, "Only some types are allowed"); + add_packed_fixed(tag, first, last, + typename std::iterator_traits::iterator_category{}); + } + + /** + * Add "repeated packed fixed32" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to uint32_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_fixed32(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_fixed(tag, first, last, + typename std::iterator_traits::iterator_category{}); + } + + /** + * Add "repeated packed sfixed32" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to int32_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_sfixed32(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_fixed(tag, first, last, + typename std::iterator_traits::iterator_category{}); + } + + /** + * Add "repeated packed fixed64" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to uint64_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_fixed64(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_fixed(tag, first, last, + typename std::iterator_traits::iterator_category{}); + } + + /** + * Add "repeated packed sfixed64" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to int64_t. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_sfixed64(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_fixed(tag, first, last, + typename std::iterator_traits::iterator_category{}); + } + + /** + * Add "repeated packed float" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to float. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_float(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_fixed(tag, first, last, + typename std::iterator_traits::iterator_category{}); + } + + /** + * Add "repeated packed double" field to data. + * + * @tparam InputIterator A type satisfying the InputIterator concept. + * Dereferencing the iterator must yield a type assignable to double. + * @param tag Tag (field number) of the field + * @param first Iterator pointing to the beginning of the data + * @param last Iterator pointing one past the end of data + */ + template + void add_packed_double(pbf_tag_type tag, InputIterator first, InputIterator last) { + add_packed_fixed(tag, first, last, + typename std::iterator_traits::iterator_category{}); + } + + ///@} + + template friend class detail::packed_field_varint; + template friend class detail::packed_field_svarint; + template friend class detail::packed_field_fixed; + +}; // class basic_pbf_writer + +/** + * Swap two basic_pbf_writer objects. + * + * @param lhs First object. + * @param rhs Second object. + */ +template +inline void swap(basic_pbf_writer& lhs, basic_pbf_writer& rhs) noexcept { + lhs.swap(rhs); +} + +namespace detail { + + template + class packed_field { + + basic_pbf_writer m_writer{}; + + public: + + packed_field(const packed_field&) = delete; + packed_field& operator=(const packed_field&) = delete; + + packed_field(packed_field&&) noexcept = default; + packed_field& operator=(packed_field&&) noexcept = default; + + packed_field() = default; + + packed_field(basic_pbf_writer& parent_writer, pbf_tag_type tag) : + m_writer{parent_writer, tag} { + } + + packed_field(basic_pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size) : + m_writer{parent_writer, tag, size} { + } + + ~packed_field() noexcept = default; + + bool valid() const noexcept { + return m_writer.valid(); + } + + void commit() { + m_writer.commit(); + } + + void rollback() { + m_writer.rollback(); + } + + basic_pbf_writer& writer() noexcept { + return m_writer; + } + + }; // class packed_field + + template + class packed_field_fixed : public packed_field { + + public: + + packed_field_fixed() : + packed_field{} { + } + + template + packed_field_fixed(basic_pbf_writer& parent_writer, P tag) : + packed_field{parent_writer, static_cast(tag)} { + } + + template + packed_field_fixed(basic_pbf_writer& parent_writer, P tag, std::size_t size) : + packed_field{parent_writer, static_cast(tag), size * sizeof(T)} { + } + + void add_element(T value) { + this->writer().template add_fixed(value); + } + + }; // class packed_field_fixed + + template + class packed_field_varint : public packed_field { + + public: + + packed_field_varint() : + packed_field{} { + } + + template + packed_field_varint(basic_pbf_writer& parent_writer, P tag) : + packed_field{parent_writer, static_cast(tag)} { + } + + void add_element(T value) { + this->writer().add_varint(uint64_t(value)); + } + + }; // class packed_field_varint + + template + class packed_field_svarint : public packed_field { + + public: + + packed_field_svarint() : + packed_field{} { + } + + template + packed_field_svarint(basic_pbf_writer& parent_writer, P tag) : + packed_field{parent_writer, static_cast(tag)} { + } + + void add_element(T value) { + this->writer().add_varint(encode_zigzag64(value)); + } + + }; // class packed_field_svarint + +} // end namespace detail + +} // end namespace protozero + +#endif // PROTOZERO_BASIC_PBF_WRITER_HPP diff --git a/third_party/protozero/include/protozero/buffer_fixed.hpp b/third_party/protozero/include/protozero/buffer_fixed.hpp new file mode 100644 index 000000000..b2e6d1d27 --- /dev/null +++ b/third_party/protozero/include/protozero/buffer_fixed.hpp @@ -0,0 +1,222 @@ +#ifndef PROTOZERO_BUFFER_FIXED_HPP +#define PROTOZERO_BUFFER_FIXED_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +/** + * @file buffer_fixed.hpp + * + * @brief Contains the fixed_size_buffer_adaptor class. + */ + +#include "buffer_tmpl.hpp" +#include "config.hpp" + +#include +#include +#include +#include + +namespace protozero { + +/** + * This class can be used instead of std::string if you want to create a + * vector tile in a fixed-size buffer. Any operation that needs more space + * than is available will fail with a std::length_error exception. + */ +class fixed_size_buffer_adaptor { + + char* m_data; + std::size_t m_capacity; + std::size_t m_size = 0; + +public: + + /// @cond usual container typedefs not documented + + using size_type = std::size_t; + + using value_type = char; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + + using iterator = pointer; + using const_iterator = const_pointer; + + /// @endcond + + /** + * Constructor. + * + * @param data Pointer to some memory allocated for the buffer. + * @param capacity Number of bytes available. + */ + fixed_size_buffer_adaptor(char* data, std::size_t capacity) noexcept : + m_data(data), + m_capacity(capacity) { + } + + /** + * Constructor. + * + * @param container Some container class supporting the member functions + * data() and size(). + */ + template + explicit fixed_size_buffer_adaptor(T& container) : + m_data(container.data()), + m_capacity(container.size()) { + } + + /// Returns a pointer to the data in the buffer. + const char* data() const noexcept { + return m_data; + } + + /// Returns a pointer to the data in the buffer. + char* data() noexcept { + return m_data; + } + + /// The capacity this buffer was created with. + std::size_t capacity() const noexcept { + return m_capacity; + } + + /// The number of bytes used in the buffer. Always <= capacity(). + std::size_t size() const noexcept { + return m_size; + } + + /// Return iterator to beginning of data. + char* begin() noexcept { + return m_data; + } + + /// Return iterator to beginning of data. + const char* begin() const noexcept { + return m_data; + } + + /// Return iterator to beginning of data. + const char* cbegin() const noexcept { + return m_data; + } + + /// Return iterator to end of data. + char* end() noexcept { + return m_data + m_size; + } + + /// Return iterator to end of data. + const char* end() const noexcept { + return m_data + m_size; + } + + /// Return iterator to end of data. + const char* cend() const noexcept { + return m_data + m_size; + } + +/// @cond INTERNAL + + // Do not rely on anything beyond this point + + void append(const char* data, std::size_t count) { + if (m_size + count > m_capacity) { + throw std::length_error{"fixed size data store exhausted"}; + } + std::copy_n(data, count, m_data + m_size); + m_size += count; + } + + void append_zeros(std::size_t count) { + if (m_size + count > m_capacity) { + throw std::length_error{"fixed size data store exhausted"}; + } + std::fill_n(m_data + m_size, count, '\0'); + m_size += count; + } + + void resize(std::size_t size) { + protozero_assert(size < m_size); + if (size > m_capacity) { + throw std::length_error{"fixed size data store exhausted"}; + } + m_size = size; + } + + void erase_range(std::size_t from, std::size_t to) { + protozero_assert(from <= m_size); + protozero_assert(to <= m_size); + protozero_assert(from < to); + std::copy(m_data + to, m_data + m_size, m_data + from); + m_size -= (to - from); + } + + char* at_pos(std::size_t pos) { + protozero_assert(pos <= m_size); + return m_data + pos; + } + + void push_back(char ch) { + if (m_size >= m_capacity) { + throw std::length_error{"fixed size data store exhausted"}; + } + m_data[m_size++] = ch; + } +/// @endcond + +}; // class fixed_size_buffer_adaptor + +/// @cond INTERNAL +template <> +struct buffer_customization { + + static std::size_t size(const fixed_size_buffer_adaptor* buffer) noexcept { + return buffer->size(); + } + + static void append(fixed_size_buffer_adaptor* buffer, const char* data, std::size_t count) { + buffer->append(data, count); + } + + static void append_zeros(fixed_size_buffer_adaptor* buffer, std::size_t count) { + buffer->append_zeros(count); + } + + static void resize(fixed_size_buffer_adaptor* buffer, std::size_t size) { + buffer->resize(size); + } + + static void reserve_additional(fixed_size_buffer_adaptor* /*buffer*/, std::size_t /*size*/) { + /* nothing to be done for fixed-size buffers */ + } + + static void erase_range(fixed_size_buffer_adaptor* buffer, std::size_t from, std::size_t to) { + buffer->erase_range(from, to); + } + + static char* at_pos(fixed_size_buffer_adaptor* buffer, std::size_t pos) { + return buffer->at_pos(pos); + } + + static void push_back(fixed_size_buffer_adaptor* buffer, char ch) { + buffer->push_back(ch); + } + +}; +/// @endcond + +} // namespace protozero + +#endif // PROTOZERO_BUFFER_FIXED_HPP diff --git a/third_party/protozero/include/protozero/buffer_string.hpp b/third_party/protozero/include/protozero/buffer_string.hpp new file mode 100644 index 000000000..1f0f902a8 --- /dev/null +++ b/third_party/protozero/include/protozero/buffer_string.hpp @@ -0,0 +1,76 @@ +#ifndef PROTOZERO_BUFFER_STRING_HPP +#define PROTOZERO_BUFFER_STRING_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +/** + * @file buffer_string.hpp + * + * @brief Contains the customization points for buffer implementation based + * on std::string + */ + +#include "buffer_tmpl.hpp" + +#include +#include +#include + +namespace protozero { + +// Implementation of buffer customizations points for std::string + +/// @cond INTERNAL +template <> +struct buffer_customization { + + static std::size_t size(const std::string* buffer) noexcept { + return buffer->size(); + } + + static void append(std::string* buffer, const char* data, std::size_t count) { + buffer->append(data, count); + } + + static void append_zeros(std::string* buffer, std::size_t count) { + buffer->append(count, '\0'); + } + + static void resize(std::string* buffer, std::size_t size) { + protozero_assert(size < buffer->size()); + buffer->resize(size); + } + + static void reserve_additional(std::string* buffer, std::size_t size) { + buffer->reserve(buffer->size() + size); + } + + static void erase_range(std::string* buffer, std::size_t from, std::size_t to) { + protozero_assert(from <= buffer->size()); + protozero_assert(to <= buffer->size()); + protozero_assert(from <= to); + buffer->erase(std::next(buffer->begin(), from), std::next(buffer->begin(), to)); + } + + static char* at_pos(std::string* buffer, std::size_t pos) { + protozero_assert(pos <= buffer->size()); + return (&*buffer->begin()) + pos; + } + + static void push_back(std::string* buffer, char ch) { + buffer->push_back(ch); + } + +}; +/// @endcond + +} // namespace protozero + +#endif // PROTOZERO_BUFFER_STRING_HPP diff --git a/third_party/protozero/include/protozero/buffer_tmpl.hpp b/third_party/protozero/include/protozero/buffer_tmpl.hpp new file mode 100644 index 000000000..ac223996d --- /dev/null +++ b/third_party/protozero/include/protozero/buffer_tmpl.hpp @@ -0,0 +1,113 @@ +#ifndef PROTOZERO_BUFFER_TMPL_HPP +#define PROTOZERO_BUFFER_TMPL_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +/** + * @file buffer_tmpl.hpp + * + * @brief Contains the customization points for buffer implementations. + */ + +#include +#include +#include + +namespace protozero { + +// Implementation of buffer customizations points for std::string + +/// @cond INTERNAL +template +struct buffer_customization { + + /** + * Get the number of bytes currently used in the buffer. + * + * @param buffer Pointer to the buffer. + * @returns number of bytes used in the buffer. + */ + static std::size_t size(const std::string* buffer); + + /** + * Append count bytes from data to the buffer. + * + * @param buffer Pointer to the buffer. + * @param data Pointer to the data. + * @param count Number of bytes to be added to the buffer. + */ + static void append(std::string* buffer, const char* data, std::size_t count); + + /** + * Append count zero bytes to the buffer. + * + * @param buffer Pointer to the buffer. + * @param count Number of bytes to be added to the buffer. + */ + static void append_zeros(std::string* buffer, std::size_t count); + + /** + * Shrink the buffer to the specified size. The new size will always be + * smaller than the current size. + * + * @param buffer Pointer to the buffer. + * @param size New size of the buffer. + * + * @pre size < current size of buffer + */ + static void resize(std::string* buffer, std::size_t size); + + /** + * Reserve an additional size bytes for use in the buffer. This is used for + * variable-sized buffers to tell the buffer implementation that soon more + * memory will be used. The implementation can ignore this. + * + * @param buffer Pointer to the buffer. + * @param size Number of bytes to reserve. + */ + static void reserve_additional(std::string* buffer, std::size_t size); + + /** + * Delete data from the buffer. This must move back the data after the + * part being deleted and resize the buffer accordingly. + * + * @param buffer Pointer to the buffer. + * @param from Offset into the buffer where we want to erase from. + * @param to Offset into the buffer one past the last byte we want to erase. + * + * @pre from, to <= size of the buffer, from < to + */ + static void erase_range(std::string* buffer, std::size_t from, std::size_t to); + + /** + * Return a pointer to the memory at the specified position in the buffer. + * + * @param buffer Pointer to the buffer. + * @param pos The position in the buffer. + * @returns pointer to the memory in the buffer at the specified position. + * + * @pre pos <= size of the buffer + */ + static char* at_pos(std::string* buffer, std::size_t pos); + + /** + * Add a char to the buffer incrementing the number of chars in the buffer. + * + * @param buffer Pointer to the buffer. + * @param ch The character to add. + */ + static void push_back(std::string* buffer, char ch); + +}; +/// @endcond + +} // namespace protozero + +#endif // PROTOZERO_BUFFER_TMPL_HPP diff --git a/third_party/protozero/include/protozero/buffer_vector.hpp b/third_party/protozero/include/protozero/buffer_vector.hpp new file mode 100644 index 000000000..6a34b072e --- /dev/null +++ b/third_party/protozero/include/protozero/buffer_vector.hpp @@ -0,0 +1,76 @@ +#ifndef PROTOZERO_BUFFER_VECTOR_HPP +#define PROTOZERO_BUFFER_VECTOR_HPP + +/***************************************************************************** + +protozero - Minimalistic protocol buffer decoder and encoder in C++. + +This file is from https://github.com/mapbox/protozero where you can find more +documentation. + +*****************************************************************************/ + +/** + * @file buffer_vector.hpp + * + * @brief Contains the customization points for buffer implementation based + * on std::vector + */ + +#include "buffer_tmpl.hpp" + +#include +#include +#include + +namespace protozero { + +// Implementation of buffer customizations points for std::vector + +/// @cond INTERNAL +template <> +struct buffer_customization> { + + static std::size_t size(const std::vector* buffer) noexcept { + return buffer->size(); + } + + static void append(std::vector* buffer, const char* data, std::size_t count) { + buffer->insert(buffer->end(), data, data + count); + } + + static void append_zeros(std::vector* buffer, std::size_t count) { + buffer->insert(buffer->end(), count, '\0'); + } + + static void resize(std::vector* buffer, std::size_t size) { + protozero_assert(size < buffer->size()); + buffer->resize(size); + } + + static void reserve_additional(std::vector* buffer, std::size_t size) { + buffer->reserve(buffer->size() + size); + } + + static void erase_range(std::vector* buffer, std::size_t from, std::size_t to) { + protozero_assert(from <= buffer->size()); + protozero_assert(to <= buffer->size()); + protozero_assert(from <= to); + buffer->erase(std::next(buffer->begin(), from), std::next(buffer->begin(), to)); + } + + static char* at_pos(std::vector* buffer, std::size_t pos) { + protozero_assert(pos <= buffer->size()); + return (&*buffer->begin()) + pos; + } + + static void push_back(std::vector* buffer, char ch) { + buffer->push_back(ch); + } + +}; +/// @endcond + +} // namespace protozero + +#endif // PROTOZERO_BUFFER_VECTOR_HPP diff --git a/third_party/protozero/include/protozero/byteswap.hpp b/third_party/protozero/include/protozero/byteswap.hpp index fd8a83a68..799d1795d 100644 --- a/third_party/protozero/include/protozero/byteswap.hpp +++ b/third_party/protozero/include/protozero/byteswap.hpp @@ -16,7 +16,7 @@ documentation. * @brief Contains functions to swap bytes in values (for different endianness). */ -#include +#include "config.hpp" #include @@ -27,10 +27,10 @@ inline uint32_t byteswap_impl(uint32_t value) noexcept { #ifdef PROTOZERO_USE_BUILTIN_BSWAP return __builtin_bswap32(value); #else - return ((value & 0xff000000) >> 24) | - ((value & 0x00ff0000) >> 8) | - ((value & 0x0000ff00) << 8) | - ((value & 0x000000ff) << 24); + return ((value & 0xff000000U) >> 24U) | + ((value & 0x00ff0000U) >> 8U) | + ((value & 0x0000ff00U) << 8U) | + ((value & 0x000000ffU) << 24U); #endif } @@ -38,46 +38,62 @@ inline uint64_t byteswap_impl(uint64_t value) noexcept { #ifdef PROTOZERO_USE_BUILTIN_BSWAP return __builtin_bswap64(value); #else - return ((value & 0xff00000000000000ULL) >> 56) | - ((value & 0x00ff000000000000ULL) >> 40) | - ((value & 0x0000ff0000000000ULL) >> 24) | - ((value & 0x000000ff00000000ULL) >> 8) | - ((value & 0x00000000ff000000ULL) << 8) | - ((value & 0x0000000000ff0000ULL) << 24) | - ((value & 0x000000000000ff00ULL) << 40) | - ((value & 0x00000000000000ffULL) << 56); + return ((value & 0xff00000000000000ULL) >> 56U) | + ((value & 0x00ff000000000000ULL) >> 40U) | + ((value & 0x0000ff0000000000ULL) >> 24U) | + ((value & 0x000000ff00000000ULL) >> 8U) | + ((value & 0x00000000ff000000ULL) << 8U) | + ((value & 0x0000000000ff0000ULL) << 24U) | + ((value & 0x000000000000ff00ULL) << 40U) | + ((value & 0x00000000000000ffULL) << 56U); #endif } +} // end namespace detail + +/// byteswap the data pointed to by ptr in-place. inline void byteswap_inplace(uint32_t* ptr) noexcept { - *ptr = byteswap_impl(*ptr); + *ptr = detail::byteswap_impl(*ptr); } +/// byteswap the data pointed to by ptr in-place. inline void byteswap_inplace(uint64_t* ptr) noexcept { - *ptr = byteswap_impl(*ptr); + *ptr = detail::byteswap_impl(*ptr); } +/// byteswap the data pointed to by ptr in-place. inline void byteswap_inplace(int32_t* ptr) noexcept { - auto bptr = reinterpret_cast(ptr); - *bptr = byteswap_impl(*bptr); + auto* bptr = reinterpret_cast(ptr); + *bptr = detail::byteswap_impl(*bptr); } +/// byteswap the data pointed to by ptr in-place. inline void byteswap_inplace(int64_t* ptr) noexcept { - auto bptr = reinterpret_cast(ptr); - *bptr = byteswap_impl(*bptr); + auto* bptr = reinterpret_cast(ptr); + *bptr = detail::byteswap_impl(*bptr); } +/// byteswap the data pointed to by ptr in-place. inline void byteswap_inplace(float* ptr) noexcept { - auto bptr = reinterpret_cast(ptr); - *bptr = byteswap_impl(*bptr); + auto* bptr = reinterpret_cast(ptr); + *bptr = detail::byteswap_impl(*bptr); } +/// byteswap the data pointed to by ptr in-place. inline void byteswap_inplace(double* ptr) noexcept { - auto bptr = reinterpret_cast(ptr); - *bptr = byteswap_impl(*bptr); + auto* bptr = reinterpret_cast(ptr); + *bptr = detail::byteswap_impl(*bptr); } +namespace detail { + + // Added for backwards compatibility with any code that might use this + // function (even if it shouldn't have). Will be removed in a later + // version of protozero. + using ::protozero::byteswap_inplace; + } // end namespace detail + } // end namespace protozero #endif // PROTOZERO_BYTESWAP_HPP diff --git a/third_party/protozero/include/protozero/data_view.hpp b/third_party/protozero/include/protozero/data_view.hpp index 952c91203..3ec87af34 100644 --- a/third_party/protozero/include/protozero/data_view.hpp +++ b/third_party/protozero/include/protozero/data_view.hpp @@ -16,7 +16,7 @@ documentation. * @brief Contains the implementation of the data_view class. */ -#include +#include "config.hpp" #include #include @@ -55,8 +55,8 @@ public: * @param length Length of the data. */ constexpr data_view(const char* ptr, std::size_t length) noexcept - : m_data(ptr), - m_size(length) { + : m_data{ptr}, + m_size{length} { } /** @@ -65,8 +65,8 @@ public: * @param str String with the data. */ data_view(const std::string& str) noexcept // NOLINT(google-explicit-constructor, hicpp-explicit-conversions) - : m_data(str.data()), - m_size(str.size()) { + : m_data{str.data()}, + m_size{str.size()} { } /** @@ -75,8 +75,8 @@ public: * @param ptr Pointer to the data. */ data_view(const char* ptr) noexcept // NOLINT(google-explicit-constructor, hicpp-explicit-conversions) - : m_data(ptr), - m_size(std::strlen(ptr)) { + : m_data{ptr}, + m_size{std::strlen(ptr)} { } /** @@ -141,8 +141,8 @@ public: * * @pre Must not be default constructed data_view. */ - int compare(data_view other) const { - protozero_assert(m_data && other.m_data); + int compare(data_view other) const noexcept { + assert(m_data && other.m_data); const int cmp = std::memcmp(data(), other.data(), std::min(size(), other.size())); if (cmp == 0) { diff --git a/third_party/protozero/include/protozero/iterators.hpp b/third_party/protozero/include/protozero/iterators.hpp index c1d7d8d69..ee8ef8ecf 100644 --- a/third_party/protozero/include/protozero/iterators.hpp +++ b/third_party/protozero/include/protozero/iterators.hpp @@ -16,8 +16,8 @@ documentation. * @brief Contains the iterators for access to packed repeated fields. */ -#include -#include +#include "config.hpp" +#include "varint.hpp" #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN # include @@ -56,7 +56,7 @@ public: * Default constructor. Create empty iterator_range. */ constexpr iterator_range() : - P(iterator{}, iterator{}) { + P{iterator{}, iterator{}} { } /** @@ -66,8 +66,8 @@ public: * @param last_iterator Iterator to end of range. */ constexpr iterator_range(iterator&& first_iterator, iterator&& last_iterator) : - P(std::forward(first_iterator), - std::forward(last_iterator)) { + P{std::forward(first_iterator), + std::forward(last_iterator)} { } /// Return iterator to beginning of range. @@ -164,6 +164,8 @@ class const_fixed_iterator { public: + /// @cond usual iterator functions not documented + using iterator_category = std::random_access_iterator_tag; using value_type = T; using difference_type = std::ptrdiff_t; @@ -173,7 +175,7 @@ public: const_fixed_iterator() noexcept = default; explicit const_fixed_iterator(const char* data) noexcept : - m_data(data) { + m_data{data} { } const_fixed_iterator(const const_fixed_iterator&) noexcept = default; @@ -184,11 +186,11 @@ public: ~const_fixed_iterator() noexcept = default; - value_type operator*() const { + value_type operator*() const noexcept { value_type result; std::memcpy(&result, m_data, sizeof(value_type)); #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN - detail::byteswap_inplace(&result); + byteswap_inplace(&result); #endif return result; } @@ -204,14 +206,6 @@ public: return tmp; } - bool operator==(const_fixed_iterator rhs) const noexcept { - return m_data == rhs.m_data; - } - - bool operator!=(const_fixed_iterator rhs) const noexcept { - return !(*this == rhs); - } - const_fixed_iterator& operator--() noexcept { m_data -= sizeof(value_type); return *this; @@ -223,6 +217,14 @@ public: return tmp; } + friend bool operator==(const_fixed_iterator lhs, const_fixed_iterator rhs) noexcept { + return lhs.m_data == rhs.m_data; + } + + friend bool operator!=(const_fixed_iterator lhs, const_fixed_iterator rhs) noexcept { + return !(lhs == rhs); + } + friend bool operator<(const_fixed_iterator lhs, const_fixed_iterator rhs) noexcept { return lhs.m_data < rhs.m_data; } @@ -237,7 +239,6 @@ public: friend bool operator>=(const_fixed_iterator lhs, const_fixed_iterator rhs) noexcept { return !(lhs < rhs); - } const_fixed_iterator& operator+=(difference_type val) noexcept { @@ -276,6 +277,8 @@ public: return *(*this + n); } + /// @endcond + }; // class const_fixed_iterator /** @@ -288,13 +291,15 @@ class const_varint_iterator { protected: /// Pointer to current iterator position - const char* m_data = nullptr; + const char* m_data = nullptr; // NOLINT(misc-non-private-member-variables-in-classes, cppcoreguidelines-non-private-member-variables-in-classes,-warnings-as-errors) /// Pointer to end iterator position - const char* m_end = nullptr; + const char* m_end = nullptr; // NOLINT(misc-non-private-member-variables-in-classes, cppcoreguidelines-non-private-member-variables-in-classes,-warnings-as-errors) public: + /// @cond usual iterator functions not documented + using iterator_category = std::forward_iterator_tag; using value_type = T; using difference_type = std::ptrdiff_t; @@ -302,19 +307,24 @@ public: using reference = value_type&; static difference_type distance(const_varint_iterator begin, const_varint_iterator end) noexcept { + // The "distance" between default initialized const_varint_iterator's + // is always 0. + if (!begin.m_data) { + return 0; + } // We know that each varint contains exactly one byte with the most // significant bit not set. We can use this to quickly figure out // how many varints there are without actually decoding the varints. return std::count_if(begin.m_data, end.m_data, [](char c) noexcept { - return (static_cast(c) & 0x80u) == 0; + return (static_cast(c) & 0x80U) == 0; }); } const_varint_iterator() noexcept = default; const_varint_iterator(const char* data, const char* end) noexcept : - m_data(data), - m_end(end) { + m_data{data}, + m_end{end} { } const_varint_iterator(const const_varint_iterator&) noexcept = default; @@ -326,16 +336,19 @@ public: ~const_varint_iterator() noexcept = default; value_type operator*() const { + protozero_assert(m_data); const char* d = m_data; // will be thrown away return static_cast(decode_varint(&d, m_end)); } const_varint_iterator& operator++() { + protozero_assert(m_data); skip_varint(&m_data, m_end); return *this; } const_varint_iterator operator++(int) { + protozero_assert(m_data); const const_varint_iterator tmp{*this}; ++(*this); return tmp; @@ -349,6 +362,8 @@ public: return !(*this == rhs); } + /// @endcond + }; // class const_varint_iterator /** @@ -360,6 +375,8 @@ class const_svarint_iterator : public const_varint_iterator { public: + /// @cond usual iterator functions not documented + using iterator_category = std::forward_iterator_tag; using value_type = T; using difference_type = std::ptrdiff_t; @@ -367,11 +384,11 @@ public: using reference = value_type&; const_svarint_iterator() noexcept : - const_varint_iterator() { + const_varint_iterator{} { } const_svarint_iterator(const char* data, const char* end) noexcept : - const_varint_iterator(data, end) { + const_varint_iterator{data, end} { } const_svarint_iterator(const const_svarint_iterator&) = default; @@ -383,21 +400,26 @@ public: ~const_svarint_iterator() = default; value_type operator*() const { + protozero_assert(this->m_data); const char* d = this->m_data; // will be thrown away return static_cast(decode_zigzag64(decode_varint(&d, this->m_end))); } const_svarint_iterator& operator++() { + protozero_assert(this->m_data); skip_varint(&this->m_data, this->m_end); return *this; } const_svarint_iterator operator++(int) { + protozero_assert(this->m_data); const const_svarint_iterator tmp{*this}; ++(*this); return tmp; } + /// @endcond + }; // class const_svarint_iterator } // end namespace protozero @@ -408,6 +430,8 @@ namespace std { // functions can't be partially specialized, we have to do this for // every value_type we are using. + /// @cond individual overloads do not need to be documented + template <> inline typename protozero::const_varint_iterator::difference_type distance>(protozero::const_varint_iterator first, // NOLINT(readability-inconsistent-declaration-parameter-name) @@ -450,6 +474,8 @@ namespace std { return protozero::const_svarint_iterator::distance(first, last); } + /// @endcond + } // end namespace std #endif // PROTOZERO_ITERATORS_HPP diff --git a/third_party/protozero/include/protozero/pbf_builder.hpp b/third_party/protozero/include/protozero/pbf_builder.hpp index 2e74b2fd9..71a2dec2b 100644 --- a/third_party/protozero/include/protozero/pbf_builder.hpp +++ b/third_party/protozero/include/protozero/pbf_builder.hpp @@ -16,249 +16,16 @@ documentation. * @brief Contains the pbf_builder template class. */ -#include -#include +#include "basic_pbf_builder.hpp" +#include "pbf_writer.hpp" -#include +#include namespace protozero { -/** - * The pbf_builder is used to write PBF formatted messages into a buffer. It - * is based on the pbf_writer class and has all the same methods. The - * difference is that while the pbf_writer class takes an integer tag, - * this template class takes a tag of the template type T. The idea is that - * T will be an enumeration value and this helps reduce the possibility of - * programming errors. - * - * Almost all methods in this class can throw an std::bad_alloc exception if - * the std::string used as a buffer wants to resize. - * - * Read the tutorial to understand how this class is used. - */ +/// Specialization of basic_pbf_builder using std::string as buffer type. template -class pbf_builder : public pbf_writer { - - static_assert(std::is_same::type>::value, - "T must be enum with underlying type protozero::pbf_tag_type"); - -public: - - /// The type of messages this class will build. - using enum_type = T; - - pbf_builder() = default; - - /** - * Create a builder using the given string as a data store. The object - * stores a reference to that string and adds all data to it. The string - * doesn't have to be empty. The pbf_message object will just append data. - */ - explicit pbf_builder(std::string& data) noexcept : - pbf_writer(data) { - } - - /** - * Construct a pbf_builder for a submessage from the pbf_message or - * pbf_writer of the parent message. - * - * @param parent_writer The parent pbf_message or pbf_writer - * @param tag Tag of the field that will be written - */ - template - pbf_builder(pbf_writer& parent_writer, P tag) noexcept : - pbf_writer(parent_writer, pbf_tag_type(tag)) { - } - -/// @cond INTERNAL -#define PROTOZERO_WRITER_WRAP_ADD_SCALAR(name, type) \ - void add_##name(T tag, type value) { \ - pbf_writer::add_##name(pbf_tag_type(tag), value); \ - } - - PROTOZERO_WRITER_WRAP_ADD_SCALAR(bool, bool) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(enum, int32_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(int32, int32_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(sint32, int32_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(uint32, uint32_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(int64, int64_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(sint64, int64_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(uint64, uint64_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(fixed32, uint32_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(sfixed32, int32_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(fixed64, uint64_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(sfixed64, int64_t) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(float, float) - PROTOZERO_WRITER_WRAP_ADD_SCALAR(double, double) - -#undef PROTOZERO_WRITER_WRAP_ADD_SCALAR -/// @endcond - - /** - * Add "bytes" field to data. - * - * @param tag Tag of the field - * @param value Pointer to value to be written - * @param size Number of bytes to be written - */ - void add_bytes(T tag, const char* value, std::size_t size) { - pbf_writer::add_bytes(pbf_tag_type(tag), value, size); - } - - /** - * Add "bytes" field to data. - * - * @param tag Tag of the field - * @param value Value to be written - */ - void add_bytes(T tag, const data_view& value) { - pbf_writer::add_bytes(pbf_tag_type(tag), value); - } - - /** - * Add "bytes" field to data. - * - * @param tag Tag of the field - * @param value Value to be written - */ - void add_bytes(T tag, const std::string& value) { - pbf_writer::add_bytes(pbf_tag_type(tag), value); - } - - /** - * Add "bytes" field to data. Bytes from the value are written until - * a null byte is encountered. The null byte is not added. - * - * @param tag Tag of the field - * @param value Pointer to zero-delimited value to be written - */ - void add_bytes(T tag, const char* value) { - pbf_writer::add_bytes(pbf_tag_type(tag), value); - } - - /** - * Add "bytes" field to data using vectored input. All the data in the - * 2nd and further arguments is "concatenated" with only a single copy - * into the final buffer. - * - * This will work with objects of any type supporting the data() and - * size() methods like std::string or protozero::data_view. - * - * Example: - * @code - * std::string data1 = "abc"; - * std::string data2 = "xyz"; - * builder.add_bytes_vectored(1, data1, data2); - * @endcode - * - * @tparam Ts List of types supporting data() and size() methods. - * @param tag Tag of the field - * @param values List of objects of types Ts with data to be appended. - */ - template - void add_bytes_vectored(T tag, Ts&&... values) { - pbf_writer::add_bytes_vectored(pbf_tag_type(tag), std::forward(values)...); - } - - /** - * Add "string" field to data. - * - * @param tag Tag of the field - * @param value Pointer to value to be written - * @param size Number of bytes to be written - */ - void add_string(T tag, const char* value, std::size_t size) { - pbf_writer::add_string(pbf_tag_type(tag), value, size); - } - - /** - * Add "string" field to data. - * - * @param tag Tag of the field - * @param value Value to be written - */ - void add_string(T tag, const data_view& value) { - pbf_writer::add_string(pbf_tag_type(tag), value); - } - - /** - * Add "string" field to data. - * - * @param tag Tag of the field - * @param value Value to be written - */ - void add_string(T tag, const std::string& value) { - pbf_writer::add_string(pbf_tag_type(tag), value); - } - - /** - * Add "string" field to data. Bytes from the value are written until - * a null byte is encountered. The null byte is not added. - * - * @param tag Tag of the field - * @param value Pointer to value to be written - */ - void add_string(T tag, const char* value) { - pbf_writer::add_string(pbf_tag_type(tag), value); - } - - /** - * Add "message" field to data. - * - * @param tag Tag of the field - * @param value Pointer to message to be written - * @param size Length of the message - */ - void add_message(T tag, const char* value, std::size_t size) { - pbf_writer::add_message(pbf_tag_type(tag), value, size); - } - - /** - * Add "message" field to data. - * - * @param tag Tag of the field - * @param value Value to be written. The value must be a complete message. - */ - void add_message(T tag, const data_view& value) { - pbf_writer::add_message(pbf_tag_type(tag), value); - } - - /** - * Add "message" field to data. - * - * @param tag Tag of the field - * @param value Value to be written. The value must be a complete message. - */ - void add_message(T tag, const std::string& value) { - pbf_writer::add_message(pbf_tag_type(tag), value); - } - -/// @cond INTERNAL -#define PROTOZERO_WRITER_WRAP_ADD_PACKED(name) \ - template \ - void add_packed_##name(T tag, InputIterator first, InputIterator last) { \ - pbf_writer::add_packed_##name(pbf_tag_type(tag), first, last); \ - } - - PROTOZERO_WRITER_WRAP_ADD_PACKED(bool) - PROTOZERO_WRITER_WRAP_ADD_PACKED(enum) - PROTOZERO_WRITER_WRAP_ADD_PACKED(int32) - PROTOZERO_WRITER_WRAP_ADD_PACKED(sint32) - PROTOZERO_WRITER_WRAP_ADD_PACKED(uint32) - PROTOZERO_WRITER_WRAP_ADD_PACKED(int64) - PROTOZERO_WRITER_WRAP_ADD_PACKED(sint64) - PROTOZERO_WRITER_WRAP_ADD_PACKED(uint64) - PROTOZERO_WRITER_WRAP_ADD_PACKED(fixed32) - PROTOZERO_WRITER_WRAP_ADD_PACKED(sfixed32) - PROTOZERO_WRITER_WRAP_ADD_PACKED(fixed64) - PROTOZERO_WRITER_WRAP_ADD_PACKED(sfixed64) - PROTOZERO_WRITER_WRAP_ADD_PACKED(float) - PROTOZERO_WRITER_WRAP_ADD_PACKED(double) - -#undef PROTOZERO_WRITER_WRAP_ADD_PACKED -/// @endcond - -}; // class pbf_builder +using pbf_builder = basic_pbf_builder; } // end namespace protozero diff --git a/third_party/protozero/include/protozero/pbf_message.hpp b/third_party/protozero/include/protozero/pbf_message.hpp index 10040d5b4..d7fd8b5d0 100644 --- a/third_party/protozero/include/protozero/pbf_message.hpp +++ b/third_party/protozero/include/protozero/pbf_message.hpp @@ -16,8 +16,8 @@ documentation. * @brief Contains the pbf_message template class. */ -#include -#include +#include "pbf_reader.hpp" +#include "types.hpp" #include @@ -78,7 +78,7 @@ public: */ template pbf_message(Args&&... args) noexcept : // NOLINT(google-explicit-constructor, hicpp-explicit-conversions) - pbf_reader(std::forward(args)...) { + pbf_reader{std::forward(args)...} { } /** diff --git a/third_party/protozero/include/protozero/pbf_reader.hpp b/third_party/protozero/include/protozero/pbf_reader.hpp index 5f8ea0eca..92bfdee5e 100644 --- a/third_party/protozero/include/protozero/pbf_reader.hpp +++ b/third_party/protozero/include/protozero/pbf_reader.hpp @@ -16,12 +16,12 @@ documentation. * @brief Contains the pbf_reader class. */ -#include -#include -#include -#include -#include -#include +#include "config.hpp" +#include "data_view.hpp" +#include "exception.hpp" +#include "iterators.hpp" +#include "types.hpp" +#include "varint.hpp" #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN # include @@ -80,7 +80,7 @@ class pbf_reader { skip_bytes(sizeof(T)); std::memcpy(&result, data, sizeof(T)); #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN - detail::byteswap_inplace(&result); + byteswap_inplace(&result); #endif return result; } @@ -98,7 +98,8 @@ class pbf_reader { template T get_varint() { - return static_cast(decode_varint(&m_data, m_end)); + const auto val = static_cast(decode_varint(&m_data, m_end)); + return val; } template @@ -112,7 +113,7 @@ class pbf_reader { } void skip_bytes(pbf_length_type len) { - if (m_data + len > m_end) { + if (m_end - m_data < static_cast(len)) { throw end_of_buffer_exception{}; } m_data += len; @@ -151,8 +152,8 @@ public: * @post There is no current field. */ explicit pbf_reader(const data_view& view) noexcept - : m_data(view.data()), - m_end(view.data() + view.size()) { + : m_data{view.data()}, + m_end{view.data() + view.size()} { } /** @@ -166,8 +167,8 @@ public: * @post There is no current field. */ pbf_reader(const char* data, std::size_t size) noexcept - : m_data(data), - m_end(data + size) { + : m_data{data}, + m_end{data + size} { } #ifndef PROTOZERO_STRICT_API @@ -183,8 +184,8 @@ public: * @deprecated Use one of the other constructors. */ explicit pbf_reader(const std::pair& data) noexcept - : m_data(data.first), - m_end(data.first + data.second) { + : m_data{data.first}, + m_end{data.first + data.second} { } #endif @@ -199,8 +200,8 @@ public: * @post There is no current field. */ explicit pbf_reader(const std::string& data) noexcept - : m_data(data.data()), - m_end(data.data() + data.size()) { + : m_data{data.data()}, + m_end{data.data() + data.size()} { } /** @@ -242,7 +243,14 @@ public: * read. */ operator bool() const noexcept { // NOLINT(google-explicit-constructor, hicpp-explicit-conversions) - return m_data < m_end; + return m_data != m_end; + } + + /** + * Get a view of the not yet read data. + */ + data_view data() const noexcept { + return {m_data, static_cast(m_end - m_data)}; } /** @@ -279,7 +287,7 @@ public: } const auto value = get_varint(); - m_tag = pbf_tag_type(value >> 3u); + m_tag = pbf_tag_type(value >> 3U); // tags 0 and 19000 to 19999 are not allowed as per // https://developers.google.com/protocol-buffers/docs/proto#assigning-tags @@ -287,7 +295,7 @@ public: throw invalid_tag_exception{}; } - m_wire_type = pbf_wire_type(value & 0x07u); + m_wire_type = pbf_wire_type(value & 0x07U); switch (m_wire_type) { case pbf_wire_type::varint: case pbf_wire_type::fixed64: @@ -486,9 +494,9 @@ public: bool get_bool() { protozero_assert(tag() != 0 && "call next() before accessing field value"); protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); - const auto data = m_data; + const bool result = m_data[0] != 0; skip_varint(&m_data, m_end); - return data[0] != 0; + return result; } /** diff --git a/third_party/protozero/include/protozero/pbf_writer.hpp b/third_party/protozero/include/protozero/pbf_writer.hpp index 1abe9a38a..9a07bd5b9 100644 --- a/third_party/protozero/include/protozero/pbf_writer.hpp +++ b/third_party/protozero/include/protozero/pbf_writer.hpp @@ -16,1033 +16,60 @@ documentation. * @brief Contains the pbf_writer class. */ -#include -#include -#include -#include +#include "basic_pbf_writer.hpp" +#include "buffer_string.hpp" -#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN -# include -#endif - -#include #include -#include -#include -#include -#include #include -#include namespace protozero { -namespace detail { - - template class packed_field_varint; - template class packed_field_svarint; - template class packed_field_fixed; - -} // end namespace detail - /** - * The pbf_writer is used to write PBF formatted messages into a buffer. - * - * Almost all methods in this class can throw an std::bad_alloc exception if - * the std::string used as a buffer wants to resize. + * Specialization of basic_pbf_writer using std::string as buffer type. */ -class pbf_writer { - - // A pointer to a string buffer holding the data already written to the - // PBF message. For default constructed writers or writers that have been - // rolled back, this is a nullptr. - std::string* m_data = nullptr; - - // A pointer to a parent writer object if this is a submessage. If this - // is a top-level writer, it is a nullptr. - pbf_writer* m_parent_writer = nullptr; - - // This is usually 0. If there is an open submessage, this is set in the - // parent to the rollback position, ie. the last position before the - // submessage was started. This is the position where the header of the - // submessage starts. - std::size_t m_rollback_pos = 0; - - // This is usually 0. If there is an open submessage, this is set in the - // parent to the position where the data of the submessage is written to. - std::size_t m_pos = 0; - - void add_varint(uint64_t value) { - protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage"); - protozero_assert(m_data); - write_varint(std::back_inserter(*m_data), value); - } - - void add_field(pbf_tag_type tag, pbf_wire_type type) { - protozero_assert(((tag > 0 && tag < 19000) || (tag > 19999 && tag <= ((1u << 29u) - 1))) && "tag out of range"); - const uint32_t b = (tag << 3u) | uint32_t(type); - add_varint(b); - } - - void add_tagged_varint(pbf_tag_type tag, uint64_t value) { - add_field(tag, pbf_wire_type::varint); - add_varint(value); - } - - template - void add_fixed(T value) { - protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage"); - protozero_assert(m_data); -#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN - detail::byteswap_inplace(&value); -#endif - m_data->append(reinterpret_cast(&value), sizeof(T)); - } - - template - void add_packed_fixed(pbf_tag_type tag, It first, It last, std::input_iterator_tag /*unused*/) { - if (first == last) { - return; - } - - pbf_writer sw{*this, tag}; - - while (first != last) { - sw.add_fixed(*first++); - } - } - - template - void add_packed_fixed(pbf_tag_type tag, It first, It last, std::forward_iterator_tag /*unused*/) { - if (first == last) { - return; - } - - const auto length = std::distance(first, last); - add_length_varint(tag, sizeof(T) * pbf_length_type(length)); - reserve(sizeof(T) * std::size_t(length)); - - while (first != last) { - add_fixed(*first++); - } - } - - template - void add_packed_varint(pbf_tag_type tag, It first, It last) { - if (first == last) { - return; - } - - pbf_writer sw{*this, tag}; - - while (first != last) { - sw.add_varint(uint64_t(*first++)); - } - } - - template - void add_packed_svarint(pbf_tag_type tag, It first, It last) { - if (first == last) { - return; - } - - pbf_writer sw{*this, tag}; - - while (first != last) { - sw.add_varint(encode_zigzag64(*first++)); - } - } - - // The number of bytes to reserve for the varint holding the length of - // a length-delimited field. The length has to fit into pbf_length_type, - // and a varint needs 8 bit for every 7 bit. - enum constant_reserve_bytes : int { - reserve_bytes = sizeof(pbf_length_type) * 8 / 7 + 1 - }; - - // If m_rollpack_pos is set to this special value, it means that when - // the submessage is closed, nothing needs to be done, because the length - // of the submessage has already been written correctly. - enum constant_size_is_known : std::size_t { - size_is_known = std::numeric_limits::max() - }; - - void open_submessage(pbf_tag_type tag, std::size_t size) { - protozero_assert(m_pos == 0); - protozero_assert(m_data); - if (size == 0) { - m_rollback_pos = m_data->size(); - add_field(tag, pbf_wire_type::length_delimited); - m_data->append(std::size_t(reserve_bytes), '\0'); - } else { - m_rollback_pos = size_is_known; - add_length_varint(tag, pbf_length_type(size)); - reserve(size); - } - m_pos = m_data->size(); - } - - void rollback_submessage() { - protozero_assert(m_pos != 0); - protozero_assert(m_rollback_pos != size_is_known); - protozero_assert(m_data); - m_data->resize(m_rollback_pos); - m_pos = 0; - } - - void commit_submessage() { - protozero_assert(m_pos != 0); - protozero_assert(m_rollback_pos != size_is_known); - protozero_assert(m_data); - const auto length = pbf_length_type(m_data->size() - m_pos); - - protozero_assert(m_data->size() >= m_pos - reserve_bytes); - const auto n = write_varint(m_data->begin() + int64_t(m_pos) - reserve_bytes, length); - - m_data->erase(m_data->begin() + int64_t(m_pos) - reserve_bytes + n, m_data->begin() + int64_t(m_pos)); - m_pos = 0; - } - - void close_submessage() { - protozero_assert(m_data); - if (m_pos == 0 || m_rollback_pos == size_is_known) { - return; - } - if (m_data->size() - m_pos == 0) { - rollback_submessage(); - } else { - commit_submessage(); - } - } - - void add_length_varint(pbf_tag_type tag, pbf_length_type length) { - add_field(tag, pbf_wire_type::length_delimited); - add_varint(length); - } - -public: - - /** - * Create a writer using the given string as a data store. The pbf_writer - * stores a reference to that string and adds all data to it. The string - * doesn't have to be empty. The pbf_writer will just append data. - */ - explicit pbf_writer(std::string& data) noexcept : - m_data(&data) { - } - - /** - * Create a writer without a data store. In this form the writer can not - * be used! - */ - pbf_writer() noexcept = default; - - /** - * Construct a pbf_writer for a submessage from the pbf_writer of the - * parent message. - * - * @param parent_writer The pbf_writer - * @param tag Tag (field number) of the field that will be written - * @param size Optional size of the submessage in bytes (use 0 for unknown). - * Setting this allows some optimizations but is only possible in - * a few very specific cases. - */ - pbf_writer(pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size=0) : - m_data(parent_writer.m_data), - m_parent_writer(&parent_writer) { - m_parent_writer->open_submessage(tag, size); - } - - /// A pbf_writer object can not be copied - pbf_writer(const pbf_writer&) = delete; - - /// A pbf_writer object can not be copied - pbf_writer& operator=(const pbf_writer&) = delete; - - /** - * A pbf_writer object can be moved. After this the other pbf_writer will - * be invalid. - */ - pbf_writer(pbf_writer&& other) noexcept : - m_data(other.m_data), - m_parent_writer(other.m_parent_writer), - m_rollback_pos(other.m_rollback_pos), - m_pos(other.m_pos) { - other.m_data = nullptr; - other.m_parent_writer = nullptr; - other.m_rollback_pos = 0; - other.m_pos = 0; - } - - /** - * A pbf_writer object can be moved. After this the other pbf_writer will - * be invalid. - */ - pbf_writer& operator=(pbf_writer&& other) noexcept { - m_data = other.m_data; - m_parent_writer = other.m_parent_writer; - m_rollback_pos = other.m_rollback_pos; - m_pos = other.m_pos; - other.m_data = nullptr; - other.m_parent_writer = nullptr; - other.m_rollback_pos = 0; - other.m_pos = 0; - return *this; - } - - ~pbf_writer() { - if (m_parent_writer != nullptr) { - m_parent_writer->close_submessage(); - } - } - - /** - * Check if this writer is valid. A writer is invalid if it was default - * constructed, moved from, or if commit() has been called on it. - * Otherwise it is valid. - */ - bool valid() const noexcept { - return m_data != nullptr; - } - - /** - * Swap the contents of this object with the other. - * - * @param other Other object to swap data with. - */ - void swap(pbf_writer& other) noexcept { - using std::swap; - swap(m_data, other.m_data); - swap(m_parent_writer, other.m_parent_writer); - swap(m_rollback_pos, other.m_rollback_pos); - swap(m_pos, other.m_pos); - } - - /** - * Reserve size bytes in the underlying message store in addition to - * whatever the message store already holds. So unlike - * the `std::string::reserve()` method this is not an absolute size, - * but additional memory that should be reserved. - * - * @param size Number of bytes to reserve in underlying message store. - */ - void reserve(std::size_t size) { - protozero_assert(m_data); - m_data->reserve(m_data->size() + size); - } - - /** - * Commit this submessage. This does the same as when the pbf_writer - * goes out of scope and is destructed. - * - * @pre Must be a pbf_writer of a submessage, ie one opened with the - * pbf_writer constructor taking a parent message. - * @post The pbf_writer is invalid and can't be used any more. - */ - void commit() { - protozero_assert(m_parent_writer && "you can't call commit() on a pbf_writer without a parent"); - protozero_assert(m_pos == 0 && "you can't call commit() on a pbf_writer that has an open nested submessage"); - m_parent_writer->close_submessage(); - m_parent_writer = nullptr; - m_data = nullptr; - } - - /** - * Cancel writing of this submessage. The complete submessage will be - * removed as if it was never created and no fields were added. - * - * @pre Must be a pbf_writer of a submessage, ie one opened with the - * pbf_writer constructor taking a parent message. - * @post The pbf_writer is invalid and can't be used any more. - */ - void rollback() { - protozero_assert(m_parent_writer && "you can't call rollback() on a pbf_writer without a parent"); - protozero_assert(m_pos == 0 && "you can't call rollback() on a pbf_writer that has an open nested submessage"); - m_parent_writer->rollback_submessage(); - m_parent_writer = nullptr; - m_data = nullptr; - } - - ///@{ - /** - * @name Scalar field writer functions - */ - - /** - * Add "bool" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_bool(pbf_tag_type tag, bool value) { - add_field(tag, pbf_wire_type::varint); - protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage"); - protozero_assert(m_data); - m_data->append(1, char(value)); - } - - /** - * Add "enum" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_enum(pbf_tag_type tag, int32_t value) { - add_tagged_varint(tag, uint64_t(value)); - } - - /** - * Add "int32" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_int32(pbf_tag_type tag, int32_t value) { - add_tagged_varint(tag, uint64_t(value)); - } - - /** - * Add "sint32" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_sint32(pbf_tag_type tag, int32_t value) { - add_tagged_varint(tag, encode_zigzag32(value)); - } - - /** - * Add "uint32" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_uint32(pbf_tag_type tag, uint32_t value) { - add_tagged_varint(tag, value); - } - - /** - * Add "int64" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_int64(pbf_tag_type tag, int64_t value) { - add_tagged_varint(tag, uint64_t(value)); - } - - /** - * Add "sint64" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_sint64(pbf_tag_type tag, int64_t value) { - add_tagged_varint(tag, encode_zigzag64(value)); - } - - /** - * Add "uint64" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_uint64(pbf_tag_type tag, uint64_t value) { - add_tagged_varint(tag, value); - } - - /** - * Add "fixed32" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_fixed32(pbf_tag_type tag, uint32_t value) { - add_field(tag, pbf_wire_type::fixed32); - add_fixed(value); - } - - /** - * Add "sfixed32" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_sfixed32(pbf_tag_type tag, int32_t value) { - add_field(tag, pbf_wire_type::fixed32); - add_fixed(value); - } - - /** - * Add "fixed64" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_fixed64(pbf_tag_type tag, uint64_t value) { - add_field(tag, pbf_wire_type::fixed64); - add_fixed(value); - } - - /** - * Add "sfixed64" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_sfixed64(pbf_tag_type tag, int64_t value) { - add_field(tag, pbf_wire_type::fixed64); - add_fixed(value); - } - - /** - * Add "float" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_float(pbf_tag_type tag, float value) { - add_field(tag, pbf_wire_type::fixed32); - add_fixed(value); - } - - /** - * Add "double" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_double(pbf_tag_type tag, double value) { - add_field(tag, pbf_wire_type::fixed64); - add_fixed(value); - } - - /** - * Add "bytes" field to data. - * - * @param tag Tag (field number) of the field - * @param value Pointer to value to be written - * @param size Number of bytes to be written - */ - void add_bytes(pbf_tag_type tag, const char* value, std::size_t size) { - protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage"); - protozero_assert(m_data); - protozero_assert(size <= std::numeric_limits::max()); - add_length_varint(tag, pbf_length_type(size)); - m_data->append(value, size); - } - - /** - * Add "bytes" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_bytes(pbf_tag_type tag, const data_view& value) { - add_bytes(tag, value.data(), value.size()); - } - - /** - * Add "bytes" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_bytes(pbf_tag_type tag, const std::string& value) { - add_bytes(tag, value.data(), value.size()); - } - - /** - * Add "bytes" field to data. Bytes from the value are written until - * a null byte is encountered. The null byte is not added. - * - * @param tag Tag (field number) of the field - * @param value Pointer to zero-delimited value to be written - */ - void add_bytes(pbf_tag_type tag, const char* value) { - add_bytes(tag, value, std::strlen(value)); - } - - /** - * Add "bytes" field to data using vectored input. All the data in the - * 2nd and further arguments is "concatenated" with only a single copy - * into the final buffer. - * - * This will work with objects of any type supporting the data() and - * size() methods like std::string or protozero::data_view. - * - * Example: - * @code - * std::string data1 = "abc"; - * std::string data2 = "xyz"; - * writer.add_bytes_vectored(1, data1, data2); - * @endcode - * - * @tparam Ts List of types supporting data() and size() methods. - * @param tag Tag (field number) of the field - * @param values List of objects of types Ts with data to be appended. - */ - template - void add_bytes_vectored(pbf_tag_type tag, Ts&&... values) { - protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage"); - protozero_assert(m_data); - size_t sum_size = 0; - (void)std::initializer_list{sum_size += values.size()...}; - protozero_assert(sum_size <= std::numeric_limits::max()); - add_length_varint(tag, pbf_length_type(sum_size)); - m_data->reserve(m_data->size() + sum_size); - (void)std::initializer_list{(m_data->append(values.data(), values.size()), 0)...}; - } - - /** - * Add "string" field to data. - * - * @param tag Tag (field number) of the field - * @param value Pointer to value to be written - * @param size Number of bytes to be written - */ - void add_string(pbf_tag_type tag, const char* value, std::size_t size) { - add_bytes(tag, value, size); - } - - /** - * Add "string" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_string(pbf_tag_type tag, const data_view& value) { - add_bytes(tag, value.data(), value.size()); - } - - /** - * Add "string" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written - */ - void add_string(pbf_tag_type tag, const std::string& value) { - add_bytes(tag, value.data(), value.size()); - } - - /** - * Add "string" field to data. Bytes from the value are written until - * a null byte is encountered. The null byte is not added. - * - * @param tag Tag (field number) of the field - * @param value Pointer to value to be written - */ - void add_string(pbf_tag_type tag, const char* value) { - add_bytes(tag, value, std::strlen(value)); - } - - /** - * Add "message" field to data. - * - * @param tag Tag (field number) of the field - * @param value Pointer to message to be written - * @param size Length of the message - */ - void add_message(pbf_tag_type tag, const char* value, std::size_t size) { - add_bytes(tag, value, size); - } - - /** - * Add "message" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written. The value must be a complete message. - */ - void add_message(pbf_tag_type tag, const data_view& value) { - add_bytes(tag, value.data(), value.size()); - } - - /** - * Add "message" field to data. - * - * @param tag Tag (field number) of the field - * @param value Value to be written. The value must be a complete message. - */ - void add_message(pbf_tag_type tag, const std::string& value) { - add_bytes(tag, value.data(), value.size()); - } - - ///@} - - ///@{ - /** - * @name Repeated packed field writer functions - */ - - /** - * Add "repeated packed bool" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to bool. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_bool(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_varint(tag, first, last); - } - - /** - * Add "repeated packed enum" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to int32_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_enum(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_varint(tag, first, last); - } - - /** - * Add "repeated packed int32" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to int32_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_int32(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_varint(tag, first, last); - } - - /** - * Add "repeated packed sint32" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to int32_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_sint32(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_svarint(tag, first, last); - } - - /** - * Add "repeated packed uint32" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to uint32_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_uint32(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_varint(tag, first, last); - } - - /** - * Add "repeated packed int64" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to int64_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_int64(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_varint(tag, first, last); - } - - /** - * Add "repeated packed sint64" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to int64_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_sint64(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_svarint(tag, first, last); - } - - /** - * Add "repeated packed uint64" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to uint64_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_uint64(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_varint(tag, first, last); - } - - /** - * Add "repeated packed fixed32" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to uint32_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_fixed32(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_fixed(tag, first, last, - typename std::iterator_traits::iterator_category()); - } - - /** - * Add "repeated packed sfixed32" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to int32_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_sfixed32(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_fixed(tag, first, last, - typename std::iterator_traits::iterator_category()); - } - - /** - * Add "repeated packed fixed64" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to uint64_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_fixed64(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_fixed(tag, first, last, - typename std::iterator_traits::iterator_category()); - } - - /** - * Add "repeated packed sfixed64" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to int64_t. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_sfixed64(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_fixed(tag, first, last, - typename std::iterator_traits::iterator_category()); - } - - /** - * Add "repeated packed float" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to float. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_float(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_fixed(tag, first, last, - typename std::iterator_traits::iterator_category()); - } - - /** - * Add "repeated packed double" field to data. - * - * @tparam InputIterator A type satisfying the InputIterator concept. - * Dereferencing the iterator must yield a type assignable to double. - * @param tag Tag (field number) of the field - * @param first Iterator pointing to the beginning of the data - * @param last Iterator pointing one past the end of data - */ - template - void add_packed_double(pbf_tag_type tag, InputIterator first, InputIterator last) { - add_packed_fixed(tag, first, last, - typename std::iterator_traits::iterator_category()); - } - - ///@} - - template friend class detail::packed_field_varint; - template friend class detail::packed_field_svarint; - template friend class detail::packed_field_fixed; - -}; // class pbf_writer - -/** - * Swap two pbf_writer objects. - * - * @param lhs First object. - * @param rhs Second object. - */ -inline void swap(pbf_writer& lhs, pbf_writer& rhs) noexcept { - lhs.swap(rhs); -} - -namespace detail { - - class packed_field { - - protected: - - pbf_writer m_writer{}; - - public: - - packed_field(const packed_field&) = delete; - packed_field& operator=(const packed_field&) = delete; - - packed_field(packed_field&&) noexcept = default; - packed_field& operator=(packed_field&&) noexcept = default; - - packed_field() = default; - - packed_field(pbf_writer& parent_writer, pbf_tag_type tag) : - m_writer(parent_writer, tag) { - } - - packed_field(pbf_writer& parent_writer, pbf_tag_type tag, std::size_t size) : - m_writer(parent_writer, tag, size) { - } - - ~packed_field() noexcept = default; - - bool valid() const noexcept { - return m_writer.valid(); - } - - void commit() { - m_writer.commit(); - } - - void rollback() { - m_writer.rollback(); - } - - }; // class packed_field - - template - class packed_field_fixed : public packed_field { - - public: - - packed_field_fixed() : - packed_field() { - } - - template - packed_field_fixed(pbf_writer& parent_writer, P tag) : - packed_field(parent_writer, static_cast(tag)) { - } - - template - packed_field_fixed(pbf_writer& parent_writer, P tag, std::size_t size) : - packed_field(parent_writer, static_cast(tag), size * sizeof(T)) { - } - - void add_element(T value) { - m_writer.add_fixed(value); - } - - }; // class packed_field_fixed - - template - class packed_field_varint : public packed_field { - - public: - - packed_field_varint() : - packed_field() { - } - - template - packed_field_varint(pbf_writer& parent_writer, P tag) : - packed_field(parent_writer, static_cast(tag)) { - } - - void add_element(T value) { - m_writer.add_varint(uint64_t(value)); - } - - }; // class packed_field_varint - - template - class packed_field_svarint : public packed_field { - - public: - - packed_field_svarint() : - packed_field() { - } - - template - packed_field_svarint(pbf_writer& parent_writer, P tag) : - packed_field(parent_writer, static_cast(tag)) { - } - - void add_element(T value) { - m_writer.add_varint(encode_zigzag64(value)); - } - - }; // class packed_field_svarint - -} // end namespace detail +using pbf_writer = basic_pbf_writer; /// Class for generating packed repeated bool fields. -using packed_field_bool = detail::packed_field_varint; +using packed_field_bool = detail::packed_field_varint; /// Class for generating packed repeated enum fields. -using packed_field_enum = detail::packed_field_varint; +using packed_field_enum = detail::packed_field_varint; /// Class for generating packed repeated int32 fields. -using packed_field_int32 = detail::packed_field_varint; +using packed_field_int32 = detail::packed_field_varint; /// Class for generating packed repeated sint32 fields. -using packed_field_sint32 = detail::packed_field_svarint; +using packed_field_sint32 = detail::packed_field_svarint; /// Class for generating packed repeated uint32 fields. -using packed_field_uint32 = detail::packed_field_varint; +using packed_field_uint32 = detail::packed_field_varint; /// Class for generating packed repeated int64 fields. -using packed_field_int64 = detail::packed_field_varint; +using packed_field_int64 = detail::packed_field_varint; /// Class for generating packed repeated sint64 fields. -using packed_field_sint64 = detail::packed_field_svarint; +using packed_field_sint64 = detail::packed_field_svarint; /// Class for generating packed repeated uint64 fields. -using packed_field_uint64 = detail::packed_field_varint; +using packed_field_uint64 = detail::packed_field_varint; /// Class for generating packed repeated fixed32 fields. -using packed_field_fixed32 = detail::packed_field_fixed; +using packed_field_fixed32 = detail::packed_field_fixed; /// Class for generating packed repeated sfixed32 fields. -using packed_field_sfixed32 = detail::packed_field_fixed; +using packed_field_sfixed32 = detail::packed_field_fixed; /// Class for generating packed repeated fixed64 fields. -using packed_field_fixed64 = detail::packed_field_fixed; +using packed_field_fixed64 = detail::packed_field_fixed; /// Class for generating packed repeated sfixed64 fields. -using packed_field_sfixed64 = detail::packed_field_fixed; +using packed_field_sfixed64 = detail::packed_field_fixed; /// Class for generating packed repeated float fields. -using packed_field_float = detail::packed_field_fixed; +using packed_field_float = detail::packed_field_fixed; /// Class for generating packed repeated double fields. -using packed_field_double = detail::packed_field_fixed; +using packed_field_double = detail::packed_field_fixed; } // end namespace protozero diff --git a/third_party/protozero/include/protozero/types.hpp b/third_party/protozero/include/protozero/types.hpp index b5241274e..3aefddfb5 100644 --- a/third_party/protozero/include/protozero/types.hpp +++ b/third_party/protozero/include/protozero/types.hpp @@ -16,7 +16,7 @@ documentation. * @brief Contains the declaration of low-level types used in the pbf format. */ -#include +#include "config.hpp" #include #include @@ -53,7 +53,7 @@ enum class pbf_wire_type : uint32_t { */ template constexpr inline uint32_t tag_and_type(T tag, pbf_wire_type wire_type) noexcept { - return (static_cast(static_cast(tag)) << 3u) | static_cast(wire_type); + return (static_cast(static_cast(tag)) << 3U) | static_cast(wire_type); } /** diff --git a/third_party/protozero/include/protozero/varint.hpp b/third_party/protozero/include/protozero/varint.hpp index dd79a6ef9..b4648a442 100644 --- a/third_party/protozero/include/protozero/varint.hpp +++ b/third_party/protozero/include/protozero/varint.hpp @@ -16,7 +16,8 @@ documentation. * @brief Contains low-level varint and zigzag encoding and decoding functions. */ -#include +#include "buffer_tmpl.hpp" +#include "exception.hpp" #include @@ -31,30 +32,30 @@ namespace detail { // from https://github.com/facebook/folly/blob/master/folly/Varint.h inline uint64_t decode_varint_impl(const char** data, const char* end) { - const auto begin = reinterpret_cast(*data); - const auto iend = reinterpret_cast(end); + const auto* begin = reinterpret_cast(*data); + const auto* iend = reinterpret_cast(end); const int8_t* p = begin; uint64_t val = 0; if (iend - begin >= max_varint_length) { // fast path do { - int64_t b; - b = *p++; val = uint64_t((b & 0x7fu) ); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 7u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 14u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 21u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 28u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 35u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 42u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 49u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x7fu) << 56u); if (b >= 0) { break; } - b = *p++; val |= uint64_t((b & 0x01u) << 63u); if (b >= 0) { break; } + int64_t b = *p++; + val = ((uint64_t(b) & 0x7fU) ); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 7U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 14U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 21U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 28U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 35U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 42U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 49U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x7fU) << 56U); if (b >= 0) { break; } + b = *p++; val |= ((uint64_t(b) & 0x01U) << 63U); if (b >= 0) { break; } throw varint_too_long_exception{}; } while (false); } else { unsigned int shift = 0; while (p != iend && *p < 0) { - val |= uint64_t(*p++ & 0x7fu) << shift; + val |= (uint64_t(*p++) & 0x7fU) << shift; shift += 7; } if (p == iend) { @@ -88,7 +89,7 @@ namespace detail { */ inline uint64_t decode_varint(const char** data, const char* end) { // If this is a one-byte varint, decode it here. - if (end != *data && ((**data & 0x80u) == 0)) { + if (end != *data && ((static_cast(**data) & 0x80U) == 0)) { const auto val = static_cast(**data); ++(*data); return val; @@ -110,15 +111,15 @@ inline uint64_t decode_varint(const char** data, const char* end) { * before the end of the varint. */ inline void skip_varint(const char** data, const char* end) { - const auto begin = reinterpret_cast(*data); - const auto iend = reinterpret_cast(end); + const auto* begin = reinterpret_cast(*data); + const auto* iend = reinterpret_cast(end); const int8_t* p = begin; while (p != iend && *p < 0) { ++p; } - if (p >= begin + max_varint_length) { + if (p - begin >= max_varint_length) { throw varint_too_long_exception{}; } @@ -140,17 +141,73 @@ inline void skip_varint(const char** data, const char* end) { * @param value The integer that will be encoded. * @returns the number of bytes written * @throws Any exception thrown by increment or dereference operator on data. + * @deprecated Use add_varint_to_buffer() instead. */ template inline int write_varint(T data, uint64_t value) { int n = 1; - while (value >= 0x80u) { - *data++ = char((value & 0x7fu) | 0x80u); - value >>= 7u; + while (value >= 0x80U) { + *data++ = char((value & 0x7fU) | 0x80U); + value >>= 7U; + ++n; + } + *data = char(value); + + return n; +} + +/** + * Varint encode a 64 bit integer. + * + * @tparam TBuffer A buffer type. + * @param buffer Output buffer the varint will be written to. + * @param value The integer that will be encoded. + * @returns the number of bytes written + * @throws Any exception thrown by calling the buffer_push_back() function. + */ +template +inline void add_varint_to_buffer(TBuffer* buffer, uint64_t value) { + while (value >= 0x80U) { + buffer_customization::push_back(buffer, char((value & 0x7fU) | 0x80U)); + value >>= 7U; + } + buffer_customization::push_back(buffer, char(value)); +} + +/** + * Varint encode a 64 bit integer. + * + * @param data Where to add the varint. There must be enough space available! + * @param value The integer that will be encoded. + * @returns the number of bytes written + */ +inline int add_varint_to_buffer(char* data, uint64_t value) noexcept { + int n = 1; + + while (value >= 0x80U) { + *data++ = char((value & 0x7fU) | 0x80U); + value >>= 7U; + ++n; + } + *data = char(value); + + return n; +} + +/** + * Get the length of the varint the specified value would produce. + * + * @param value The integer to be encoded. + * @returns the number of bytes the varint would have if we created it. + */ +inline int length_of_varint(uint64_t value) noexcept { + int n = 1; + + while (value >= 0x80U) { + value >>= 7U; ++n; } - *data++ = char(value); return n; } @@ -159,28 +216,28 @@ inline int write_varint(T data, uint64_t value) { * ZigZag encodes a 32 bit integer. */ inline constexpr uint32_t encode_zigzag32(int32_t value) noexcept { - return (static_cast(value) << 1u) ^ (static_cast(value >> 31u)); + return (static_cast(value) << 1U) ^ static_cast(-static_cast(static_cast(value) >> 31U)); } /** * ZigZag encodes a 64 bit integer. */ inline constexpr uint64_t encode_zigzag64(int64_t value) noexcept { - return (static_cast(value) << 1u) ^ (static_cast(value >> 63u)); + return (static_cast(value) << 1U) ^ static_cast(-static_cast(static_cast(value) >> 63U)); } /** * Decodes a 32 bit ZigZag-encoded integer. */ inline constexpr int32_t decode_zigzag32(uint32_t value) noexcept { - return static_cast(value >> 1u) ^ -static_cast(value & 1u); + return static_cast((value >> 1U) ^ static_cast(-static_cast(value & 1U))); } /** * Decodes a 64 bit ZigZag-encoded integer. */ inline constexpr int64_t decode_zigzag64(uint64_t value) noexcept { - return static_cast(value >> 1u) ^ -static_cast(value & 1u); + return static_cast((value >> 1U) ^ static_cast(-static_cast(value & 1U))); } } // end namespace protozero diff --git a/third_party/protozero/include/protozero/version.hpp b/third_party/protozero/include/protozero/version.hpp index 32a494f4b..9a0e4cc9f 100644 --- a/third_party/protozero/include/protozero/version.hpp +++ b/third_party/protozero/include/protozero/version.hpp @@ -20,15 +20,15 @@ documentation. #define PROTOZERO_VERSION_MAJOR 1 /// The minor version number -#define PROTOZERO_VERSION_MINOR 6 +#define PROTOZERO_VERSION_MINOR 7 /// The patch number -#define PROTOZERO_VERSION_PATCH 2 +#define PROTOZERO_VERSION_PATCH 0 /// The complete version number #define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH) /// Version number as string -#define PROTOZERO_VERSION_STRING "1.6.2" +#define PROTOZERO_VERSION_STRING "1.7.0" #endif // PROTOZERO_VERSION_HPP diff --git a/third_party/protozero/test/catch/catch.hpp b/third_party/protozero/test/catch/catch.hpp index 6b5129d60..6beb0eadb 100644 --- a/third_party/protozero/test/catch/catch.hpp +++ b/third_party/protozero/test/catch/catch.hpp @@ -1,17 +1,21 @@ /* - * Catch v1.12.0 - * Generated: 2018-01-11 21:56:34.893972 + * Catch v2.12.1 + * Generated: 2020-04-21 19:29:20.964532 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved. * * 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) */ #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +// start catch.hpp -#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 12 +#define CATCH_VERSION_PATCH 1 #ifdef __clang__ # pragma clang system_header @@ -19,36 +23,66 @@ # pragma GCC system_header #endif -// #included from: internal/catch_suppress_warnings.h +// start catch_suppress_warnings.h #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(push) # pragma warning(disable: 161 1682) # else // __ICC -# pragma clang diagnostic ignored "-Wglobal-constructors" -# pragma clang diagnostic ignored "-Wvariadic-macros" -# pragma clang diagnostic ignored "-Wc99-extensions" -# pragma clang diagnostic ignored "-Wunused-variable" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" -# pragma clang diagnostic ignored "-Wc++98-compat" -# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" # pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ -# pragma GCC diagnostic ignored "-Wvariadic-macros" -# pragma GCC diagnostic ignored "-Wunused-variable" -# pragma GCC diagnostic ignored "-Wparentheses" + // Because REQUIREs trigger GCC's -Wparentheses, and because still + // supported version of g++ have only buggy support for _Pragmas, + // Wparentheses have to be suppressed globally. +# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details # pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic ignored "-Wpadded" #endif +// end catch_suppress_warnings.h #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS #endif +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) +# define CATCH_CONFIG_EXTERNAL_INTERFACES +# if defined(CATCH_CONFIG_DISABLE_MATCHERS) +# undef CATCH_CONFIG_DISABLE_MATCHERS +# endif +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) +// start catch_platform.h + +#ifdef __APPLE__ +# include +# if TARGET_OS_OSX == 1 +# define CATCH_PLATFORM_MAC +# elif TARGET_OS_IPHONE == 1 +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS +#endif + +// end catch_platform.h + #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED @@ -56,93 +90,110 @@ # endif #endif -// #included from: internal/catch_notimplemented_exception.h -#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED +// start catch_user_interfaces.h -// #included from: catch_common.h -#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED +namespace Catch { + unsigned int rngSeed(); +} -// #included from: catch_compiler_capabilities.h -#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h -// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// start catch_common.h + +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler // The following features are defined: // -// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? -// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? -// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods -// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? -// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported -// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? -// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? -// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) -// CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported? -// CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported? - -// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? - -// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too // **************** // In general each macro has a _NO_ form -// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they // can be combined, en-mass, with the _NO_ forms later. -// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 - #ifdef __cplusplus -# if __cplusplus >= 201103L -# define CATCH_CPP11_OR_GREATER +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +# define CATCH_CPP14_OR_GREATER # endif -# if __cplusplus >= 201402L -# define CATCH_CPP14_OR_GREATER +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER # endif #endif -#ifdef __clang__ +#if defined(__cpp_lib_uncaught_exceptions) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif -# if __has_feature(cxx_nullptr) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +// We have to avoid both ICC and Clang, because they try to mask themselves +// as gcc, and we want only GCC in this block +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) + +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) + +#endif + +#if defined(__clang__) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) + +// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug +// which results in calls to destructors being emitted for each temporary, +// without a matching initialization. In practice, this can result in something +// like `std::string::~string` being called on an uninitialized value. +// +// For example, this code will likely segfault under IBM XL: +// ``` +// REQUIRE(std::string("12") + "34" == "1234") +// ``` +// +// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. +# if !defined(__ibmxl__) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg) */ # endif -# if __has_feature(cxx_noexcept) -# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -# endif +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") -# if defined(CATCH_CPP11_OR_GREATER) -# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ - _Pragma( "clang diagnostic pop" ) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic pop" ) -# endif +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) + +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) #endif // __clang__ +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif + //////////////////////////////////////////////////////////////////////////////// // We know some environments not to support full POSIX signals -#if defined(__CYGWIN__) || defined(__QNX__) - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -# endif - +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS #endif #ifdef __OS400__ @@ -150,6 +201,25 @@ # define CATCH_CONFIG_COLOUR_NONE #endif +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + //////////////////////////////////////////////////////////////////////////////// // Cygwin #ifdef __CYGWIN__ @@ -157,219 +227,248 @@ // Required for some versions of Cygwin to declare gettimeofday // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin # define _BSD_SOURCE +// some versions of cygwin (most) do not support std::to_string. Use the libstd check. +// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 +# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ + && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING + +# endif #endif // __CYGWIN__ -//////////////////////////////////////////////////////////////////////////////// -// Borland -#ifdef __BORLANDC__ - -#endif // __BORLANDC__ - -//////////////////////////////////////////////////////////////////////////////// -// EDG -#ifdef __EDG_VERSION__ - -#endif // __EDG_VERSION__ - -//////////////////////////////////////////////////////////////////////////////// -// Digital Mars -#ifdef __DMC__ - -#endif // __DMC__ - -//////////////////////////////////////////////////////////////////////////////// -// GCC -#ifdef __GNUC__ - -# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# endif - -// - otherwise more recent versions define __cplusplus >= 201103L -// and will get picked up below - -#endif // __GNUC__ - //////////////////////////////////////////////////////////////////////////////// // Visual C++ -#ifdef _MSC_VER +#if defined(_MSC_VER) -#define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) -#if (_MSC_VER >= 1600) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR -#endif +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif -#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) -#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -#define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE -#define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS -#endif +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif + +// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ +// _MSVC_TRADITIONAL == 0 means new conformant preprocessor +// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor +# if !defined(__clang__) // Handle Clang masquerading for msvc +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif // MSVC_TRADITIONAL +# endif // __clang__ #endif // _MSC_VER +#if defined(_REENTRANT) || defined(_MSC_VER) +// Enable async processing, as -pthread is specified or no additional linking is required +# define CATCH_INTERNAL_CONFIG_USE_ASYNC +#endif // _MSC_VER + //////////////////////////////////////////////////////////////////////////////// - -// Use variadic macros if the compiler supports them -#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ - ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ - ( defined __GNUC__ && __GNUC__ >= 3 ) || \ - ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) - -#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS - +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED #endif -// Use __COUNTER__ if the compiler supports it -#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \ - ( defined __GNUC__ && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 )) ) || \ - ( defined __clang__ && __clang_major__ >= 3 ) +//////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ -// Use of __COUNTER__ is suppressed during code analysis in CLion/AppCode 2017.2.x and former, -// because __COUNTER__ is not properly handled by it. -// This does not affect compilation -#if ( !defined __JETBRAINS_IDE__ || __JETBRAINS_IDE__ >= 20170300L ) +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) + #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) #define CATCH_INTERNAL_CONFIG_COUNTER #endif -#endif - //////////////////////////////////////////////////////////////////////////////// -// C++ language feature support -// catch all support for C++11 -#if defined(CATCH_CPP11_OR_GREATER) - -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) -# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM -# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM -# endif - -# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE -# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE -# endif - -# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS -# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS -# endif - -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) -# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG -# endif - -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) -# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE -# endif -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) -# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR -# endif -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) -# define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE -# endif -# if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) -# define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS -# endif - -#endif // __cplusplus >= 201103L - -// Now set the actual defines based on the above + anything the user has configured -#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_NULLPTR +// RTX is a special version of Windows that is real time. +// This means that it is detected as Windows, but does not provide +// the same set of capabilities as real Windows does. +#if defined(UNDER_RTSS) || defined(RTX64_BUILD) + #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH + #define CATCH_INTERNAL_CONFIG_NO_ASYNC + #define CATCH_CONFIG_COLOUR_NONE #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_NOEXCEPT -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_GENERATED_METHODS -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_IS_ENUM -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_TUPLE -#endif -#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) -# define CATCH_CONFIG_VARIADIC_MACROS -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_LONG_LONG -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_OVERRIDE -#endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_UNIQUE_PTR + +#if !defined(_GLIBCXX_USE_C99_MATH_TR1) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER #endif + +// Various stdlib support checks that require __has_include +#if defined(__has_include) + // Check if string_view is available and usable + #if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif + + // Check if optional is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if byte is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 + # include + # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # define CATCH_CONFIG_NO_CPP17_VARIANT + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__clang__) && (__clang_major__ < 8) + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) + #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) # define CATCH_CONFIG_COUNTER #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_SHUFFLE -#endif -# if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11) -# define CATCH_CONFIG_CPP11_TYPE_TRAITS -# endif -#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) # define CATCH_CONFIG_WINDOWS_SEH #endif // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. -#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) # define CATCH_CONFIG_POSIX_SIGNALS #endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) +# define CATCH_CONFIG_CPP17_VARIANT +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) +# define CATCH_CONFIG_CPP17_BYTE +#endif + +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) +# define CATCH_CONFIG_POLYFILL_ISNAN +#endif + +#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) +# define CATCH_CONFIG_USE_ASYNC +#endif + +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +# define CATCH_CONFIG_ANDROID_LOGWRITE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Even if we do not think the compiler has that warning, we still have +// to provide a macro that can be used by the code. +#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS #endif -#if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS #endif -// noexcept support: -#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) -# define CATCH_NOEXCEPT noexcept -# define CATCH_NOEXCEPT_IS(x) noexcept(x) +// The goal of this macro is to avoid evaluation of the arguments, but +// still have the compiler warn on problems inside... +#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) +#endif + +#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#elif defined(__clang__) && (__clang_major__ < 5) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) #else -# define CATCH_NOEXCEPT throw() -# define CATCH_NOEXCEPT_IS(x) +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) #endif -// nullptr support -#ifdef CATCH_CONFIG_CPP11_NULLPTR -# define CATCH_NULL nullptr -#else -# define CATCH_NULL NULL -#endif - -// override support -#ifdef CATCH_CONFIG_CPP11_OVERRIDE -# define CATCH_OVERRIDE override -#else -# define CATCH_OVERRIDE -#endif - -// unique_ptr support -#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR -# define CATCH_AUTO_PTR( T ) std::unique_ptr -#else -# define CATCH_AUTO_PTR( T ) std::auto_ptr +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #endif +// end catch_compiler_capabilities.h #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) #ifdef CATCH_CONFIG_COUNTER @@ -378,95 +477,48 @@ # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) #endif -#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr -#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) +#include +#include +#include -#include -#include +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); namespace Catch { - struct IConfig; - struct CaseSensitive { enum Choice { Yes, No }; }; class NonCopyable { -#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable& operator = ( NonCopyable const& ) = delete; NonCopyable& operator = ( NonCopyable && ) = delete; -#else - NonCopyable( NonCopyable const& info ); - NonCopyable& operator = ( NonCopyable const& ); -#endif protected: - NonCopyable() {} + NonCopyable(); virtual ~NonCopyable(); }; - class SafeBool { - public: - typedef void (SafeBool::*type)() const; - - static type makeSafe( bool value ) { - return value ? &SafeBool::trueValue : 0; - } - private: - void trueValue() const {} - }; - - template - void deleteAll( ContainerT& container ) { - typename ContainerT::const_iterator it = container.begin(); - typename ContainerT::const_iterator itEnd = container.end(); - for(; it != itEnd; ++it ) - delete *it; - } - template - void deleteAllValues( AssociativeContainerT& container ) { - typename AssociativeContainerT::const_iterator it = container.begin(); - typename AssociativeContainerT::const_iterator itEnd = container.end(); - for(; it != itEnd; ++it ) - delete it->second; - } - - bool startsWith( std::string const& s, std::string const& prefix ); - bool startsWith( std::string const& s, char prefix ); - bool endsWith( std::string const& s, std::string const& suffix ); - bool endsWith( std::string const& s, char suffix ); - bool contains( std::string const& s, std::string const& infix ); - void toLowerInPlace( std::string& s ); - std::string toLower( std::string const& s ); - std::string trim( std::string const& str ); - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); - - struct pluralise { - pluralise( std::size_t count, std::string const& label ); - - friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); - - std::size_t m_count; - std::string m_label; - }; - struct SourceLineInfo { - SourceLineInfo(); - SourceLineInfo( char const* _file, std::size_t _line ); -# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS - SourceLineInfo(SourceLineInfo const& other) = default; - SourceLineInfo( SourceLineInfo && ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo& operator = ( SourceLineInfo && ) = default; -# endif - bool empty() const; - bool operator == ( SourceLineInfo const& other ) const; - bool operator < ( SourceLineInfo const& other ) const; + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} + + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo( SourceLineInfo&& ) noexcept = default; + SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; + + bool empty() const noexcept { return file[0] == '\0'; } + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; char const* file; std::size_t line; @@ -474,24 +526,17 @@ namespace Catch { std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); - // This is just here to avoid compiler warnings with macro constants and boolean literals - inline bool isTrue( bool value ){ return value; } - inline bool alwaysTrue() { return true; } - inline bool alwaysFalse() { return false; } - - void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); - - void seedRng( IConfig const& config ); - unsigned int rngSeed(); + // Bring in operator<< from global namespace into Catch namespace + // This is necessary because the overload of operator<< above makes + // lookup stop at namespace Catch + using ::operator<<; // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as // >> stuff +StreamEndStop struct StreamEndStop { - std::string operator+() { - return std::string(); - } + std::string operator+() const; }; template T const& operator + ( T const& value, StreamEndStop ) { @@ -499,180 +544,28 @@ namespace Catch { } } -#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) -#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) +// end catch_common.h namespace Catch { - class NotImplementedException : public std::exception - { - public: - NotImplementedException( SourceLineInfo const& lineInfo ); - - virtual ~NotImplementedException() CATCH_NOEXCEPT {} - - virtual const char* what() const CATCH_NOEXCEPT; - - private: - std::string m_what; - SourceLineInfo m_lineInfo; + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); }; } // end namespace Catch -/////////////////////////////////////////////////////////////////////////////// -#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION -// #included from: internal/catch_context.h -#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h -// #included from: catch_interfaces_generators.h -#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED - -#include - -namespace Catch { - - struct IGeneratorInfo { - virtual ~IGeneratorInfo(); - virtual bool moveNext() = 0; - virtual std::size_t getCurrentIndex() const = 0; - }; - - struct IGeneratorsForTest { - virtual ~IGeneratorsForTest(); - - virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; - virtual bool moveNext() = 0; - }; - - IGeneratorsForTest* createGeneratorsForTest(); - -} // end namespace Catch - -// #included from: catch_ptr.hpp -#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -namespace Catch { - - // An intrusive reference counting smart pointer. - // T must implement addRef() and release() methods - // typically implementing the IShared interface - template - class Ptr { - public: - Ptr() : m_p( CATCH_NULL ){} - Ptr( T* p ) : m_p( p ){ - if( m_p ) - m_p->addRef(); - } - Ptr( Ptr const& other ) : m_p( other.m_p ){ - if( m_p ) - m_p->addRef(); - } - ~Ptr(){ - if( m_p ) - m_p->release(); - } - void reset() { - if( m_p ) - m_p->release(); - m_p = CATCH_NULL; - } - Ptr& operator = ( T* p ){ - Ptr temp( p ); - swap( temp ); - return *this; - } - Ptr& operator = ( Ptr const& other ){ - Ptr temp( other ); - swap( temp ); - return *this; - } - void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } - T* get() const{ return m_p; } - T& operator*() const { return *m_p; } - T* operator->() const { return m_p; } - bool operator !() const { return m_p == CATCH_NULL; } - operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } - - private: - T* m_p; - }; - - struct IShared : NonCopyable { - virtual ~IShared(); - virtual void addRef() const = 0; - virtual void release() const = 0; - }; - - template - struct SharedImpl : T { - - SharedImpl() : m_rc( 0 ){} - - virtual void addRef() const { - ++m_rc; - } - virtual void release() const { - if( --m_rc == 0 ) - delete this; - } - - mutable unsigned int m_rc; - }; - -} // end namespace Catch - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -namespace Catch { - - class TestCase; - class Stream; - struct IResultCapture; - struct IRunner; - struct IGeneratorsForTest; - struct IConfig; - - struct IContext - { - virtual ~IContext(); - - virtual IResultCapture* getResultCapture() = 0; - virtual IRunner* getRunner() = 0; - virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; - virtual bool advanceGeneratorsForCurrentTest() = 0; - virtual Ptr getConfig() const = 0; - }; - - struct IMutableContext : IContext - { - virtual ~IMutableContext(); - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setRunner( IRunner* runner ) = 0; - virtual void setConfig( Ptr const& config ) = 0; - }; - - IContext& getCurrentContext(); - IMutableContext& getCurrentMutableContext(); - void cleanUpContext(); - Stream createStream( std::string const& streamName ); - -} - -// #included from: internal/catch_test_registry.hpp -#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED - -// #included from: catch_interfaces_testcase.h -#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED +// start catch_interfaces_testcase.h #include @@ -680,10 +573,9 @@ namespace Catch { class TestSpec; - struct ITestCase : IShared { + struct ITestInvoker { virtual void invoke () const = 0; - protected: - virtual ~ITestCase(); + virtual ~ITestInvoker(); }; class TestCase; @@ -695,167 +587,769 @@ namespace Catch { virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector const& getAllTestCasesSorted( IConfig const& config ); } +// end catch_interfaces_testcase.h +// start catch_stringref.h + +#include +#include +#include +#include + +namespace Catch { + + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. + class StringRef { + public: + using size_type = std::size_t; + using const_iterator = const char*; + + private: + static constexpr char const* const s_empty = ""; + + char const* m_start = s_empty; + size_type m_size = 0; + + public: // construction + constexpr StringRef() noexcept = default; + + StringRef( char const* rawChars ) noexcept; + + constexpr StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + explicit operator std::string() const { + return std::string(m_start, m_size); + } + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != (StringRef const& other) const noexcept -> bool { + return !(*this == other); + } + + auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } + + public: // named queries + constexpr auto empty() const noexcept -> bool { + return m_size == 0; + } + constexpr auto size() const noexcept -> size_type { + return m_size; + } + + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception + auto c_str() const -> char const*; + + public: // substrings and searches + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr( size_type start, size_type length ) const noexcept -> StringRef; + + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const*; + + constexpr auto isNullTerminated() const noexcept -> bool { + return m_start[m_size] == '\0'; + } + + public: // iterators + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } + }; + + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + + constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } +} // namespace Catch + +constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); +} + +// end catch_stringref.h +// start catch_preprocessor.hpp + + +#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ +#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) + +#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ +// MSVC needs more evaluations +#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) +#else +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) +#endif + +#define CATCH_REC_END(...) +#define CATCH_REC_OUT + +#define CATCH_EMPTY() +#define CATCH_DEFER(id) id CATCH_EMPTY() + +#define CATCH_REC_GET_END2() 0, CATCH_REC_END +#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 +#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 +#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT +#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) +#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) + +#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) + +#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) + +// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, +// and passes userdata as the first parameter to each invocation, +// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) +#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) +#else +// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) +#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) +#endif + +#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ +#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) + +#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) +#else +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#endif + +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ + CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) + +#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) +#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) +#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) +#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) +#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) +#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) +#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) +#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) + +#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define INTERNAL_CATCH_TYPE_GEN\ + template struct TypeList {};\ + template\ + constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ + template class...> struct TemplateTypeList{};\ + template class...Cs>\ + constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ + template\ + struct append;\ + template\ + struct rewrap;\ + template class, typename...>\ + struct create;\ + template class, typename>\ + struct convert;\ + \ + template \ + struct append { using type = T; };\ + template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ + struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ + template< template class L1, typename...E1, typename...Rest>\ + struct append, TypeList, Rest...> { using type = L1; };\ + \ + template< template class Container, template class List, typename...elems>\ + struct rewrap, List> { using type = TypeList>; };\ + template< template class Container, template class List, class...Elems, typename...Elements>\ + struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ + \ + template