From 1c5b74454fda7f6c8215e076f91cda978c32c84f Mon Sep 17 00:00:00 2001 From: Hartmut Seichter Date: Tue, 15 Dec 2020 12:40:17 +0100 Subject: [PATCH] external UUID implementation for asset tracking --- src/deps/stduuid/.gitignore | 37 + src/deps/stduuid/.travis.yml | 25 + src/deps/stduuid/CMakeLists.txt | 67 + src/deps/stduuid/LICENSE | 21 + src/deps/stduuid/P0959.md | 857 + src/deps/stduuid/README.md | 274 + src/deps/stduuid/appveyor.yml | 28 + src/deps/stduuid/catch/catch.hpp | 17877 ++++++++++++++++ .../stduuid/catch/catch_reporter_automake.hpp | 62 + src/deps/stduuid/catch/catch_reporter_tap.hpp | 255 + .../stduuid/catch/catch_reporter_teamcity.hpp | 220 + src/deps/stduuid/cmake/Config.cmake.in | 14 + src/deps/stduuid/cmake/FindLibuuid.cmake | 17 + src/deps/stduuid/gsl/gsl | 29 + src/deps/stduuid/gsl/gsl_algorithm | 63 + src/deps/stduuid/gsl/gsl_assert | 145 + src/deps/stduuid/gsl/gsl_byte | 181 + src/deps/stduuid/gsl/gsl_util | 158 + src/deps/stduuid/gsl/multi_span | 2242 ++ src/deps/stduuid/gsl/pointers | 193 + src/deps/stduuid/gsl/span | 766 + src/deps/stduuid/gsl/string_span | 730 + src/deps/stduuid/how_to_build.md | 40 + src/deps/stduuid/include/uuid.h | 943 + src/deps/stduuid/lgtm.yml | 5 + src/deps/stduuid/test/CMakeLists.txt | 31 + src/deps/stduuid/test/main.cpp | 3 + src/deps/stduuid/test/test_generators.cpp | 279 + src/deps/stduuid/test/test_uuid.cpp | 520 + 29 files changed, 26082 insertions(+) create mode 100644 src/deps/stduuid/.gitignore create mode 100644 src/deps/stduuid/.travis.yml create mode 100644 src/deps/stduuid/CMakeLists.txt create mode 100644 src/deps/stduuid/LICENSE create mode 100644 src/deps/stduuid/P0959.md create mode 100644 src/deps/stduuid/README.md create mode 100644 src/deps/stduuid/appveyor.yml create mode 100644 src/deps/stduuid/catch/catch.hpp create mode 100644 src/deps/stduuid/catch/catch_reporter_automake.hpp create mode 100644 src/deps/stduuid/catch/catch_reporter_tap.hpp create mode 100644 src/deps/stduuid/catch/catch_reporter_teamcity.hpp create mode 100644 src/deps/stduuid/cmake/Config.cmake.in create mode 100644 src/deps/stduuid/cmake/FindLibuuid.cmake create mode 100644 src/deps/stduuid/gsl/gsl create mode 100644 src/deps/stduuid/gsl/gsl_algorithm create mode 100644 src/deps/stduuid/gsl/gsl_assert create mode 100644 src/deps/stduuid/gsl/gsl_byte create mode 100644 src/deps/stduuid/gsl/gsl_util create mode 100644 src/deps/stduuid/gsl/multi_span create mode 100644 src/deps/stduuid/gsl/pointers create mode 100644 src/deps/stduuid/gsl/span create mode 100644 src/deps/stduuid/gsl/string_span create mode 100644 src/deps/stduuid/how_to_build.md create mode 100644 src/deps/stduuid/include/uuid.h create mode 100644 src/deps/stduuid/lgtm.yml create mode 100644 src/deps/stduuid/test/CMakeLists.txt create mode 100644 src/deps/stduuid/test/main.cpp create mode 100644 src/deps/stduuid/test/test_generators.cpp create mode 100644 src/deps/stduuid/test/test_uuid.cpp diff --git a/src/deps/stduuid/.gitignore b/src/deps/stduuid/.gitignore new file mode 100644 index 0000000..e275b70 --- /dev/null +++ b/src/deps/stduuid/.gitignore @@ -0,0 +1,37 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +/build/.gitignore + +build +/test/CMakeFiles/3.10.0/CompilerIdC/Debug/CompilerIdC.tlog +/.vs diff --git a/src/deps/stduuid/.travis.yml b/src/deps/stduuid/.travis.yml new file mode 100644 index 0000000..f572317 --- /dev/null +++ b/src/deps/stduuid/.travis.yml @@ -0,0 +1,25 @@ +language: cpp +compiler: gcc +dist: trusty + +before_install: + - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test + - sudo apt-get update -qq + - sudo apt-cache search libuuid + +install: + - sudo apt-get install -qq g++-8 + - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-8 90 + - sudo apt-get install -qq cppcheck + - sudo apt-get install uuid-dev + +before_script: + - cd ${TRAVIS_BUILD_DIR} + - cmake -H. -BBuild -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON -Wdev + - cd Build + +script: + - make -j 2 + - ctest -V -j 2 -C Release + - cppcheck --quiet --error-exitcode=1 . + \ No newline at end of file diff --git a/src/deps/stduuid/CMakeLists.txt b/src/deps/stduuid/CMakeLists.txt new file mode 100644 index 0000000..65df943 --- /dev/null +++ b/src/deps/stduuid/CMakeLists.txt @@ -0,0 +1,67 @@ +cmake_minimum_required(VERSION 3.7.0) +project(stduuid CXX) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") + +option(UUID_BUILD_TESTS "Build the unit tests" ON) +option(UUID_SYSTEM_GENERATOR "Enable operating system uuid generator" OFF) +option(UUID_USING_CXX20_SPAN "Using span from std instead of gsl" OFF) + +# Library target +add_library(${PROJECT_NAME} INTERFACE) +target_include_directories(${PROJECT_NAME} INTERFACE + $ + $) + +# Using system uuid generator +if (UUID_SYSTEM_GENERATOR) + target_compile_definitions(${PROJECT_NAME} INTERFACE UUID_SYSTEM_GENERATOR) + + if (WIN32) + elseif (APPLE) + find_library(CFLIB CoreFoundation REQUIRED) + target_link_libraries(${PROJECT_NAME} INTERFACE ${CFLIB}) + else () + find_package(Libuuid REQUIRED) + if (Libuuid_FOUND) + target_include_directories(${PROJECT_NAME} INTERFACE ${Libuuid_INCLUDE_DIRS}) + target_link_libraries(${PROJECT_NAME} INTERFACE ${Libuuid_LIBRARIES}) + endif () + endif () +endif () + +# Using span from std +if (NOT UUID_USING_CXX20_SPAN) + target_include_directories(${PROJECT_NAME} INTERFACE + $ + $) + install(DIRECTORY gsl DESTINATION include) +endif () + +# Install step and imported target +install(FILES include/uuid.h DESTINATION include) +install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets) +install(EXPORT ${PROJECT_NAME}-targets + DESTINATION lib/cmake/${PROJECT_NAME}) + +# Config files for find_package() +include(CMakePackageConfigHelpers) +configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" + INSTALL_DESTINATION lib/cmake/${PROJECT_NAME}) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-version.cmake" + VERSION "1.0" + COMPATIBILITY AnyNewerVersion) +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-version.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindLibuuid.cmake" + DESTINATION lib/cmake/${PROJECT_NAME}) +export(EXPORT ${PROJECT_NAME}-targets + FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}-targets.cmake") + +# Tests +if (UUID_BUILD_TESTS) + enable_testing() + add_subdirectory(test) +endif () \ No newline at end of file diff --git a/src/deps/stduuid/LICENSE b/src/deps/stduuid/LICENSE new file mode 100644 index 0000000..8864d4a --- /dev/null +++ b/src/deps/stduuid/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/deps/stduuid/P0959.md b/src/deps/stduuid/P0959.md new file mode 100644 index 0000000..a1c0c42 --- /dev/null +++ b/src/deps/stduuid/P0959.md @@ -0,0 +1,857 @@ +| ___ | ___ | +| --- | --- | +| Doc. No.: | P0959R3 | +| Date: | 2020-09-09 | +| Reply to: | Marius Bancila, Tony van Eerd | +| Audience: | Library WG | +| Title: | A Proposal for a Universally Unique Identifier Library | + +# A Proposal for a Universally Unique Identifier Library + +## I. Revision History + +### 1.1 P0959R0 +Original UUID library paper with motivation, specification, and examples. + +### 1.2 P0959R1 +Revised with feedback from the LWG and the community. +* Removed string constructors and replaced with an overloaded static member function `from_string()`. +* Parsing strings to `uuid` throws exception `uuid_error` instead of creating a nil uuid when the operation fails. +* {} included in the supported format for string parsing, i.e. `"{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"`. +* Removed `state_size`. +* Rename member function `nil()` to `is_nil()`. +* The default constructor is defaulted. +* Added a conversion construct from `std::span`. +* Added the member function `as_bytes()` to convert the `uuid` into a view of its underlying bytes. +* Constructing a `uuid` from a range with a size other than 16 is undefined behaviour. +* Replaced operators `==`, `!=` and `<` with the three-way operator `<=>` +* Removed mutable iterators (but preserved the constant iterators). +* Removed typedefs and others container-like parts. +* Defined the correlation between the internal UUID bytes and the string representation. +* Added UUID layout and byte order specification from the RFC 4122 document. +* Added section on alternative ordering design +* Most functions are constexpr. +* Replaced typedefs with using statements. + +### 1.3 P0959R2 + +P0959R1 was discussed in San Diego LEWGI (attendance 13 people) with the following feedback in polls: + +* `std::uuid`'s byte ordering should be fixed (implying we have the option to make it memcpy and there is no need for a container-like interface) + + | SF | F | N | A | SA | + |---|---|---|---|---| + | 4 | 3 | 1 | 0 | 0 | + +* `std::uuid` should have iterators (e.g. begin/end methods) + + | SF | F | N | A | SA | + |---|---|---|---|---| + | 2 | 3 | 2 | 1 | 1 | + + *Comment*: interpreted as "author's discretion". + +* `std::uuid` should be able to generate uuids from names + + | SF | F | N | A | SA | + |---|---|---|---|---| + | 4 | 2 | 3 | 0 | 0 | + +* explore having `std::uuid` be able to generate from times + + | SF | F | N | A | SA | + |---|---|---|---|---| + | 4 | 3 | 2 | 0 | 0 | + +* We want `std::basic_uuid_random_generator` + + | SF | F | N | A | SA | + |---|---|---|---|---| + | 0 | 6 | 2 | 0 | 1 | + + *Comments*: Author is instructed to investigate less hazardous API, and not just fix the examples. + +* Explore non-exception based approach to error handling in `std::uuid::from_string` + + | SF | F | N | A | SA | + |---|---|---|---|---| + | 9 | 0 | 0 | 0 | 0 | + +Based on this feedback the following changes have been done in this version: +* `std::uuid` byte order is fixed +* removed container interface (iterators and `size()`) because, fundamentally, a uuid is a single entity, an identifier, and not a container of other things +* removed `basic_uuid_random_generator` default constructor +* added `uuid_time_generator` functor to generate variant 1 time-based uuids +* proper initialization for the pseudo-random generator engines in all examples +* removed `to_wstring()` and made `to_string()` a function template +* made `from_string()` a non-throwing function template returning `std::optional` +* added `is_valid_uuid()` a non-throwing function template that checks if a string contains a valid uuid +* removed the `std::wstring` overloaded call operator for `uuid_name_generator` and replaced with with function templates +* `uuid`s produced from names in different character sets or encodings are different (i.e. "jane" and L"jane") +* removed the class `uuid_error` +* footnote on the use of the name Microsoft + +### 1.4 P0959R3 + +P0959R2 was discussed by LEWGI in Kona with the following feedback: +* The random number generator is not random enough; may want to consult W23 - or not provide a default. +* Why `string` and `char*` instead of `string_view`? +* Some methods that can be `constexpr`/`noexcept` are not. +* Need more explanations about the choices of ordering and how the RFC works in that regard. +* Need to specify which algorithm the name generator uses. +* The uuid should be a `class` not a `struct`. +* The three-way comparison operator cannot be defaulted if the class doesn't have at least exposition only members. + +Based on this feedback and further considerations, the following changes have been done in this version: +* Added detailed explanation of the algorithms for generating uuids. +* `from_string()` and non-member `swap()` declared with `noexcept`. +* The `uuid` type is now defined as a class. +* Added an exposition-only member to hint and the possible internal representation of the uuid data. +* Added `uuid` constructors from arrays. +* Added implementation-specific constant uuids that can be used for generating name-based uuids. +* Added a new section (Open discussion) in this document to address questions/concerns from the committee. +* The global constants in the namespace `std` for generating name-based uuids are defined `inline` + +## II. Motivation + +Universally unique identifiers (*uuid*), also known as Globally Unique Identifiers (*guid*s), are commonly used in many types of applications to uniquely identify data. A standard uuid library would benefit developers that currently have to either use operating system specific APIs for creating new uuids or resort to 3rd party libraries, such as *boost::uuid*. + +UUIDs are 128-bit numbers that are for most practical purposes unique, without depending on a central registration authority for ensuring their uniqueness. Although the probability of UUID duplication exists, it is negligible. According to Wikipedia, "*for there to be a one in a billion chance of duplication, 103 trillion version 4 UUIDs must be generated.*" UUID is an Internet Engineering Task Force standard described by RFC 4122. + +The library proposed on this paper is a light one: it enables developers to generate random and name-based UUIDs, serialize and deserialize UUIDs to and from strings, validate UUIDs and other common operations. + +## III. Impact On the Standard + +This proposal is a pure library extension. It does not require changes to any standard classes, functions or headers. It does not require any changes in the core language, and it has been implemented in standard C++ as per ISO/IEC 14882:2017. The implementation is available at https://github.com/mariusbancila/stduuid. + +## IV. Design Decisions + +The proposed library, that should be available in a new header called `` in the namespace `std`, provides: +* a class called `uuid` that represents a universally unique identifier +* strongly type enums `uuid_variant` and `uuid_version` to represent the possible variant and version types of a UUID +* function objects that generate UUIDs, called generators: `basic_uuid_random_generator`, `uuid_random_generator`, `uuid_name_generator`, `uuid_time_generator` +* conversion functions from strings `from_string()` and to strings `std::to_string()`, as well as an overloaded `operator<<` for `std::basic_ostream` +* `std::swap()` overload for `uuid` +* `std::hash<>` specialization for `uuid` + +### Default constructor + +Creates a nil UUID that has all the bits set to 0 (i.e. `00000000-0000-0000-0000-000000000000`). + +```cpp +uuid empty; +auto empty = uuid{}; +``` + +### Iterators constructors + +The conversion constructor that takes two forward iterators constructs an `uuid` with the content of the range \[first, last). It requires the range to have exactly 16 elements, otherwise the behaviour is undefined. This constructor follows the conventions of other containers in the standard library. + +```cpp +std::array arr{{ + 0x47, 0x18, 0x38, 0x23, + 0x25, 0x74, + 0x4b, 0xfd, + 0xb4, 0x11, + 0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 +}}; +uuid id(std::begin(arr), std::end(arr)); +``` + +```cpp +uuid::value_type arr[16] = { + 0x47, 0x18, 0x38, 0x23, + 0x25, 0x74, + 0x4b, 0xfd, + 0xb4, 0x11, + 0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 }; +uuid id(std::begin(arr), std::end(arr)); +``` + +### Array constructors +The array constructors allow to create a `uuid` from an array or using direct initialization. +```cpp +uuid id{ {0x47, 0x18, 0x38, 0x23, + 0x25, 0x74, + 0x4b, 0xfd, + 0xb4, 0x11, + 0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 } }; + +assert(to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43"); +``` + +```cpp +uuid::value_type arr[16] = { + 0x47, 0x18, 0x38, 0x23, + 0x25, 0x74, + 0x4b, 0xfd, + 0xb4, 0x11, + 0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 }; +uuid id(arr); + +assert(to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43"); +``` + +### Span constructor + +The conversion constructor that takes a `std::span` and constructs a `uuid` from a contiguous sequence of 16 bytes. + +```cpp +std::array arr{ { + 0x47, 0x18, 0x38, 0x23, + 0x25, 0x74, + 0x4b, 0xfd, + 0xb4, 0x11, + 0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 +} }; + +std::span data(arr); + +uuid id{ data }; + +assert(to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43"); +``` + +### Nil + +A nil UUID is a special UUID that has all the bits set to 0. Its canonical textual representation is `00000000-0000-0000-0000-000000000000`. Member function `is_nil()` indicates whether the `uuid` has all the bits set to 0. A nil UUID is created by the default constructor or by parsing the strings `00000000-0000-0000-0000-000000000000` or `{00000000-0000-0000-0000-000000000000}`. + +```cpp +uuid id; +assert(id.is_nil()); + +std::optional id = uuid::from_string("00000000-0000-0000-0000-000000000000"); +assert(id.has_value() && id.value().is_nil()); +``` + +### `variant` and `version` + +Member functions `variant()` and `version()` allow checking the variant type of the uuid and, respectively, the version type. These are defined by two strongly typed enums called `uuid_variant` and `uuid_version`. + +```cpp +uuid id = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value(); +assert(id.version() == uuid_version::random_number_based); +assert(id.variant() == uuid_variant::rfc); +``` + +### Comparisons + +Although it does not make sense to check whether a UUID is less (or less or equal) then another UUID, the overloading of this operator for `uuid` is necessary in order to be able to store `uuid` values in containers such as `std::set` that by default use `operator <` to compare keys. Because operators `==` and `!=` are needed for checking whether two UUIDs are the same (a basic operation for an identifier type) the three-way comparison operator `<=>` is defined so that all comparison operators are provided. + +```cpp +std::array arr{ { + 0x47, 0x18, 0x38, 0x23, + 0x25, 0x74, + 0x4b, 0xfd, + 0xb4, 0x11, + 0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 +} }; + +uuid id1{ std::span{arr} }; +uuid id2 = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value(); +assert(id1 == id2); + +std::set ids{ + uuid{}, + uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value() +}; + +assert(ids.size() == 2); +assert(ids.find(uuid{}) != ids.end()); +``` + +### Span view +Member function `as_bytes()` converts the `uuid` into a view of its underlying bytes. +```cpp +std::array arr{ { + 0x47, 0x18, 0x38, 0x23, + 0x25, 0x74, + 0x4b, 0xfd, + 0xb4, 0x11, + 0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 + } }; + +uuid const id{ arr }; +assert(!id.is_nil()); + +auto view = id.as_bytes(); +assert(memcmp(view.data(), arr.data(), arr.size()) == 0); +``` + +### Swapping + +Both member and non-member `swap()` functions are available to perform the swapping of `uuid` values. + +```cpp +uuid empty; +uuid id = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value(); + +assert(empty.is_nil()); +assert(!id.is_nil()); + +std::swap(empty, id); + +assert(!empty.is_nil()); +assert(id.is_nil()); + +empty.swap(id); + +assert(empty.is_nil()); +assert(!id.is_nil()); +``` + +### String parsing + +Static overloaded member function template `from_string()` allows to create `uuid` instances from various strings. + +The input argument must have the form `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` or `{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}` where `x` is a hexadecimal digit. The return value is an `std::optional` that contains a valid `uuid` if the parsing completed successful. + +```cpp +auto id1 = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43"); +assert(id1.has_value()); + +auto id2 = uuid::from_string(L"{47183823-2574-4bfd-b411-99ed177d3e43}"); +assert(id2.has_value()); +``` + +The order of the bytes in the input string reflects directly into the internal representation of the UUID. That is, for an input string in the form `"aabbccdd-eeff-gghh-iijj-kkllmmnnoopp"` or `"{aabbccdd-eeff-gghh-iijj-kkllmmnnoopp}"` the internal byte order of the resulted UUID is `aa,bb,cc,dd,ee,ff,gg,hh,ii,jj,kk,ll,mm,nn,oo,pp`. + +### String conversion + +Non-member template function `to_string()` returns a string with the UUID formatted to the canonical textual representation `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`, where `x` is a lower case hexadecimal digit. + +```cpp +auto id = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43"); +assert(id.has_value()); +assert(to_string(id.value()) == "47183823-2574-4bfd-b411-99ed177d3e43"); +assert(to_string(id.value()) == L"47183823-2574-4bfd-b411-99ed177d3e43"); +``` + +The order of the internal UUID bytes reflects directly into the string bytes order. That is, for a UUID with the internal bytes in the form `aa,bb,cc,dd,ee,ff,gg,hh,ii,jj,kk,ll,mm,nn,oo,pp` the resulted string has the form `"aabbccdd-eeff-gghh-iijj-kkllmmnnoopp"`. + +### Hashing + +A `std::hash<>` specialization for `uuid` is provided in order to enable the use of `uuid`s in associative unordered containers such as `std::unordered_set`. + +```cpp +std::unordered_set ids{ + uuid{}, + uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value(), +}; + +assert(ids.size() == 2); +assert(ids.find(uuid{}) != ids.end()); +``` + +### Generating new uuids +Several function objects, called generators, are provided in order to create different versions of UUIDs. + +Examples for generating new UUIDs with the `basic_uuid_random_generator` class: +```cpp +{ + std::random_device rd; + auto seed_data = std::array {}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 engine(seq); + + basic_uuid_random_generator dgen{engine}; + auto id1 = dgen(); + assert(!id1.is_nil()); + assert(id1.size() == 16); + assert(id1.version() == uuid_version::random_number_based); + assert(id1.variant() == uuid_variant::rfc); +} + +{ + std::random_device rd; + auto seed_data = std::array {}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::ranlux48_base engine(seq); + + basic_uuid_random_generator dgen{engine}; + auto id1 = dgen(); + assert(!id1.is_nil()); + assert(id1.size() == 16); + assert(id1.version() == uuid_version::random_number_based); + assert(id1.variant() == uuid_variant::rfc); +} + +{ + std::random_device rd; + auto seed_data = std::array {}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + auto engine = std::make_unique(seq); + + basic_uuid_random_generator dgen(engine.get()); + auto id1 = dgen(); + assert(!id1.is_nil()); + assert(id1.size() == 16); + assert(id1.version() == uuid_version::random_number_based); + assert(id1.variant() == uuid_variant::rfc); +} +``` + +Examples for generating new UUIDs with the `uuid_random_generator` type alias: +```cpp +std::random_device rd; +auto seed_data = std::array {}; +std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); +std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); +std::mt19937 engine(seq); + +uuid const guid = uuid_random_generator{engine}(); +auto id1 = dgen(); +assert(!id1.is_nil()); +assert(id1.size() == 16); +assert(id1.version() == uuid_version::random_number_based); +assert(id1.variant() == uuid_variant::rfc); +``` + +Examples for genearting new UUIDs with the `uuid_name_generator` class: +```cpp +uuid_name_generator dgen(uuid::from_string("415ccc2b-f5cf-4ec1-b544-45132a518cc8").value()); +auto id1 = dgen("john"); +assert(!id1.is_nil()); +assert(id1.size() == 16); +assert(id1.version() == uuid_version::name_based_sha1); +assert(id1.variant() == uuid_variant::rfc); + +auto id2 = dgen("jane"); +assert(!id2.is_nil()); +assert(id2.size() == 16); +assert(id2.version() == uuid_version::name_based_sha1); +assert(id2.variant() == uuid_variant::rfc); + +auto id3 = dgen("jane"); +assert(!id3.is_nil()); +assert(id3.size() == 16); +assert(id3.version() == uuid_version::name_based_sha1); +assert(id3.variant() == uuid_variant::rfc); + +auto id4 = dgen(L"jane"); +assert(!id4.is_nil()); +assert(id4.size() == 16); +assert(id4.version() == uuid_version::name_based_sha1); +assert(id4.variant() == uuid_variant::rfc); + +assert(id1 != id2); +assert(id2 == id3); +assert(id3 != id4); +``` + +## V. Technical Specifications + +### Header +Add a new header called ``. + +### `uuid_variant` enum + +```cpp +namespace std { + enum class uuid_variant + { + ncs, + rfc, + microsoft, + future + }; +} +``` + +**Footnote**: Microsoft is a registered trademark of Microsoft Corporation. This information is given for the convenience of users of this document and does not constitute an endorsement by ISO or IEC of these products. + +### `uuid_version` enum + +```cpp +namespace std { + enum class uuid_version + { + none = 0, + time_based = 1, + dce_security = 2, + name_based_md5 = 3, + random_number_based = 4, + name_based_sha1 = 5 + }; +} +``` + +### `uuid` class + +```cpp +namespace std { + class uuid + { + public: + using value_type = uint8_t; + + constexpr uuid() noexcept = default; + constexpr uuid(value_type(&arr)[16]) noexcept; + constexpr uuid(std::array const & arr) noexcept; + constexpr explicit uuid(std::span bytes); + + template + constexpr explicit uuid(ForwardIterator first, ForwardIterator last); + + constexpr uuid_variant variant() const noexcept; + constexpr uuid_version version() const noexcept; + constexpr bool is_nil() const noexcept; + + constexpr void swap(uuid & other) noexcept; + + constexpr std::span as_bytes() const; + + constexpr std::strong_ordering operator<=>(uuid const&) const noexcept = default; + + template + static bool is_valid_uuid(CharT const * str) noexcept; + + template, + class Allocator = std::allocator> + static bool is_valid_uuid(std::basic_string const & str) noexcept; + + template + static uuid from_string(CharT const * str) noexcept; + + template, + class Allocator = std::allocator> + static uuid from_string(std::basic_string const & str) noexcept; + private: + template + friend std::basic_ostream & operator<<(std::basic_ostream &s, uuid const & id); + + value_type data[16]; // exposition-only + }; +} +``` + +### non-member functions + +```cpp +namespace std { + inline constexpr void swap(uuid & lhs, uuid & rhs) noexcept; + + template + std::basic_ostream & operator<<(std::basic_ostream &s, uuid const & id); + + template, + class Allocator = std::allocator> + inline std::basic_string to_string(uuid const & id); +} +``` + +### Constants +The following implementation-specific constant uuid values can be used for generating name-based uuids. +```cpp +namespace std { + inline constexpr uuid uuid_namespace_dns = /* implementation-specific */; + inline constexpr uuid uuid_namespace_url = /* implementation-specific */; + inline constexpr uuid uuid_namespace_oid = /* implementation-specific */; + inline constexpr uuid uuid_namespace_x500 = /* implementation-specific */; +} +``` + +### Generators +#### Random uuid generators +`basic_uuid_random_generator` is a class template for generating random or pseudo-random UUIDs (version 4, i.e. `uuid_version::random_number_based`). +The type template parameter represents a function object that implements both the [`RandomNumberEngine`](http://en.cppreference.com/w/cpp/concept/UniformRandomBitGenerator) and [`UniformRandomBitGenerator`](http://en.cppreference.com/w/cpp/concept/RandomNumberEngine) concepts. +`basic_uuid_random_generator` can be constructed with a reference or pointer to a an objects that satisfies the `UniformRandomNumberGenerator` requirements. +```cpp +namespace std { + template + class basic_uuid_random_generator + { + public: + using engine_type = UniformRandomNumberGenerator; + + explicit basic_uuid_random_generator(engine_type& gen); + explicit basic_uuid_random_generator(engine_type* gen); + + uuid operator()(); + }; +} +``` +A type alias `uuid_random_generator` is provided for convenience as `std::mt19937` is probably the preferred choice of a pseudo-random number generator engine in most cases. +```cpp +namespace std { + using uuid_random_generator = basic_uuid_random_generator; +} +``` + +The algorithm for generating random uuids is as follows: +* Set the two most significant bits (bits 6 and 7) of the `clock_seq_hi_and_reserved` to zero and one, respectively. +* Set the four most significant bits (bits 12 through 15) of the `time_hi_and_version` to the binary value 0100 (representing version 3 as defined in the section _VII. UUID format specification_). +* Set all the other bits to randomly (or pseudo-randomly) chosen values. + +#### Name-base uuid generator +`uuid_name_generator` is a function object that generates new UUIDs from a name and has to be initialized with another UUID. +```cpp +namespace std { + class uuid_name_generator + { + public: + explicit uuid_name_generator(uuid const& namespace_uuid) noexcept; + + template + uuid operator()(CharT const * name); + + template, + class Allocator = std::allocator> + uuid operator()(std::basic_string const & name); + }; +} +``` +This generator produces different uuids for the same text represented in different character sets or encodings. In order words, the uuids generated from "jane" and L"jane" are different. + +The algorithm for generating name-based uuids is as follows: +* Use a uuid as a namespace identifier for all uuids generated from names in that namespace +* Convert the name to a canonical sequence of octets (as defined by the standards or conventions of its name space); put the name space ID in network byte order. +* Compute the SHA-1 hash of the name space ID concatenated with the name. +* Copy the octects of the hash to the octets of the uuid as follows: + * octets 0 to 3 of the hash to octets 0 to 3 of `time_low field`, + * octets 4 and 5 of the hash to octets 0 and 1 of `time_mid`, + * octets 6 and 7 of the hash to octets 0 and 1 of `time_hi_and_version` + * octet 8 of the hash to `clock_seq_hi_and_reserved` + * octet 9 of the hash to `clock_seq_low` + * octets 10 to 15 of the hash to octets 0 to 5 of `node` +* Set the four most significant bits (bits 12 through 15) of the `time_hi_and_version` field to binary value 0101 (representing version 5 as defined in the section _VII. UUID format specification_). +* Set the two most significant bits (bits 6 and 7) of the `clock_seq_hi_and_reserved` to zero and one, respectively. +* Convert the resulting uuid to local byte order. + +#### Time-based uuid generator +`uuid_time_generator` is a function object that generates a time-based UUID as described in the RFC4122 document. +```cpp +namespace std { + class uuid_time_generator + { + public: + uuid_time_generator() noexcept; + + uuid operator()(); + }; +} +``` + +The generated uuid's parts are as follows: +* the timestamp is a 60-bit value, representing the number of 100 nanosecond intervals since 15 October 1582 00:00:000000000. +* the clock sequence is a 14-bit value, that is initially a high-quality pseudo-random value; when the previous value is known, it is simply incremented by one. +* the node identifier is an IEEE 802 MAC address (when multiple are available any could be used); if no such address is available, a pseudo-randomly generated value may be used, in which case the multicast bit (least significant bit of the first byte) is set to 1, this to avoid clashes with legitimate IEEE 802 addresses. + +The algorithm for generating time-based uuids is as follows: +* Consider the timestamp to be a 60-bit unsigned integer and the clock sequence to be a 14-bit unsigned integer. Sequentially number the bits in a field, starting with zero for the least significant bit. +* Determine the values for the UTC-based timestamp and clock sequence to be used in the UUID as a 60-bit count of 100-nanosecond intervals since 00:00:00.00, 15 October 1582. +* Copy the bits of the timestamp to the uuid bits as follows, using the same order of significance: + * bits 0 through 31 to the `time_low` field + * bits 32 through 47 to the `time_mid` field + * bits 48 through 59 to the 12 least significant bits (bits 0 through 11) of the `time_hi_and_version` field +* Copy the bits of the clock sequence to the uuid bits as follows, using the same order of significance: + * bits 0 through 7 to the `clock_seq_low` field + * bits 8 through 13 to the 6 least significant bits (bits 0 through 5) of the `clock_seq_hi_and_reserved` field +* Set the four most significant bits (bits 12 through 15) of the `time_hi_and_version` field to the binary value 0001 (representing version 1 as defined in the section _VII. UUID format specification_). +* Set the two most significant bits (bits 6 and 7) of the `clock_seq_hi_and_reserved` to zero and one, respectively. +* Set the `node` field to the 48-bit IEEE address in the same order of significance as the address. + +### Specialization +The template specializations of `std::hash` for the `uuid` class allow users to obtain hashes of UUIDs. +```cpp +namespace std { + template <> + struct hash + { + using argument_type = uuid; + using result_type = std::size_t; + + result_type operator()(argument_type const &uuid) const; + }; +} +``` + +## VI. Alternative ordering design +The comparison of UUIDs is not an operation that makes logical sense but it is required for using UUIDs as keys for containers such as `std::set` or `std::map`. The technical specification of the `uuid` class given in the previous section features the three-way operator `<=>` as member of the class. The C++ community, however, is divided on this particular aspect (with long discussions happening in the [ISO C++ proposals forum](https://groups.google.com/a/isocpp.org/forum/#!forum/std-proposals)) between those that want convenience and those that want rigour. Although the RFC 4122 document, as quoted in the next section, does specify rules for lexical equivalence, not everybody is happy with the definition of comparison operator `<`. + +The alternative put forward is to define non-member ordering functors. In this case, the library can define the following functors: +* `uuid_lexicographical_order` performs a lexicographic comparison (can provide compatibility with other systems) +* `uuid_fast_order` performs a memberwise comparison for efficiency. + +These could be used as the comparison function for containers such as `std::set` or `std::map`: +```cpp +std::map map; +``` + +```cpp +template> +using uuid_map = std::map; +``` + +In this case, the `uuid` class should be defined as follows: +```cpp +namespace std { + class uuid + { + public: + using value_type = uint8_t; + + constexpr uuid() noexcept = default; + constexpr uuid(value_type(&arr)[16]) noexcept; + constexpr uuid(std::array const & arr) noexcept; + constexpr explicit uuid(std::span bytes); + + template + constexpr explicit uuid(ForwardIterator first, ForwardIterator last); + + constexpr uuid_variant variant() const noexcept; + constexpr uuid_version version() const noexcept; + constexpr bool is_nil() const noexcept; + + constexpr void swap(uuid & other) noexcept; + + constexpr std::span as_bytes() const; + + template + static bool is_valid_uuid(CharT const * str) noexcept; + + template, + class Allocator = std::allocator> + static bool is_valid_uuid(std::basic_string const & str) noexcept; + + template + static uuid from_string(CharT const * str) noexcept; + + template, + class Allocator = std::allocator> + static uuid from_string(std::basic_string const & str) noexcept; + private: + template + friend std::basic_ostream & operator<<(std::basic_ostream &s, uuid const & id); + + value_type data[16]; // exposition-only + }; +} +``` + +In addition, the following must be added to the `` header: +```cpp +namespace std { + struct uuid_lexicographical_order { + constexpr bool operator()(uuid const&, uuid const&) const; + }; + + struct uuid_fast_order { + constexpr bool operator()(uuid const&, uuid const&) const; + }; +} +``` + +Should users require other types of comparison they can provide their own implementation and use them instead of the standard ones. + +## VII. UUID format specification +The content of this section is copied from the RFC 4122 document that describes the UUID standard. + +The UUID format is 16 octets; some bits of the eight octet variant field determine the layout of the UUID. That is, the interpretation of all other bits in the UUID depends on the setting of the bits in the variant field. The variant field consists of a variable number of the most significant bits of octet 8 of the UUID. The following table lists the contents of the variant field, where the letter "x" indicates a "don't-care" value. + +| Msb0 | Msb1 | Msb2 | Description | +| ---- | ---- | ---- | ----------- | +| 0 | x | x | Reserved, NCS backward compatibility. | +| 1 | 0 | x | The variant specified in this document. | +| 1 | 1 | 0 | Reserved, Microsoft Corporation backward compatibility. | +| 1 | 1 | 1 | Reserved for future definition. | + +Only UUIDs of the variant with the bit pattern 10x are considered in this document. All the other references to UUIDs in this document refer to this variant. For simplicity, we will call this the RFC variant UUID. + +The UUID record definition is defined only in terms of fields that are integral numbers of octets. The fields are presented with the most significant one first. + +| Field | Data Type | Octet number | Note | +| ----- | --------- | ------------ | ---- | +| `time_low` | unsigned 32 bit integer | 0-3 | The low field of the timestamp | +| `time_mid` | unsigned 16 bit integer | 4-5 | The middle field of the timestamp | +| `time_hi_and_version` | unsigned 16 bit integer | 6-7 | The high field of the timestamp multiplexed with the version number | +| `clock_seq_hi_and_reserved` | unsigned 8 bit integer | 8 | The high field of the clock sequence multiplexed with the variant | +| `clock_seq_low` | unsigned 8 bit integer | 9 | The low field of the clock sequence | +| `node` | unsigned 48 bit integer | 10-15 | The spatially unique node identifier | + +In the absence of explicit application or presentation protocol specification to the contrary, a UUID is encoded as a 128-bit object, as follows: + +The fields are encoded as 16 octets, with the sizes and order of the fields defined above, and with each field encoded with the Most Significant Byte first (known as network byte order). + +``` +0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| time_low | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| time_mid | time_hi_and_version | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +|clk_seq_hi_res | clk_seq_low | node (0-1) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| node (2-5) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +``` + +The version number is in the most significant 4 bits of the timestamp (bits 4 through 7 of the `time_hi_and_version` field). The following table lists the currently-defined versions for the RFC variant. + +| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description | +| ---- | ---- | ---- | ---- | ------- | ----------- | +| 0 | 0 | 0 | 1 | 1 | The time-based version specified in this document. | +| 0 | 0 | 1 | 0 | 2 | DCE Security version, with embedded POSIX UIDs. | +| 0 | 0 | 1 | 1 | 3 | The name-based version specified in this document that uses MD5 hashing. | +| 0 | 1 | 0 | 0 | 4 | The randomly or pseudo-randomly generated version specified in this document. | +| 0 | 1 | 0 | 1 | 5 | The name-based version specified in this document that uses SHA-1 hashing. | + +### Rules for Lexical Equivalence +Consider each field of the UUID to be an unsigned integer as shown in the table in the section above. Then, to compare a pair of UUIDs, arithmetically compare the corresponding fields from each UUID in order of significance and according to their data type. Two UUIDs are equal if and only if all the corresponding fields are equal. + +As an implementation note, equality comparison can be performed on many systems by doing the appropriate byte-order canonicalization, and then treating the two UUIDs as 128-bit unsigned integers. + +UUIDs, as defined in this document, can also be ordered lexicographically. For a pair of UUIDs, the first one follows the second if the most significant field in which the UUIDs differ is greater for the first UUID. The second precedes the first if the most significant field in which the UUIDs differ is greater for the second UUID. + +### VIII. Open discussion +The LEWGI in Kona have raised the following questions or concerns, which are answered below. + +#### Why `string` and `char*` instead of `string_view`? + +The reason for having these two overloads is because it should be possible to create uuids both from literals and objects. +```cpp +auto id1 = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43"); // [1] + +std::string str{ "47183823-2574-4bfd-b411-99ed177d3e43" }; +auto id2 = uuid::from_string(str); // [2] +``` +Because template argument deduction does not work, both [1] and [2] would produce compiler errors. Instead, it should be one of the following, neither being desirable. +```cpp +auto id1 = uuid::from_string( + std::string_view {"47183823-2574-4bfd-b411-99ed177d3e43"}); // [1] + +std::string str{ "47183823-2574-4bfd-b411-99ed177d3e43" }; +auto id2 = uuid::from_string(std::string_view {str}); // [2] +``` +or +```cpp +auto id1 = uuid::from_string>( + "47183823-2574-4bfd-b411-99ed177d3e43"); // [1] + +std::string str{ "47183823-2574-4bfd-b411-99ed177d3e43" }; +auto id2 = uuid::from_string>(str); // [2] +``` + +#### Need more explanations about the choices of ordering and how the RFC works in that regard. + +The RFC states the rules for lexical equivalence. These are mentioned in section VII, paragraph _Rules for Lexical Equivalence_ . They say that: +* to compare two UUIDs you must compare the fields they are composed of in the order of significance; two UUIDs are equal if all the fields are equal. +* a UUID follows another one if the most significant field in which the UUIDs differ is greater for the first UUID. + + +## IX. References + +* [1] Universally unique identifier, https://en.wikipedia.org/wiki/Universally_unique_identifier +* [2] A Universally Unique IDentifier (UUID) URN Namespace, https://tools.ietf.org/html/rfc4122 +* [3] Boost Uuid Library http://www.boost.org/doc/libs/1_65_1/libs/uuid/uuid.html +* [4] crossguid - Lightweight cross platform C++ GUID/UUID library, https://github.com/graeme-hill/crossguid diff --git a/src/deps/stduuid/README.md b/src/deps/stduuid/README.md new file mode 100644 index 0000000..3b3e66f --- /dev/null +++ b/src/deps/stduuid/README.md @@ -0,0 +1,274 @@ +# stduuid +A C++17 cross-platform single-header library implementation **for universally unique identifiers**, simply know as either UUID or GUID (mostly on Windows). A UUID is a 128-bit number used to uniquely identify information in computer systems, such as database table keys, COM interfaces, classes and type libraries, and many others. + +[![Build Status](https://travis-ci.org/mariusbancila/stduuid.svg?branch=master)](https://travis-ci.org/mariusbancila/stduuid) +[![Tests status](https://ci.appveyor.com/api/projects/status/0kw1n2s2xqxu5m62?svg=true&pendingText=tests%20-%20pending&failingText=tests%20-%20FAILED&passingText=tests%20-%20OK)](https://ci.appveyor.com/project/mariusbancila/stduuid) + +For information about UUID/GUIDs see: +* [Universally unique identifier](https://en.wikipedia.org/wiki/Universally_unique_identifier) +* [A Universally Unique IDentifier (UUID) URN Namespace](https://www.ietf.org/rfc/rfc4122.txt) + +## Library overview +Although the specification puts the uuid library in the `std` namespace, this implementation uses the namespace `uuids` for this purpose, in order to make the library usable without violating the restrictions imposed on the `std` namespace. The following types and utilities are available: + +Basic types: + +| Name | Description | +| ---- | ----------- | +| `uuid` | a class representing a UUID; this can be default constructed (a nil UUID), constructed from a range (defined by a pair of iterators), or from a `span`. | +| `uuid_variant` | a strongly type enum representing the type of a UUID | +| `uuid_version` | a strongly type enum representing the version of a UUID | + +Generators: + +| Name | Description | +| ---- | ----------- | +| `basic_uuid_random_generator` | a function object that generates version 4 UUIDs using a pseudo-random number generator engine. | +| `uuid_random_generator` | a `basic_uuid_random_generator` using the Marsenne Twister engine (`basic_uuid_random_generator`) | +| `uuid_name_generator` | a function object that generates version 5, name-based UUIDs using SHA1 hashing. | +| `uuid_system_generator` | a function object that generates new UUIDs using operating system resources (`CoCreateGuid` on Windows, `uuid_generate` on Linux, `CFUUIDCreate` on Mac)

**Note**: This is not part of the standard proposal. It is available only if the `UUID_SYSTEM_GENERATOR` macro is defined. | + +Utilities: + +| Name | Description | +| ---- | ----------- | +| `std::swap<>` | specialization of `swap` for `uuid` | +| `std::hash<>` | specialization of `hash` for `uuid` (necessary for storing UUIDs in unordered associative containers, such as `std::unordered_set`) | + +Constants: + +| Name | Description | +| ---- | ----------- | +| `uuid_namespace_dns` | Namespace ID for name-based uuids when name string is a fully-qualified domain name. | +| `uuid_namespace_url` | Namespace ID for name-based uuids when name string is a URL. | +| `uuid_namespace_oid` | Namespace ID for name-based uuids when mame string is an ISO OID (See https://oidref.com/, https://en.wikipedia.org/wiki/Object_identifier). | +| `uuid_namespace_x500` | Namespace ID for name-based uuids when name string is an X.500 DN, in DER or a text output format (See https://en.wikipedia.org/wiki/X.500, https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One). | + +Other: + +| Name | Description | +| ---- | ----------- | +| `operator==` and `operator!=` | for UUIDs comparison for equality/inequality | +| `operator<` | for comparing whether one UUIDs is less than another. Although this operation does not make much logical sense, it is necessary in order to store UUIDs in a std::set. | +| `operator<<` | to write a UUID to an output stream using the canonical textual representation. | +| `to_string()` | creates a string with the canonical textual representation of a UUID. | + +## Library history +This library is an implementation of the proposal [P0959](P0959.md). + +**As the proposal evolves based on the standard committee and the C++ community feedback, this library implementation will reflect those changes.** + +See the revision history of the proposal for history of changes. + +## Using the library +The following is a list of examples for using the library: +* Creating a nil UUID + + ```cpp + uuid empty; + assert(empty.is_nil()); + ``` + +* Creating a new UUID + + ```cpp + uuid const id = uuids::uuid_system_generator{}(); + assert(!id.is_nil()); + assert(id.version() == uuids::uuid_version::random_number_based); + assert(id.variant() == uuids::uuid_variant::rfc); + ``` + +* Creating a new UUID with a default random generator + + ```cpp + std::random_device rd; + auto seed_data = std::array {}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 generator(seq); + uuids::uuid_random_generator gen{generator}; + + uuid const id = gen(); + assert(!id.is_nil()); + assert(id.as_bytes().size() == 16); + assert(id.version() == uuids::uuid_version::random_number_based); + assert(id.variant() == uuids::uuid_variant::rfc); + ``` + +* Creating a new UUID with a particular random generator + + ```cpp + std::random_device rd; + auto seed_data = std::array {}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::ranlux48_base generator(seq); + + uuids::basic_uuid_random_generator gen(&generator); + uuid const id = gen(); + assert(!id.is_nil()); + assert(id.as_bytes().size() == 16); + assert(id.version() == uuids::uuid_version::random_number_based); + assert(id.variant() == uuids::uuid_variant::rfc); + ``` + +* Creating a new UUID with the name generator + + ```cpp + uuids::uuid_name_generator gen(uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value()); + uuid const id = gen("john"); + + assert(!id.is_nil()); + assert(id.version() == uuids::uuid_version::name_based_sha1); + assert(id.variant() == uuids::uuid_variant::rfc); + ``` + +* Create a UUID from a string + + ```cpp + auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s; + auto id = uuids::uuid::from_string(str); + assert(id.has_value()); + assert(uuids::to_string(id.value()) == str); + + // or + + auto str = L"47183823-2574-4bfd-b411-99ed177d3e43"s; + uuid id = uuids::uuid::from_string(str).value(); + assert(uuids::to_string(id) == str); + ``` + +* Creating a UUID from a sequence of 16 bytes + + ```cpp + std::array arr{{ + 0x47, 0x18, 0x38, 0x23, + 0x25, 0x74, + 0x4b, 0xfd, + 0xb4, 0x11, + 0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43}}; + uuid id(arr); + + assert(uuids::to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43"); + + // or + + uuids::uuid::value_type arr[16] = { + 0x47, 0x18, 0x38, 0x23, + 0x25, 0x74, + 0x4b, 0xfd, + 0xb4, 0x11, + 0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 }; + uuid id(std::begin(arr), std::end(arr)); + assert(uuids::to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43"); + + // or + + uuids::uuid id{{ + 0x47, 0x18, 0x38, 0x23, + 0x25, 0x74, + 0x4b, 0xfd, + 0xb4, 0x11, + 0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43}}; + + assert(uuids::to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43"); + ``` + +* Comparing UUIDs + + ```cpp + uuid empty; + uuid id = uuids::uuid_system_generator{}(); + assert(empty == empty); + assert(id == id); + assert(empty != id); + ``` + +* Swapping UUIDs + + ```cpp + uuid empty; + uuid id = uuids::uuid_system_generator{}(); + + assert(empty.is_nil()); + assert(!id.is_nil()); + + std::swap(empty, id); + + assert(!empty.is_nil()); + assert(id.is_nil()); + + empty.swap(id); + + assert(empty.is_nil()); + assert(!id.is_nil()); + ``` + +* Converting to string + + ```cpp + uuid empty; + assert(uuids::to_string(empty) == "00000000-0000-0000-0000-000000000000"); + assert(uuids::to_string(empty) == L"00000000-0000-0000-0000-000000000000"); + ``` + +* Using with an orderered associative container + + ```cpp + std::random_device rd; + auto seed_data = std::array {}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 engine(seq); + uuids::uuid_random_generator gen(&engine); + + std::set ids{uuid{}, gen(), gen(), gen(), gen()}; + + assert(ids.size() == 5); + assert(ids.find(uuid{}) != ids.end()); + ``` + +* Using in an unordered associative container + + ```cpp + std::random_device rd; + auto seed_data = std::array {}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 engine(seq); + uuids::uuid_random_generator gen(&engine); + + std::unordered_set ids{uuid{}, gen(), gen(), gen(), gen()}; + + assert(ids.size() == 5); + assert(ids.find(uuid{}) != ids.end()); + ``` + +* Hashing UUIDs + + ```cpp + using namespace std::string_literals; + auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s; + uuid id = uuids::uuid::from_string(str).value(); + + auto h1 = std::hash{}; + auto h2 = std::hash{}; + assert(h1(str) == h2(id)); + ``` + +## Support +The library is supported on all major operating systems: Windows, Linux and Mac OS. + +## Dependencies +Because no major compiler supports `std::span` yet the [Microsoft Guidelines Support Library](https://github.com/Microsoft/GSL) (aka GSL) is used for its span implementation (from which the standard version was defined). + +## Testing +A testing project is available in the sources. To build and execute the tests do the following: +* Clone or download this repository +* Create a `build` directory in the root directory of the sources +* Run the command `cmake ..` from the `build` directory; if you do not have CMake you must install it first. +* Build the project created in the previous step +* Run the executable. + +## Credits +The SHA1 implementation is based on the [TinySHA1](https://github.com/mohaps/TinySHA1) library. diff --git a/src/deps/stduuid/appveyor.yml b/src/deps/stduuid/appveyor.yml new file mode 100644 index 0000000..458dda3 --- /dev/null +++ b/src/deps/stduuid/appveyor.yml @@ -0,0 +1,28 @@ +version: '{build}' + +environment: + matrix: + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + platform: x86 + FLAGS: "" + GENERATOR: Visual Studio 15 2017 + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + platform: x64 + FLAGS: "" + GENERATOR: Visual Studio 15 2017 + +init: + - cmake --version + - msbuild /version + +before_build: + - mkdir build + - cd build + - cmake .. -G "%GENERATOR%" -DBUILD_TESTS=ON -DCMAKE_CXX_FLAGS="%FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin" + +build_script: + - cmake --build . --config Release + +test_script: + - ctest -C Release -V -j diff --git a/src/deps/stduuid/catch/catch.hpp b/src/deps/stduuid/catch/catch.hpp new file mode 100644 index 0000000..2a2d77a --- /dev/null +++ b/src/deps/stduuid/catch/catch.hpp @@ -0,0 +1,17877 @@ +/* + * Catch v2.13.3 + * Generated: 2020-10-31 18:20:31.045274 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * 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 CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 13 +#define CATCH_VERSION_PATCH 3 + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// 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 push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ + // 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 +# define CLARA_CONFIG_MAIN +# endif +#endif + +// start catch_user_interfaces.h + +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h + +// start catch_common.h + +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler +// The following features are defined: +// +// 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_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. + +#ifdef __cplusplus + +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +# define CATCH_CPP14_OR_GREATER +# endif + +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +// 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) && !defined(__CUDACC__) +# 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__) && !defined(__CUDACC__) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ +# endif + +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) + +# 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__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#endif + +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# 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__ + +// 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__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#if defined(_MSC_VER) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) + +// 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 + +//////////////////////////////////////////////////////////////////////////////// +// 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 + +//////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// +// 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 + +//////////////////////////////////////////////////////////////////////////////// + +// 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(_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) + # include + # if __cpp_lib_byte > 0 + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif + # 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_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_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_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 +#endif +#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 + +// 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_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) +#endif + +#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 +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#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 CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; + + protected: + NonCopyable(); + virtual ~NonCopyable(); + }; + + struct SourceLineInfo { + + 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; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // 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+() const; + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) + +// end catch_common.h +namespace Catch { + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#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 + +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h + +// start catch_interfaces_testcase.h + +#include + +namespace Catch { + + class TestSpec; + + struct ITestInvoker { + virtual void invoke () const = 0; + virtual ~ITestInvoker(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + 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, _3, _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