external UUID implementation for asset tracking
This commit is contained in:
parent
e25625998c
commit
1c5b74454f
29 changed files with 26082 additions and 0 deletions
37
src/deps/stduuid/.gitignore
vendored
Normal file
37
src/deps/stduuid/.gitignore
vendored
Normal file
|
@ -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
|
25
src/deps/stduuid/.travis.yml
Normal file
25
src/deps/stduuid/.travis.yml
Normal file
|
@ -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 .
|
||||||
|
|
67
src/deps/stduuid/CMakeLists.txt
Normal file
67
src/deps/stduuid/CMakeLists.txt
Normal file
|
@ -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
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||||
|
$<INSTALL_INTERFACE:include>)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/gsl>
|
||||||
|
$<INSTALL_INTERFACE:include/gsl>)
|
||||||
|
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 ()
|
21
src/deps/stduuid/LICENSE
Normal file
21
src/deps/stduuid/LICENSE
Normal file
|
@ -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.
|
857
src/deps/stduuid/P0959.md
Normal file
857
src/deps/stduuid/P0959.md
Normal file
|
@ -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<std::byte, 16>`.
|
||||||
|
* 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<std::uuid>`
|
||||||
|
* 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 `<uuid>` 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<T>`, `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<uuid::value_type, 16> 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<uuid::value_type, 16> arr{ {
|
||||||
|
0x47, 0x18, 0x38, 0x23,
|
||||||
|
0x25, 0x74,
|
||||||
|
0x4b, 0xfd,
|
||||||
|
0xb4, 0x11,
|
||||||
|
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43
|
||||||
|
} };
|
||||||
|
|
||||||
|
std::span<uuid::value_type, 16> 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<uuid> 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<uuid::value_type, 16> arr{ {
|
||||||
|
0x47, 0x18, 0x38, 0x23,
|
||||||
|
0x25, 0x74,
|
||||||
|
0x4b, 0xfd,
|
||||||
|
0xb4, 0x11,
|
||||||
|
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43
|
||||||
|
} };
|
||||||
|
|
||||||
|
uuid id1{ std::span<uuid::value_type, 16>{arr} };
|
||||||
|
uuid id2 = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value();
|
||||||
|
assert(id1 == id2);
|
||||||
|
|
||||||
|
std::set<std::uuid> 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<uuids::uuid::value_type, 16> 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<uuid>` 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<wchar_t>(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<uuid> 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<int, std::mt19937::state_size> {};
|
||||||
|
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<std::mt19937> 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<int, 6> {};
|
||||||
|
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<std::ranlux48_base> 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<int, std::mt19937::state_size> {};
|
||||||
|
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<std::mt19937>(seq);
|
||||||
|
|
||||||
|
basic_uuid_random_generator<std::mt19937> 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<int, std::mt19937::state_size> {};
|
||||||
|
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>`.
|
||||||
|
|
||||||
|
### `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<value_type, 16> const & arr) noexcept;
|
||||||
|
constexpr explicit uuid(std::span<value_type, 16> bytes);
|
||||||
|
|
||||||
|
template<typename ForwardIterator>
|
||||||
|
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<std::byte const, 16> as_bytes() const;
|
||||||
|
|
||||||
|
constexpr std::strong_ordering operator<=>(uuid const&) const noexcept = default;
|
||||||
|
|
||||||
|
template<class CharT = char>
|
||||||
|
static bool is_valid_uuid(CharT const * str) noexcept;
|
||||||
|
|
||||||
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
static bool is_valid_uuid(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
|
||||||
|
|
||||||
|
template<class CharT = char>
|
||||||
|
static uuid from_string(CharT const * str) noexcept;
|
||||||
|
|
||||||
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
static uuid from_string(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
|
||||||
|
private:
|
||||||
|
template <class Elem, class Traits>
|
||||||
|
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &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 <class Elem, class Traits>
|
||||||
|
std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
|
||||||
|
|
||||||
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
inline std::basic_string<CharT, Traits, Allocator> 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<T>` 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 <typename UniformRandomNumberGenerator>
|
||||||
|
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<std::mt19937>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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<class CharT = char>
|
||||||
|
uuid operator()(CharT const * name);
|
||||||
|
|
||||||
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
uuid operator()(std::basic_string<CharT, Traits, Allocator> 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<uuid>
|
||||||
|
{
|
||||||
|
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<std::uuid, Value, std::uuid_fast_order> map;
|
||||||
|
```
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<typename Value, typename Allocator = std::allocator<T>>
|
||||||
|
using uuid_map = std::map<std::uuid, Value, std::uuid_lexicographical_order, Allocator>;
|
||||||
|
```
|
||||||
|
|
||||||
|
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<value_type, 16> const & arr) noexcept;
|
||||||
|
constexpr explicit uuid(std::span<value_type, 16> bytes);
|
||||||
|
|
||||||
|
template<typename ForwardIterator>
|
||||||
|
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<std::byte const, 16> as_bytes() const;
|
||||||
|
|
||||||
|
template<class CharT = char>
|
||||||
|
static bool is_valid_uuid(CharT const * str) noexcept;
|
||||||
|
|
||||||
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
static bool is_valid_uuid(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
|
||||||
|
|
||||||
|
template<class CharT = char>
|
||||||
|
static uuid from_string(CharT const * str) noexcept;
|
||||||
|
|
||||||
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
static uuid from_string(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
|
||||||
|
private:
|
||||||
|
template <class Elem, class Traits>
|
||||||
|
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
|
||||||
|
|
||||||
|
value_type data[16]; // exposition-only
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In addition, the following must be added to the `<uuid>` 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<char, std::char_traits<char>>(
|
||||||
|
"47183823-2574-4bfd-b411-99ed177d3e43"); // [1]
|
||||||
|
|
||||||
|
std::string str{ "47183823-2574-4bfd-b411-99ed177d3e43" };
|
||||||
|
auto id2 = uuid::from_string<char, std::char_traits<char>>(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
|
274
src/deps/stduuid/README.md
Normal file
274
src/deps/stduuid/README.md
Normal file
|
@ -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.
|
||||||
|
|
||||||
|
[](https://travis-ci.org/mariusbancila/stduuid)
|
||||||
|
[](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<std::mt19937>`) |
|
||||||
|
| `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) <br><br> **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<int, std::mt19937::state_size> {};
|
||||||
|
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<int, 6> {};
|
||||||
|
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<std::ranlux48_base> 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<wchar_t>(id) == str);
|
||||||
|
```
|
||||||
|
|
||||||
|
* Creating a UUID from a sequence of 16 bytes
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::array<uuids::uuid::value_type, 16> 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<wchar_t>(empty) == L"00000000-0000-0000-0000-000000000000");
|
||||||
|
```
|
||||||
|
|
||||||
|
* Using with an orderered associative container
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::random_device rd;
|
||||||
|
auto seed_data = std::array<int, std::mt19937::state_size> {};
|
||||||
|
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<uuids::uuid> 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<int, std::mt19937::state_size> {};
|
||||||
|
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<uuids::uuid> 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<std::string>{};
|
||||||
|
auto h2 = std::hash<uuid>{};
|
||||||
|
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.
|
28
src/deps/stduuid/appveyor.yml
Normal file
28
src/deps/stduuid/appveyor.yml
Normal file
|
@ -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
|
17877
src/deps/stduuid/catch/catch.hpp
Normal file
17877
src/deps/stduuid/catch/catch.hpp
Normal file
File diff suppressed because it is too large
Load diff
62
src/deps/stduuid/catch/catch_reporter_automake.hpp
Normal file
62
src/deps/stduuid/catch/catch_reporter_automake.hpp
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Created by Justin R. Wilson on 2/19/2017.
|
||||||
|
* Copyright 2017 Justin R. Wilson. 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_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
|
||||||
|
#define TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
|
||||||
|
|
||||||
|
// Don't #include any Catch headers here - we can assume they are already
|
||||||
|
// included before this header.
|
||||||
|
// This is not good practice in general but is necessary in this case so this
|
||||||
|
// file can be distributed as a single header that works with the main
|
||||||
|
// Catch single header.
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct AutomakeReporter : StreamingReporterBase<AutomakeReporter> {
|
||||||
|
AutomakeReporter( ReporterConfig const& _config )
|
||||||
|
: StreamingReporterBase( _config )
|
||||||
|
{}
|
||||||
|
|
||||||
|
~AutomakeReporter() override;
|
||||||
|
|
||||||
|
static std::string getDescription() {
|
||||||
|
return "Reports test results in the format of Automake .trs files";
|
||||||
|
}
|
||||||
|
|
||||||
|
void assertionStarting( AssertionInfo const& ) override {}
|
||||||
|
|
||||||
|
bool assertionEnded( AssertionStats const& /*_assertionStats*/ ) override { return true; }
|
||||||
|
|
||||||
|
void testCaseEnded( TestCaseStats const& _testCaseStats ) override {
|
||||||
|
// Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR.
|
||||||
|
stream << ":test-result: ";
|
||||||
|
if (_testCaseStats.totals.assertions.allPassed()) {
|
||||||
|
stream << "PASS";
|
||||||
|
} else if (_testCaseStats.totals.assertions.allOk()) {
|
||||||
|
stream << "XFAIL";
|
||||||
|
} else {
|
||||||
|
stream << "FAIL";
|
||||||
|
}
|
||||||
|
stream << ' ' << _testCaseStats.testInfo.name << '\n';
|
||||||
|
StreamingReporterBase::testCaseEnded( _testCaseStats );
|
||||||
|
}
|
||||||
|
|
||||||
|
void skipTest( TestCaseInfo const& testInfo ) override {
|
||||||
|
stream << ":test-result: SKIP " << testInfo.name << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CATCH_IMPL
|
||||||
|
AutomakeReporter::~AutomakeReporter() {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CATCH_REGISTER_REPORTER( "automake", AutomakeReporter)
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
|
255
src/deps/stduuid/catch/catch_reporter_tap.hpp
Normal file
255
src/deps/stduuid/catch/catch_reporter_tap.hpp
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
/*
|
||||||
|
* Created by Colton Wolkins on 2015-08-15.
|
||||||
|
* Copyright 2015 Martin Moene. 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_CATCH_REPORTER_TAP_HPP_INCLUDED
|
||||||
|
#define TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
// Don't #include any Catch headers here - we can assume they are already
|
||||||
|
// included before this header.
|
||||||
|
// This is not good practice in general but is necessary in this case so this
|
||||||
|
// file can be distributed as a single header that works with the main
|
||||||
|
// Catch single header.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct TAPReporter : StreamingReporterBase<TAPReporter> {
|
||||||
|
|
||||||
|
using StreamingReporterBase::StreamingReporterBase;
|
||||||
|
|
||||||
|
~TAPReporter() override;
|
||||||
|
|
||||||
|
static std::string getDescription() {
|
||||||
|
return "Reports test results in TAP format, suitable for test harnesses";
|
||||||
|
}
|
||||||
|
|
||||||
|
ReporterPreferences getPreferences() const override {
|
||||||
|
ReporterPreferences prefs;
|
||||||
|
prefs.shouldRedirectStdOut = false;
|
||||||
|
return prefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void noMatchingTestCases( std::string const& spec ) override {
|
||||||
|
stream << "# No test cases matched '" << spec << "'" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void assertionStarting( AssertionInfo const& ) override {}
|
||||||
|
|
||||||
|
bool assertionEnded( AssertionStats const& _assertionStats ) override {
|
||||||
|
++counter;
|
||||||
|
|
||||||
|
AssertionPrinter printer( stream, _assertionStats, counter );
|
||||||
|
printer.print();
|
||||||
|
stream << " # " << currentTestCaseInfo->name ;
|
||||||
|
|
||||||
|
stream << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testRunEnded( TestRunStats const& _testRunStats ) override {
|
||||||
|
printTotals( _testRunStats.totals );
|
||||||
|
stream << "\n" << std::endl;
|
||||||
|
StreamingReporterBase::testRunEnded( _testRunStats );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::size_t counter = 0;
|
||||||
|
class AssertionPrinter {
|
||||||
|
public:
|
||||||
|
AssertionPrinter& operator= ( AssertionPrinter const& ) = delete;
|
||||||
|
AssertionPrinter( AssertionPrinter const& ) = delete;
|
||||||
|
AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, std::size_t _counter )
|
||||||
|
: stream( _stream )
|
||||||
|
, result( _stats.assertionResult )
|
||||||
|
, messages( _stats.infoMessages )
|
||||||
|
, itMessage( _stats.infoMessages.begin() )
|
||||||
|
, printInfoMessages( true )
|
||||||
|
, counter(_counter)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void print() {
|
||||||
|
itMessage = messages.begin();
|
||||||
|
|
||||||
|
switch( result.getResultType() ) {
|
||||||
|
case ResultWas::Ok:
|
||||||
|
printResultType( passedString() );
|
||||||
|
printOriginalExpression();
|
||||||
|
printReconstructedExpression();
|
||||||
|
if ( ! result.hasExpression() )
|
||||||
|
printRemainingMessages( Colour::None );
|
||||||
|
else
|
||||||
|
printRemainingMessages();
|
||||||
|
break;
|
||||||
|
case ResultWas::ExpressionFailed:
|
||||||
|
if (result.isOk()) {
|
||||||
|
printResultType(passedString());
|
||||||
|
} else {
|
||||||
|
printResultType(failedString());
|
||||||
|
}
|
||||||
|
printOriginalExpression();
|
||||||
|
printReconstructedExpression();
|
||||||
|
if (result.isOk()) {
|
||||||
|
printIssue(" # TODO");
|
||||||
|
}
|
||||||
|
printRemainingMessages();
|
||||||
|
break;
|
||||||
|
case ResultWas::ThrewException:
|
||||||
|
printResultType( failedString() );
|
||||||
|
printIssue( "unexpected exception with message:" );
|
||||||
|
printMessage();
|
||||||
|
printExpressionWas();
|
||||||
|
printRemainingMessages();
|
||||||
|
break;
|
||||||
|
case ResultWas::FatalErrorCondition:
|
||||||
|
printResultType( failedString() );
|
||||||
|
printIssue( "fatal error condition with message:" );
|
||||||
|
printMessage();
|
||||||
|
printExpressionWas();
|
||||||
|
printRemainingMessages();
|
||||||
|
break;
|
||||||
|
case ResultWas::DidntThrowException:
|
||||||
|
printResultType( failedString() );
|
||||||
|
printIssue( "expected exception, got none" );
|
||||||
|
printExpressionWas();
|
||||||
|
printRemainingMessages();
|
||||||
|
break;
|
||||||
|
case ResultWas::Info:
|
||||||
|
printResultType( "info" );
|
||||||
|
printMessage();
|
||||||
|
printRemainingMessages();
|
||||||
|
break;
|
||||||
|
case ResultWas::Warning:
|
||||||
|
printResultType( "warning" );
|
||||||
|
printMessage();
|
||||||
|
printRemainingMessages();
|
||||||
|
break;
|
||||||
|
case ResultWas::ExplicitFailure:
|
||||||
|
printResultType( failedString() );
|
||||||
|
printIssue( "explicitly" );
|
||||||
|
printRemainingMessages( Colour::None );
|
||||||
|
break;
|
||||||
|
// These cases are here to prevent compiler warnings
|
||||||
|
case ResultWas::Unknown:
|
||||||
|
case ResultWas::FailureBit:
|
||||||
|
case ResultWas::Exception:
|
||||||
|
printResultType( "** internal error **" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Colour::Code dimColour() { return Colour::FileName; }
|
||||||
|
|
||||||
|
static const char* failedString() { return "not ok"; }
|
||||||
|
static const char* passedString() { return "ok"; }
|
||||||
|
|
||||||
|
void printSourceInfo() const {
|
||||||
|
Colour colourGuard( dimColour() );
|
||||||
|
stream << result.getSourceInfo() << ":";
|
||||||
|
}
|
||||||
|
|
||||||
|
void printResultType( std::string const& passOrFail ) const {
|
||||||
|
if( !passOrFail.empty() ) {
|
||||||
|
stream << passOrFail << ' ' << counter << " -";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printIssue( std::string const& issue ) const {
|
||||||
|
stream << " " << issue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printExpressionWas() {
|
||||||
|
if( result.hasExpression() ) {
|
||||||
|
stream << ";";
|
||||||
|
{
|
||||||
|
Colour colour( dimColour() );
|
||||||
|
stream << " expression was:";
|
||||||
|
}
|
||||||
|
printOriginalExpression();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printOriginalExpression() const {
|
||||||
|
if( result.hasExpression() ) {
|
||||||
|
stream << " " << result.getExpression();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printReconstructedExpression() const {
|
||||||
|
if( result.hasExpandedExpression() ) {
|
||||||
|
{
|
||||||
|
Colour colour( dimColour() );
|
||||||
|
stream << " for: ";
|
||||||
|
}
|
||||||
|
std::string expr = result.getExpandedExpression();
|
||||||
|
std::replace( expr.begin(), expr.end(), '\n', ' ');
|
||||||
|
stream << expr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printMessage() {
|
||||||
|
if ( itMessage != messages.end() ) {
|
||||||
|
stream << " '" << itMessage->message << "'";
|
||||||
|
++itMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printRemainingMessages( Colour::Code colour = dimColour() ) {
|
||||||
|
if (itMessage == messages.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// using messages.end() directly (or auto) yields compilation error:
|
||||||
|
std::vector<MessageInfo>::const_iterator itEnd = messages.end();
|
||||||
|
const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
|
||||||
|
|
||||||
|
{
|
||||||
|
Colour colourGuard( colour );
|
||||||
|
stream << " with " << pluralise( N, "message" ) << ":";
|
||||||
|
}
|
||||||
|
|
||||||
|
for(; itMessage != itEnd; ) {
|
||||||
|
// If this assertion is a warning ignore any INFO messages
|
||||||
|
if( printInfoMessages || itMessage->type != ResultWas::Info ) {
|
||||||
|
stream << " '" << itMessage->message << "'";
|
||||||
|
if ( ++itMessage != itEnd ) {
|
||||||
|
Colour colourGuard( dimColour() );
|
||||||
|
stream << " and";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::ostream& stream;
|
||||||
|
AssertionResult const& result;
|
||||||
|
std::vector<MessageInfo> messages;
|
||||||
|
std::vector<MessageInfo>::const_iterator itMessage;
|
||||||
|
bool printInfoMessages;
|
||||||
|
std::size_t counter;
|
||||||
|
};
|
||||||
|
|
||||||
|
void printTotals( const Totals& totals ) const {
|
||||||
|
if( totals.testCases.total() == 0 ) {
|
||||||
|
stream << "1..0 # Skipped: No tests ran.";
|
||||||
|
} else {
|
||||||
|
stream << "1.." << counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CATCH_IMPL
|
||||||
|
TAPReporter::~TAPReporter() {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CATCH_REGISTER_REPORTER( "tap", TAPReporter )
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED
|
220
src/deps/stduuid/catch/catch_reporter_teamcity.hpp
Normal file
220
src/deps/stduuid/catch/catch_reporter_teamcity.hpp
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
/*
|
||||||
|
* Created by Phil Nash on 19th December 2014
|
||||||
|
* Copyright 2014 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_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
|
||||||
|
#define TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
|
||||||
|
|
||||||
|
// Don't #include any Catch headers here - we can assume they are already
|
||||||
|
// included before this header.
|
||||||
|
// This is not good practice in general but is necessary in this case so this
|
||||||
|
// file can be distributed as a single header that works with the main
|
||||||
|
// Catch single header.
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wpadded"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct TeamCityReporter : StreamingReporterBase<TeamCityReporter> {
|
||||||
|
TeamCityReporter( ReporterConfig const& _config )
|
||||||
|
: StreamingReporterBase( _config )
|
||||||
|
{
|
||||||
|
m_reporterPrefs.shouldRedirectStdOut = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string escape( std::string const& str ) {
|
||||||
|
std::string escaped = str;
|
||||||
|
replaceInPlace( escaped, "|", "||" );
|
||||||
|
replaceInPlace( escaped, "'", "|'" );
|
||||||
|
replaceInPlace( escaped, "\n", "|n" );
|
||||||
|
replaceInPlace( escaped, "\r", "|r" );
|
||||||
|
replaceInPlace( escaped, "[", "|[" );
|
||||||
|
replaceInPlace( escaped, "]", "|]" );
|
||||||
|
return escaped;
|
||||||
|
}
|
||||||
|
~TeamCityReporter() override;
|
||||||
|
|
||||||
|
static std::string getDescription() {
|
||||||
|
return "Reports test results as TeamCity service messages";
|
||||||
|
}
|
||||||
|
|
||||||
|
void skipTest( TestCaseInfo const& /* testInfo */ ) override {
|
||||||
|
}
|
||||||
|
|
||||||
|
void noMatchingTestCases( std::string const& /* spec */ ) override {}
|
||||||
|
|
||||||
|
void testGroupStarting( GroupInfo const& groupInfo ) override {
|
||||||
|
StreamingReporterBase::testGroupStarting( groupInfo );
|
||||||
|
stream << "##teamcity[testSuiteStarted name='"
|
||||||
|
<< escape( groupInfo.name ) << "']\n";
|
||||||
|
}
|
||||||
|
void testGroupEnded( TestGroupStats const& testGroupStats ) override {
|
||||||
|
StreamingReporterBase::testGroupEnded( testGroupStats );
|
||||||
|
stream << "##teamcity[testSuiteFinished name='"
|
||||||
|
<< escape( testGroupStats.groupInfo.name ) << "']\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void assertionStarting( AssertionInfo const& ) override {}
|
||||||
|
|
||||||
|
bool assertionEnded( AssertionStats const& assertionStats ) override {
|
||||||
|
AssertionResult const& result = assertionStats.assertionResult;
|
||||||
|
if( !result.isOk() ) {
|
||||||
|
|
||||||
|
ReusableStringStream msg;
|
||||||
|
if( !m_headerPrintedForThisSection )
|
||||||
|
printSectionHeader( msg.get() );
|
||||||
|
m_headerPrintedForThisSection = true;
|
||||||
|
|
||||||
|
msg << result.getSourceInfo() << "\n";
|
||||||
|
|
||||||
|
switch( result.getResultType() ) {
|
||||||
|
case ResultWas::ExpressionFailed:
|
||||||
|
msg << "expression failed";
|
||||||
|
break;
|
||||||
|
case ResultWas::ThrewException:
|
||||||
|
msg << "unexpected exception";
|
||||||
|
break;
|
||||||
|
case ResultWas::FatalErrorCondition:
|
||||||
|
msg << "fatal error condition";
|
||||||
|
break;
|
||||||
|
case ResultWas::DidntThrowException:
|
||||||
|
msg << "no exception was thrown where one was expected";
|
||||||
|
break;
|
||||||
|
case ResultWas::ExplicitFailure:
|
||||||
|
msg << "explicit failure";
|
||||||
|
break;
|
||||||
|
|
||||||
|
// We shouldn't get here because of the isOk() test
|
||||||
|
case ResultWas::Ok:
|
||||||
|
case ResultWas::Info:
|
||||||
|
case ResultWas::Warning:
|
||||||
|
throw std::domain_error( "Internal error in TeamCity reporter" );
|
||||||
|
// These cases are here to prevent compiler warnings
|
||||||
|
case ResultWas::Unknown:
|
||||||
|
case ResultWas::FailureBit:
|
||||||
|
case ResultWas::Exception:
|
||||||
|
throw std::domain_error( "Not implemented" );
|
||||||
|
}
|
||||||
|
if( assertionStats.infoMessages.size() == 1 )
|
||||||
|
msg << " with message:";
|
||||||
|
if( assertionStats.infoMessages.size() > 1 )
|
||||||
|
msg << " with messages:";
|
||||||
|
for( auto const& messageInfo : assertionStats.infoMessages )
|
||||||
|
msg << "\n \"" << messageInfo.message << "\"";
|
||||||
|
|
||||||
|
|
||||||
|
if( result.hasExpression() ) {
|
||||||
|
msg <<
|
||||||
|
"\n " << result.getExpressionInMacro() << "\n"
|
||||||
|
"with expansion:\n" <<
|
||||||
|
" " << result.getExpandedExpression() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if( currentTestCaseInfo->okToFail() ) {
|
||||||
|
msg << "- failure ignore as test marked as 'ok to fail'\n";
|
||||||
|
stream << "##teamcity[testIgnored"
|
||||||
|
<< " name='" << escape( currentTestCaseInfo->name )<< "'"
|
||||||
|
<< " message='" << escape( msg.str() ) << "'"
|
||||||
|
<< "]\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
stream << "##teamcity[testFailed"
|
||||||
|
<< " name='" << escape( currentTestCaseInfo->name )<< "'"
|
||||||
|
<< " message='" << escape( msg.str() ) << "'"
|
||||||
|
<< "]\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream.flush();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sectionStarting( SectionInfo const& sectionInfo ) override {
|
||||||
|
m_headerPrintedForThisSection = false;
|
||||||
|
StreamingReporterBase::sectionStarting( sectionInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
void testCaseStarting( TestCaseInfo const& testInfo ) override {
|
||||||
|
m_testTimer.start();
|
||||||
|
StreamingReporterBase::testCaseStarting( testInfo );
|
||||||
|
stream << "##teamcity[testStarted name='"
|
||||||
|
<< escape( testInfo.name ) << "']\n";
|
||||||
|
stream.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void testCaseEnded( TestCaseStats const& testCaseStats ) override {
|
||||||
|
StreamingReporterBase::testCaseEnded( testCaseStats );
|
||||||
|
if( !testCaseStats.stdOut.empty() )
|
||||||
|
stream << "##teamcity[testStdOut name='"
|
||||||
|
<< escape( testCaseStats.testInfo.name )
|
||||||
|
<< "' out='" << escape( testCaseStats.stdOut ) << "']\n";
|
||||||
|
if( !testCaseStats.stdErr.empty() )
|
||||||
|
stream << "##teamcity[testStdErr name='"
|
||||||
|
<< escape( testCaseStats.testInfo.name )
|
||||||
|
<< "' out='" << escape( testCaseStats.stdErr ) << "']\n";
|
||||||
|
stream << "##teamcity[testFinished name='"
|
||||||
|
<< escape( testCaseStats.testInfo.name ) << "' duration='"
|
||||||
|
<< m_testTimer.getElapsedMilliseconds() << "']\n";
|
||||||
|
stream.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void printSectionHeader( std::ostream& os ) {
|
||||||
|
assert( !m_sectionStack.empty() );
|
||||||
|
|
||||||
|
if( m_sectionStack.size() > 1 ) {
|
||||||
|
os << getLineOfChars<'-'>() << "\n";
|
||||||
|
|
||||||
|
std::vector<SectionInfo>::const_iterator
|
||||||
|
it = m_sectionStack.begin()+1, // Skip first section (test case)
|
||||||
|
itEnd = m_sectionStack.end();
|
||||||
|
for( ; it != itEnd; ++it )
|
||||||
|
printHeaderString( os, it->name );
|
||||||
|
os << getLineOfChars<'-'>() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
|
||||||
|
|
||||||
|
if( !lineInfo.empty() )
|
||||||
|
os << lineInfo << "\n";
|
||||||
|
os << getLineOfChars<'.'>() << "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// if string has a : in first line will set indent to follow it on
|
||||||
|
// subsequent lines
|
||||||
|
static void printHeaderString( std::ostream& os, std::string const& _string, std::size_t indent = 0 ) {
|
||||||
|
std::size_t i = _string.find( ": " );
|
||||||
|
if( i != std::string::npos )
|
||||||
|
i+=2;
|
||||||
|
else
|
||||||
|
i = 0;
|
||||||
|
os << Column( _string )
|
||||||
|
.indent( indent+i)
|
||||||
|
.initialIndent( indent ) << "\n";
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
bool m_headerPrintedForThisSection = false;
|
||||||
|
Timer m_testTimer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CATCH_IMPL
|
||||||
|
TeamCityReporter::~TeamCityReporter() {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CATCH_REGISTER_REPORTER( "teamcity", TeamCityReporter )
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
|
14
src/deps/stduuid/cmake/Config.cmake.in
Normal file
14
src/deps/stduuid/cmake/Config.cmake.in
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
include(CMakeFindDependencyMacro)
|
||||||
|
if (@UUID_SYSTEM_GENERATOR@)
|
||||||
|
if (WIN32 OR APPLE)
|
||||||
|
else ()
|
||||||
|
list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
find_dependency(Libuuid REQUIRED)
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")
|
||||||
|
|
||||||
|
check_required_components(@PROJECT_NAME@)
|
17
src/deps/stduuid/cmake/FindLibuuid.cmake
Normal file
17
src/deps/stduuid/cmake/FindLibuuid.cmake
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
find_path(Libuuid_INCLUDE_DIRS uuid/uuid.h)
|
||||||
|
find_library(Libuuid_LIBRARIES uuid)
|
||||||
|
|
||||||
|
if (Libuuid_LIBRARIES AND Libuuid_INCLUDE_DIRS)
|
||||||
|
set(Libuuid_FOUND YES)
|
||||||
|
if (NOT Libuuid_FIND_QUIETLY)
|
||||||
|
message(STATUS "Found libuuid: ${Libuuid_LIBRARIES}")
|
||||||
|
endif ()
|
||||||
|
else ()
|
||||||
|
if (Libuuid_FIND_REQUIRED)
|
||||||
|
message(SEND_ERROR "Could NOT find libuuid")
|
||||||
|
else ()
|
||||||
|
if (NOT Libuuid_FIND_QUIETLY)
|
||||||
|
message(STATUS "Could NOT find libuuid")
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
endif ()
|
29
src/deps/stduuid/gsl/gsl
Normal file
29
src/deps/stduuid/gsl/gsl
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||||
|
//
|
||||||
|
// This code is licensed under the MIT License (MIT).
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef GSL_GSL_H
|
||||||
|
#define GSL_GSL_H
|
||||||
|
|
||||||
|
#include "gsl_algorithm" // copy
|
||||||
|
#include "gsl_assert" // Ensures/Expects
|
||||||
|
#include "gsl_byte" // byte
|
||||||
|
#include "gsl_util" // finally()/narrow()/narrow_cast()...
|
||||||
|
#include "multi_span" // multi_span, strided_span...
|
||||||
|
#include "pointers" // owner, not_null
|
||||||
|
#include "span" // span
|
||||||
|
#include "string_span" // zstring, string_span, zstring_builder...
|
||||||
|
|
||||||
|
#endif // GSL_GSL_H
|
63
src/deps/stduuid/gsl/gsl_algorithm
Normal file
63
src/deps/stduuid/gsl/gsl_algorithm
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||||
|
//
|
||||||
|
// This code is licensed under the MIT License (MIT).
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef GSL_ALGORITHM_H
|
||||||
|
#define GSL_ALGORITHM_H
|
||||||
|
|
||||||
|
#include "gsl_assert" // for Expects
|
||||||
|
#include "span" // for dynamic_extent, span
|
||||||
|
|
||||||
|
#include <algorithm> // for copy_n
|
||||||
|
#include <cstddef> // for ptrdiff_t
|
||||||
|
#include <type_traits> // for is_assignable
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
|
||||||
|
// turn off some warnings that are noisy about our Expects statements
|
||||||
|
#pragma warning(disable : 4127) // conditional expression is constant
|
||||||
|
#pragma warning(disable : 4996) // unsafe use of std::copy_n
|
||||||
|
|
||||||
|
// blanket turn off warnings from CppCoreCheck for now
|
||||||
|
// so people aren't annoyed by them when running the tool.
|
||||||
|
// more targeted suppressions will be added in a future update to the GSL
|
||||||
|
#pragma warning(disable : 26481 26482 26483 26485 26490 26491 26492 26493 26495)
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
namespace gsl
|
||||||
|
{
|
||||||
|
|
||||||
|
template <class SrcElementType, std::ptrdiff_t SrcExtent, class DestElementType,
|
||||||
|
std::ptrdiff_t DestExtent>
|
||||||
|
void copy(span<SrcElementType, SrcExtent> src, span<DestElementType, DestExtent> dest)
|
||||||
|
{
|
||||||
|
static_assert(std::is_assignable<decltype(*dest.data()), decltype(*src.data())>::value,
|
||||||
|
"Elements of source span can not be assigned to elements of destination span");
|
||||||
|
static_assert(SrcExtent == dynamic_extent || DestExtent == dynamic_extent ||
|
||||||
|
(SrcExtent <= DestExtent),
|
||||||
|
"Source range is longer than target range");
|
||||||
|
|
||||||
|
Expects(dest.size() >= src.size());
|
||||||
|
std::copy_n(src.data(), src.size(), dest.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace gsl
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
#endif // GSL_ALGORITHM_H
|
145
src/deps/stduuid/gsl/gsl_assert
Normal file
145
src/deps/stduuid/gsl/gsl_assert
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||||
|
//
|
||||||
|
// This code is licensed under the MIT License (MIT).
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef GSL_CONTRACTS_H
|
||||||
|
#define GSL_CONTRACTS_H
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <stdexcept> // for logic_error
|
||||||
|
|
||||||
|
//
|
||||||
|
// Temporary until MSVC STL supports no-exceptions mode.
|
||||||
|
// Currently terminate is a no-op in this mode, so we add termination behavior back
|
||||||
|
//
|
||||||
|
#if defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
|
||||||
|
#define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// There are three configuration options for this GSL implementation's behavior
|
||||||
|
// when pre/post conditions on the GSL types are violated:
|
||||||
|
//
|
||||||
|
// 1. GSL_TERMINATE_ON_CONTRACT_VIOLATION: std::terminate will be called (default)
|
||||||
|
// 2. GSL_THROW_ON_CONTRACT_VIOLATION: a gsl::fail_fast exception will be thrown
|
||||||
|
// 3. GSL_UNENFORCED_ON_CONTRACT_VIOLATION: nothing happens
|
||||||
|
//
|
||||||
|
#if !(defined(GSL_THROW_ON_CONTRACT_VIOLATION) || defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) || \
|
||||||
|
defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION))
|
||||||
|
#define GSL_TERMINATE_ON_CONTRACT_VIOLATION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define GSL_STRINGIFY_DETAIL(x) #x
|
||||||
|
#define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x)
|
||||||
|
|
||||||
|
#if defined(__clang__) || defined(__GNUC__)
|
||||||
|
#define GSL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||||
|
#define GSL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||||
|
#else
|
||||||
|
#define GSL_LIKELY(x) (!!(x))
|
||||||
|
#define GSL_UNLIKELY(x) (!!(x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// GSL_ASSUME(cond)
|
||||||
|
//
|
||||||
|
// Tell the optimizer that the predicate cond must hold. It is unspecified
|
||||||
|
// whether or not cond is actually evaluated.
|
||||||
|
//
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define GSL_ASSUME(cond) __assume(cond)
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define GSL_ASSUME(cond) ((cond) ? static_cast<void>(0) : __builtin_unreachable())
|
||||||
|
#else
|
||||||
|
#define GSL_ASSUME(cond) static_cast<void>((cond) ? 0 : 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// GSL.assert: assertions
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace gsl
|
||||||
|
{
|
||||||
|
struct fail_fast : public std::logic_error
|
||||||
|
{
|
||||||
|
explicit fail_fast(char const* const message) : std::logic_error(message) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace details
|
||||||
|
{
|
||||||
|
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
|
||||||
|
|
||||||
|
typedef void (__cdecl *terminate_handler)();
|
||||||
|
|
||||||
|
inline gsl::details::terminate_handler& get_terminate_handler() noexcept
|
||||||
|
{
|
||||||
|
static terminate_handler handler = &abort;
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[[noreturn]] inline void terminate() noexcept
|
||||||
|
{
|
||||||
|
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
|
||||||
|
(*gsl::details::get_terminate_handler())();
|
||||||
|
#else
|
||||||
|
std::terminate();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
|
||||||
|
|
||||||
|
template <typename Exception>
|
||||||
|
[[noreturn]] void throw_exception(Exception&&)
|
||||||
|
{
|
||||||
|
gsl::details::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
template <typename Exception>
|
||||||
|
[[noreturn]] void throw_exception(Exception&& exception)
|
||||||
|
{
|
||||||
|
throw std::forward<Exception>(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace gsl
|
||||||
|
|
||||||
|
#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
|
||||||
|
|
||||||
|
#define GSL_CONTRACT_CHECK(type, cond) \
|
||||||
|
(GSL_LIKELY(cond) ? static_cast<void>(0) \
|
||||||
|
: gsl::details::throw_exception(gsl::fail_fast( \
|
||||||
|
"GSL: " type " failure at " __FILE__ ": " GSL_STRINGIFY(__LINE__))))
|
||||||
|
|
||||||
|
#elif defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
|
||||||
|
|
||||||
|
#define GSL_CONTRACT_CHECK(type, cond) \
|
||||||
|
(GSL_LIKELY(cond) ? static_cast<void>(0) : gsl::details::terminate())
|
||||||
|
|
||||||
|
#elif defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION)
|
||||||
|
|
||||||
|
#define GSL_CONTRACT_CHECK(type, cond) GSL_ASSUME(cond)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define Expects(cond) GSL_CONTRACT_CHECK("Precondition", cond)
|
||||||
|
#define Ensures(cond) GSL_CONTRACT_CHECK("Postcondition", cond)
|
||||||
|
|
||||||
|
#endif // GSL_CONTRACTS_H
|
181
src/deps/stduuid/gsl/gsl_byte
Normal file
181
src/deps/stduuid/gsl/gsl_byte
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||||
|
//
|
||||||
|
// This code is licensed under the MIT License (MIT).
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef GSL_BYTE_H
|
||||||
|
#define GSL_BYTE_H
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
#pragma warning(push)
|
||||||
|
|
||||||
|
// don't warn about function style casts in byte related operators
|
||||||
|
#pragma warning(disable : 26493)
|
||||||
|
|
||||||
|
#ifndef GSL_USE_STD_BYTE
|
||||||
|
// this tests if we are under MSVC and the standard lib has std::byte and it is enabled
|
||||||
|
#if defined(_HAS_STD_BYTE) && _HAS_STD_BYTE
|
||||||
|
|
||||||
|
#define GSL_USE_STD_BYTE 1
|
||||||
|
|
||||||
|
#else // defined(_HAS_STD_BYTE) && _HAS_STD_BYTE
|
||||||
|
|
||||||
|
#define GSL_USE_STD_BYTE 0
|
||||||
|
|
||||||
|
#endif // defined(_HAS_STD_BYTE) && _HAS_STD_BYTE
|
||||||
|
#endif // GSL_USE_STD_BYTE
|
||||||
|
|
||||||
|
#else // _MSC_VER
|
||||||
|
|
||||||
|
#ifndef GSL_USE_STD_BYTE
|
||||||
|
// this tests if we are under GCC or Clang with enough -std:c++1z power to get us std::byte
|
||||||
|
#if defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||||
|
|
||||||
|
#define GSL_USE_STD_BYTE 1
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#else // defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||||
|
|
||||||
|
#define GSL_USE_STD_BYTE 0
|
||||||
|
|
||||||
|
#endif //defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||||
|
#endif // GSL_USE_STD_BYTE
|
||||||
|
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
// Use __may_alias__ attribute on gcc and clang
|
||||||
|
#if defined __clang__ || (__GNUC__ > 5)
|
||||||
|
#define byte_may_alias __attribute__((__may_alias__))
|
||||||
|
#else // defined __clang__ || defined __GNUC__
|
||||||
|
#define byte_may_alias
|
||||||
|
#endif // defined __clang__ || defined __GNUC__
|
||||||
|
|
||||||
|
namespace gsl
|
||||||
|
{
|
||||||
|
#if GSL_USE_STD_BYTE
|
||||||
|
|
||||||
|
|
||||||
|
using std::byte;
|
||||||
|
using std::to_integer;
|
||||||
|
|
||||||
|
#else // GSL_USE_STD_BYTE
|
||||||
|
|
||||||
|
// This is a simple definition for now that allows
|
||||||
|
// use of byte within span<> to be standards-compliant
|
||||||
|
enum class byte_may_alias byte : unsigned char
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||||
|
constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept
|
||||||
|
{
|
||||||
|
return b = byte(static_cast<unsigned char>(b) << shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||||
|
constexpr byte operator<<(byte b, IntegerType shift) noexcept
|
||||||
|
{
|
||||||
|
return byte(static_cast<unsigned char>(b) << shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||||
|
constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept
|
||||||
|
{
|
||||||
|
return b = byte(static_cast<unsigned char>(b) >> shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||||
|
constexpr byte operator>>(byte b, IntegerType shift) noexcept
|
||||||
|
{
|
||||||
|
return byte(static_cast<unsigned char>(b) >> shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr byte& operator|=(byte& l, byte r) noexcept
|
||||||
|
{
|
||||||
|
return l = byte(static_cast<unsigned char>(l) | static_cast<unsigned char>(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr byte operator|(byte l, byte r) noexcept
|
||||||
|
{
|
||||||
|
return byte(static_cast<unsigned char>(l) | static_cast<unsigned char>(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr byte& operator&=(byte& l, byte r) noexcept
|
||||||
|
{
|
||||||
|
return l = byte(static_cast<unsigned char>(l) & static_cast<unsigned char>(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr byte operator&(byte l, byte r) noexcept
|
||||||
|
{
|
||||||
|
return byte(static_cast<unsigned char>(l) & static_cast<unsigned char>(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr byte& operator^=(byte& l, byte r) noexcept
|
||||||
|
{
|
||||||
|
return l = byte(static_cast<unsigned char>(l) ^ static_cast<unsigned char>(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr byte operator^(byte l, byte r) noexcept
|
||||||
|
{
|
||||||
|
return byte(static_cast<unsigned char>(l) ^ static_cast<unsigned char>(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr byte operator~(byte b) noexcept { return byte(~static_cast<unsigned char>(b)); }
|
||||||
|
|
||||||
|
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
|
||||||
|
constexpr IntegerType to_integer(byte b) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<IntegerType>(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // GSL_USE_STD_BYTE
|
||||||
|
|
||||||
|
template <bool E, typename T>
|
||||||
|
constexpr byte to_byte_impl(T t) noexcept
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
E, "gsl::to_byte(t) must be provided an unsigned char, otherwise data loss may occur. "
|
||||||
|
"If you are calling to_byte with an integer contant use: gsl::to_byte<t>() version.");
|
||||||
|
return static_cast<byte>(t);
|
||||||
|
}
|
||||||
|
template <>
|
||||||
|
constexpr byte to_byte_impl<true, unsigned char>(unsigned char t) noexcept
|
||||||
|
{
|
||||||
|
return byte(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr byte to_byte(T t) noexcept
|
||||||
|
{
|
||||||
|
return to_byte_impl<std::is_same<T, unsigned char>::value, T>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int I>
|
||||||
|
constexpr byte to_byte() noexcept
|
||||||
|
{
|
||||||
|
static_assert(I >= 0 && I <= 255,
|
||||||
|
"gsl::byte only has 8 bits of storage, values must be in range 0-255");
|
||||||
|
return static_cast<byte>(I);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace gsl
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
#endif // GSL_BYTE_H
|
158
src/deps/stduuid/gsl/gsl_util
Normal file
158
src/deps/stduuid/gsl/gsl_util
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||||
|
//
|
||||||
|
// This code is licensed under the MIT License (MIT).
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef GSL_UTIL_H
|
||||||
|
#define GSL_UTIL_H
|
||||||
|
|
||||||
|
#include "gsl_assert" // for Expects
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef> // for ptrdiff_t, size_t
|
||||||
|
#include <exception> // for exception
|
||||||
|
#include <initializer_list> // for initializer_list
|
||||||
|
#include <type_traits> // for is_signed, integral_constant
|
||||||
|
#include <utility> // for forward
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4127) // conditional expression is constant
|
||||||
|
|
||||||
|
#if _MSC_VER < 1910
|
||||||
|
#pragma push_macro("constexpr")
|
||||||
|
#define constexpr /*constexpr*/
|
||||||
|
#endif // _MSC_VER < 1910
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
namespace gsl
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// GSL.util: utilities
|
||||||
|
//
|
||||||
|
|
||||||
|
// index type for all container indexes/subscripts/sizes
|
||||||
|
using index = std::ptrdiff_t;
|
||||||
|
|
||||||
|
// final_action allows you to ensure something gets run at the end of a scope
|
||||||
|
template <class F>
|
||||||
|
class final_action
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit final_action(F f) noexcept : f_(std::move(f)) {}
|
||||||
|
|
||||||
|
final_action(final_action&& other) noexcept : f_(std::move(other.f_)), invoke_(other.invoke_)
|
||||||
|
{
|
||||||
|
other.invoke_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final_action(const final_action&) = delete;
|
||||||
|
final_action& operator=(const final_action&) = delete;
|
||||||
|
final_action& operator=(final_action&&) = delete;
|
||||||
|
|
||||||
|
~final_action() noexcept
|
||||||
|
{
|
||||||
|
if (invoke_) f_();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
F f_;
|
||||||
|
bool invoke_ {true};
|
||||||
|
};
|
||||||
|
|
||||||
|
// finally() - convenience function to generate a final_action
|
||||||
|
template <class F>
|
||||||
|
|
||||||
|
final_action<F> finally(const F& f) noexcept
|
||||||
|
{
|
||||||
|
return final_action<F>(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
final_action<F> finally(F&& f) noexcept
|
||||||
|
{
|
||||||
|
return final_action<F>(std::forward<F>(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
// narrow_cast(): a searchable way to do narrowing casts of values
|
||||||
|
template <class T, class U>
|
||||||
|
constexpr T narrow_cast(U&& u) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<T>(std::forward<U>(u));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct narrowing_error : public std::exception
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace details
|
||||||
|
{
|
||||||
|
template <class T, class U>
|
||||||
|
struct is_same_signedness
|
||||||
|
: public std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value
|
||||||
|
template <class T, class U>
|
||||||
|
T narrow(U u)
|
||||||
|
{
|
||||||
|
T t = narrow_cast<T>(u);
|
||||||
|
if (static_cast<U>(t) != u) gsl::details::throw_exception(narrowing_error());
|
||||||
|
if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))
|
||||||
|
gsl::details::throw_exception(narrowing_error());
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// at() - Bounds-checked way of accessing builtin arrays, std::array, std::vector
|
||||||
|
//
|
||||||
|
template <class T, std::size_t N>
|
||||||
|
constexpr T& at(T (&arr)[N], const index i)
|
||||||
|
{
|
||||||
|
Expects(i >= 0 && i < narrow_cast<index>(N));
|
||||||
|
return arr[static_cast<std::size_t>(i)];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Cont>
|
||||||
|
constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()])
|
||||||
|
{
|
||||||
|
Expects(i >= 0 && i < narrow_cast<index>(cont.size()));
|
||||||
|
using size_type = decltype(cont.size());
|
||||||
|
return cont[static_cast<size_type>(i)];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
constexpr T at(const std::initializer_list<T> cont, const index i)
|
||||||
|
{
|
||||||
|
Expects(i >= 0 && i < narrow_cast<index>(cont.size()));
|
||||||
|
return *(cont.begin() + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace gsl
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#if _MSC_VER < 1910
|
||||||
|
#undef constexpr
|
||||||
|
#pragma pop_macro("constexpr")
|
||||||
|
|
||||||
|
#endif // _MSC_VER < 1910
|
||||||
|
|
||||||
|
#pragma warning(pop)
|
||||||
|
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
#endif // GSL_UTIL_H
|
2242
src/deps/stduuid/gsl/multi_span
Normal file
2242
src/deps/stduuid/gsl/multi_span
Normal file
File diff suppressed because it is too large
Load diff
193
src/deps/stduuid/gsl/pointers
Normal file
193
src/deps/stduuid/gsl/pointers
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||||
|
//
|
||||||
|
// This code is licensed under the MIT License (MIT).
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef GSL_POINTERS_H
|
||||||
|
#define GSL_POINTERS_H
|
||||||
|
|
||||||
|
#include "gsl_assert" // for Ensures, Expects
|
||||||
|
|
||||||
|
#include <algorithm> // for forward
|
||||||
|
#include <iosfwd> // for ptrdiff_t, nullptr_t, ostream, size_t
|
||||||
|
#include <memory> // for shared_ptr, unique_ptr
|
||||||
|
#include <system_error> // for hash
|
||||||
|
#include <type_traits> // for enable_if_t, is_convertible, is_assignable
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER < 1910
|
||||||
|
#pragma push_macro("constexpr")
|
||||||
|
#define constexpr /*constexpr*/
|
||||||
|
|
||||||
|
#endif // defined(_MSC_VER) && _MSC_VER < 1910
|
||||||
|
|
||||||
|
namespace gsl
|
||||||
|
{
|
||||||
|
|
||||||
|
//
|
||||||
|
// GSL.owner: ownership pointers
|
||||||
|
//
|
||||||
|
using std::unique_ptr;
|
||||||
|
using std::shared_ptr;
|
||||||
|
|
||||||
|
//
|
||||||
|
// owner
|
||||||
|
//
|
||||||
|
// owner<T> is designed as a bridge for code that must deal directly with owning pointers for some reason
|
||||||
|
//
|
||||||
|
// T must be a pointer type
|
||||||
|
// - disallow construction from any type other than pointer type
|
||||||
|
//
|
||||||
|
template <class T, class = std::enable_if_t<std::is_pointer<T>::value>>
|
||||||
|
using owner = T;
|
||||||
|
|
||||||
|
//
|
||||||
|
// not_null
|
||||||
|
//
|
||||||
|
// Restricts a pointer or smart pointer to only hold non-null values.
|
||||||
|
//
|
||||||
|
// Has zero size overhead over T.
|
||||||
|
//
|
||||||
|
// If T is a pointer (i.e. T == U*) then
|
||||||
|
// - allow construction from U*
|
||||||
|
// - disallow construction from nullptr_t
|
||||||
|
// - disallow default construction
|
||||||
|
// - ensure construction from null U* fails
|
||||||
|
// - allow implicit conversion to U*
|
||||||
|
//
|
||||||
|
template <class T>
|
||||||
|
class not_null
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static_assert(std::is_assignable<T&, std::nullptr_t>::value, "T cannot be assigned nullptr.");
|
||||||
|
|
||||||
|
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||||
|
constexpr explicit not_null(U&& u) : ptr_(std::forward<U>(u))
|
||||||
|
{
|
||||||
|
Expects(ptr_ != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
|
||||||
|
constexpr explicit not_null(T u) : ptr_(u)
|
||||||
|
{
|
||||||
|
Expects(ptr_ != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
|
||||||
|
constexpr not_null(const not_null<U>& other) : not_null(other.get())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
not_null(not_null&& other) = default;
|
||||||
|
not_null(const not_null& other) = default;
|
||||||
|
not_null& operator=(const not_null& other) = default;
|
||||||
|
|
||||||
|
constexpr T get() const
|
||||||
|
{
|
||||||
|
Ensures(ptr_ != nullptr);
|
||||||
|
return ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr operator T() const { return get(); }
|
||||||
|
constexpr T operator->() const { return get(); }
|
||||||
|
constexpr decltype(auto) operator*() const { return *get(); }
|
||||||
|
|
||||||
|
// prevents compilation when someone attempts to assign a null pointer constant
|
||||||
|
not_null(std::nullptr_t) = delete;
|
||||||
|
not_null& operator=(std::nullptr_t) = delete;
|
||||||
|
|
||||||
|
// unwanted operators...pointers only point to single objects!
|
||||||
|
not_null& operator++() = delete;
|
||||||
|
not_null& operator--() = delete;
|
||||||
|
not_null operator++(int) = delete;
|
||||||
|
not_null operator--(int) = delete;
|
||||||
|
not_null& operator+=(std::ptrdiff_t) = delete;
|
||||||
|
not_null& operator-=(std::ptrdiff_t) = delete;
|
||||||
|
void operator[](std::ptrdiff_t) const = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
T ptr_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
std::ostream& operator<<(std::ostream& os, const not_null<T>& val)
|
||||||
|
{
|
||||||
|
os << val.get();
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class U>
|
||||||
|
auto operator==(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() == rhs.get())
|
||||||
|
{
|
||||||
|
return lhs.get() == rhs.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class U>
|
||||||
|
auto operator!=(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() != rhs.get())
|
||||||
|
{
|
||||||
|
return lhs.get() != rhs.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class U>
|
||||||
|
auto operator<(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() < rhs.get())
|
||||||
|
{
|
||||||
|
return lhs.get() < rhs.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class U>
|
||||||
|
auto operator<=(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() <= rhs.get())
|
||||||
|
{
|
||||||
|
return lhs.get() <= rhs.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class U>
|
||||||
|
auto operator>(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() > rhs.get())
|
||||||
|
{
|
||||||
|
return lhs.get() > rhs.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class U>
|
||||||
|
auto operator>=(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() >= rhs.get())
|
||||||
|
{
|
||||||
|
return lhs.get() >= rhs.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// more unwanted operators
|
||||||
|
template <class T, class U>
|
||||||
|
std::ptrdiff_t operator-(const not_null<T>&, const not_null<U>&) = delete;
|
||||||
|
template <class T>
|
||||||
|
not_null<T> operator-(const not_null<T>&, std::ptrdiff_t) = delete;
|
||||||
|
template <class T>
|
||||||
|
not_null<T> operator+(const not_null<T>&, std::ptrdiff_t) = delete;
|
||||||
|
template <class T>
|
||||||
|
not_null<T> operator+(std::ptrdiff_t, const not_null<T>&) = delete;
|
||||||
|
|
||||||
|
} // namespace gsl
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
struct hash<gsl::not_null<T>>
|
||||||
|
{
|
||||||
|
std::size_t operator()(const gsl::not_null<T>& value) const { return hash<T>{}(value); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER < 1910
|
||||||
|
#undef constexpr
|
||||||
|
#pragma pop_macro("constexpr")
|
||||||
|
|
||||||
|
#endif // defined(_MSC_VER) && _MSC_VER < 1910
|
||||||
|
|
||||||
|
#endif // GSL_POINTERS_H
|
766
src/deps/stduuid/gsl/span
Normal file
766
src/deps/stduuid/gsl/span
Normal file
|
@ -0,0 +1,766 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||||
|
//
|
||||||
|
// This code is licensed under the MIT License (MIT).
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef GSL_SPAN_H
|
||||||
|
#define GSL_SPAN_H
|
||||||
|
|
||||||
|
#include "gsl_assert" // for Expects
|
||||||
|
#include "gsl_byte" // for byte
|
||||||
|
#include "gsl_util" // for narrow_cast, narrow
|
||||||
|
|
||||||
|
#include <algorithm> // for lexicographical_compare
|
||||||
|
#include <array> // for array
|
||||||
|
#include <cstddef> // for ptrdiff_t, size_t, nullptr_t
|
||||||
|
#include <iterator> // for reverse_iterator, distance, random_access_...
|
||||||
|
#include <limits>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <type_traits> // for enable_if_t, declval, is_convertible, inte...
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
|
||||||
|
// turn off some warnings that are noisy about our Expects statements
|
||||||
|
#pragma warning(disable : 4127) // conditional expression is constant
|
||||||
|
#pragma warning(disable : 4702) // unreachable code
|
||||||
|
|
||||||
|
// blanket turn off warnings from CppCoreCheck for now
|
||||||
|
// so people aren't annoyed by them when running the tool.
|
||||||
|
// more targeted suppressions will be added in a future update to the GSL
|
||||||
|
#pragma warning(disable : 26481 26482 26483 26485 26490 26491 26492 26493 26495)
|
||||||
|
|
||||||
|
#if _MSC_VER < 1910
|
||||||
|
#pragma push_macro("constexpr")
|
||||||
|
#define constexpr /*constexpr*/
|
||||||
|
#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
|
||||||
|
|
||||||
|
#endif // _MSC_VER < 1910
|
||||||
|
#else // _MSC_VER
|
||||||
|
|
||||||
|
// See if we have enough C++17 power to use a static constexpr data member
|
||||||
|
// without needing an out-of-line definition
|
||||||
|
#if !(defined(__cplusplus) && (__cplusplus >= 201703L))
|
||||||
|
#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
|
||||||
|
#endif // !(defined(__cplusplus) && (__cplusplus >= 201703L))
|
||||||
|
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
// GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t)
|
||||||
|
// While there is a conversion from signed to unsigned, it happens at
|
||||||
|
// compiletime, so the compiler wouldn't have to warn indiscriminently, but
|
||||||
|
// could check if the source value actually doesn't fit into the target type
|
||||||
|
// and only warn in those cases.
|
||||||
|
#if __GNUC__ > 6
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace gsl
|
||||||
|
{
|
||||||
|
|
||||||
|
// [views.constants], constants
|
||||||
|
constexpr const std::ptrdiff_t dynamic_extent = -1;
|
||||||
|
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
class span;
|
||||||
|
|
||||||
|
// implementation details
|
||||||
|
namespace details
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
struct is_span_oracle : std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent>
|
||||||
|
struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct is_span : public is_span_oracle<std::remove_cv_t<T>>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct is_std_array_oracle : std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class ElementType, std::size_t Extent>
|
||||||
|
struct is_std_array_oracle<std::array<ElementType, Extent>> : std::true_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct is_std_array : public is_std_array_oracle<std::remove_cv_t<T>>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <std::ptrdiff_t From, std::ptrdiff_t To>
|
||||||
|
struct is_allowed_extent_conversion
|
||||||
|
: public std::integral_constant<bool, From == To || From == gsl::dynamic_extent ||
|
||||||
|
To == gsl::dynamic_extent>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class From, class To>
|
||||||
|
struct is_allowed_element_type_conversion
|
||||||
|
: public std::integral_constant<bool, std::is_convertible<From (*)[], To (*)[]>::value>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Span, bool IsConst>
|
||||||
|
class span_iterator
|
||||||
|
{
|
||||||
|
using element_type_ = typename Span::element_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// Tell Microsoft standard library that span_iterators are checked.
|
||||||
|
using _Unchecked_type = typename Span::pointer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using iterator_category = std::random_access_iterator_tag;
|
||||||
|
using value_type = std::remove_cv_t<element_type_>;
|
||||||
|
using difference_type = typename Span::index_type;
|
||||||
|
|
||||||
|
using reference = std::conditional_t<IsConst, const element_type_, element_type_>&;
|
||||||
|
using pointer = std::add_pointer_t<reference>;
|
||||||
|
|
||||||
|
span_iterator() = default;
|
||||||
|
|
||||||
|
constexpr span_iterator(const Span* span, typename Span::index_type idx) noexcept
|
||||||
|
: span_(span), index_(idx)
|
||||||
|
{}
|
||||||
|
|
||||||
|
friend span_iterator<Span, true>;
|
||||||
|
template<bool B, std::enable_if_t<!B && IsConst>* = nullptr>
|
||||||
|
constexpr span_iterator(const span_iterator<Span, B>& other) noexcept
|
||||||
|
: span_iterator(other.span_, other.index_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr reference operator*() const
|
||||||
|
{
|
||||||
|
Expects(index_ != span_->size());
|
||||||
|
return *(span_->data() + index_);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr pointer operator->() const
|
||||||
|
{
|
||||||
|
Expects(index_ != span_->size());
|
||||||
|
return span_->data() + index_;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr span_iterator& operator++()
|
||||||
|
{
|
||||||
|
Expects(0 <= index_ && index_ != span_->size());
|
||||||
|
++index_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr span_iterator operator++(int)
|
||||||
|
{
|
||||||
|
auto ret = *this;
|
||||||
|
++(*this);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr span_iterator& operator--()
|
||||||
|
{
|
||||||
|
Expects(index_ != 0 && index_ <= span_->size());
|
||||||
|
--index_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr span_iterator operator--(int)
|
||||||
|
{
|
||||||
|
auto ret = *this;
|
||||||
|
--(*this);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr span_iterator operator+(difference_type n) const
|
||||||
|
{
|
||||||
|
auto ret = *this;
|
||||||
|
return ret += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr span_iterator operator+(difference_type n, span_iterator const& rhs)
|
||||||
|
{
|
||||||
|
return rhs + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr span_iterator& operator+=(difference_type n)
|
||||||
|
{
|
||||||
|
Expects((index_ + n) >= 0 && (index_ + n) <= span_->size());
|
||||||
|
index_ += n;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr span_iterator operator-(difference_type n) const
|
||||||
|
{
|
||||||
|
auto ret = *this;
|
||||||
|
return ret -= n;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr span_iterator& operator-=(difference_type n) { return *this += -n; }
|
||||||
|
|
||||||
|
constexpr difference_type operator-(span_iterator rhs) const
|
||||||
|
{
|
||||||
|
Expects(span_ == rhs.span_);
|
||||||
|
return index_ - rhs.index_;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr reference operator[](difference_type n) const
|
||||||
|
{
|
||||||
|
return *(*this + n);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr friend bool operator==(span_iterator lhs,
|
||||||
|
span_iterator rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr friend bool operator!=(span_iterator lhs,
|
||||||
|
span_iterator rhs) noexcept
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr friend bool operator<(span_iterator lhs,
|
||||||
|
span_iterator rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.index_ < rhs.index_;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr friend bool operator<=(span_iterator lhs,
|
||||||
|
span_iterator rhs) noexcept
|
||||||
|
{
|
||||||
|
return !(rhs < lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr friend bool operator>(span_iterator lhs,
|
||||||
|
span_iterator rhs) noexcept
|
||||||
|
{
|
||||||
|
return rhs < lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr friend bool operator>=(span_iterator lhs,
|
||||||
|
span_iterator rhs) noexcept
|
||||||
|
{
|
||||||
|
return !(rhs > lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// MSVC++ iterator debugging support; allows STL algorithms in 15.8+
|
||||||
|
// to unwrap span_iterator to a pointer type after a range check in STL
|
||||||
|
// algorithm calls
|
||||||
|
friend constexpr void _Verify_range(span_iterator lhs,
|
||||||
|
span_iterator rhs) noexcept
|
||||||
|
{ // test that [lhs, rhs) forms a valid range inside an STL algorithm
|
||||||
|
Expects(lhs.span_ == rhs.span_ // range spans have to match
|
||||||
|
&& lhs.index_ <= rhs.index_); // range must not be transposed
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void _Verify_offset(const difference_type n) const noexcept
|
||||||
|
{ // test that the iterator *this + n is a valid range in an STL
|
||||||
|
// algorithm call
|
||||||
|
Expects((index_ + n) >= 0 && (index_ + n) <= span_->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr pointer _Unwrapped() const noexcept
|
||||||
|
{ // after seeking *this to a high water mark, or using one of the
|
||||||
|
// _Verify_xxx functions above, unwrap this span_iterator to a raw
|
||||||
|
// pointer
|
||||||
|
return span_->data() + index_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell the STL that span_iterator should not be unwrapped if it can't
|
||||||
|
// validate in advance, even in release / optimized builds:
|
||||||
|
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
|
||||||
|
static constexpr const bool _Unwrap_when_unverified = false;
|
||||||
|
#else
|
||||||
|
static constexpr bool _Unwrap_when_unverified = false;
|
||||||
|
#endif
|
||||||
|
constexpr void _Seek_to(const pointer p) noexcept
|
||||||
|
{ // adjust the position of *this to previously verified location p
|
||||||
|
// after _Unwrapped
|
||||||
|
index_ = p - span_->data();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const Span* span_ = nullptr;
|
||||||
|
std::ptrdiff_t index_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Ext>
|
||||||
|
class extent_type
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using index_type = std::ptrdiff_t;
|
||||||
|
|
||||||
|
static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size.");
|
||||||
|
|
||||||
|
constexpr extent_type() noexcept {}
|
||||||
|
|
||||||
|
template <index_type Other>
|
||||||
|
constexpr extent_type(extent_type<Other> ext)
|
||||||
|
{
|
||||||
|
static_assert(Other == Ext || Other == dynamic_extent,
|
||||||
|
"Mismatch between fixed-size extent and size of initializing data.");
|
||||||
|
Expects(ext.size() == Ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr extent_type(index_type size) { Expects(size == Ext); }
|
||||||
|
|
||||||
|
constexpr index_type size() const noexcept { return Ext; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class extent_type<dynamic_extent>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using index_type = std::ptrdiff_t;
|
||||||
|
|
||||||
|
template <index_type Other>
|
||||||
|
explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); }
|
||||||
|
|
||||||
|
constexpr index_type size() const noexcept { return size_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
index_type size_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent, std::ptrdiff_t Offset, std::ptrdiff_t Count>
|
||||||
|
struct calculate_subspan_type
|
||||||
|
{
|
||||||
|
using type = span<ElementType, Count != dynamic_extent ? Count : (Extent != dynamic_extent ? Extent - Offset : Extent)>;
|
||||||
|
};
|
||||||
|
} // namespace details
|
||||||
|
|
||||||
|
// [span], class template span
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent>
|
||||||
|
class span
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// constants and types
|
||||||
|
using element_type = ElementType;
|
||||||
|
using value_type = std::remove_cv_t<ElementType>;
|
||||||
|
using index_type = std::ptrdiff_t;
|
||||||
|
using pointer = element_type*;
|
||||||
|
using reference = element_type&;
|
||||||
|
|
||||||
|
using iterator = details::span_iterator<span<ElementType, Extent>, false>;
|
||||||
|
using const_iterator = details::span_iterator<span<ElementType, Extent>, true>;
|
||||||
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||||
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||||
|
|
||||||
|
using size_type = index_type;
|
||||||
|
|
||||||
|
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
|
||||||
|
static constexpr const index_type extent { Extent };
|
||||||
|
#else
|
||||||
|
static constexpr index_type extent { Extent };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// [span.cons], span constructors, copy, assignment, and destructor
|
||||||
|
template <bool Dependent = false,
|
||||||
|
// "Dependent" is needed to make "std::enable_if_t<Dependent || Extent <= 0>" SFINAE,
|
||||||
|
// since "std::enable_if_t<Extent <= 0>" is ill-formed when Extent is greater than 0.
|
||||||
|
class = std::enable_if_t<(Dependent || Extent <= 0)>>
|
||||||
|
constexpr span() noexcept : storage_(nullptr, details::extent_type<0>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {}
|
||||||
|
|
||||||
|
constexpr span(pointer firstElem, pointer lastElem)
|
||||||
|
: storage_(firstElem, std::distance(firstElem, lastElem))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t N>
|
||||||
|
constexpr span(element_type (&arr)[N]) noexcept
|
||||||
|
: storage_(KnownNotNull{&arr[0]}, details::extent_type<N>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
|
||||||
|
constexpr span(std::array<ArrayElementType, N>& arr) noexcept
|
||||||
|
: storage_(&arr[0], details::extent_type<N>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t N>
|
||||||
|
constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) noexcept
|
||||||
|
: storage_(&arr[0], details::extent_type<N>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement
|
||||||
|
// on Container to be a contiguous sequence container.
|
||||||
|
template <class Container,
|
||||||
|
class = std::enable_if_t<
|
||||||
|
!details::is_span<Container>::value && !details::is_std_array<Container>::value &&
|
||||||
|
std::is_convertible<typename Container::pointer, pointer>::value &&
|
||||||
|
std::is_convertible<typename Container::pointer,
|
||||||
|
decltype(std::declval<Container>().data())>::value>>
|
||||||
|
constexpr span(Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Container,
|
||||||
|
class = std::enable_if_t<
|
||||||
|
std::is_const<element_type>::value && !details::is_span<Container>::value &&
|
||||||
|
std::is_convertible<typename Container::pointer, pointer>::value &&
|
||||||
|
std::is_convertible<typename Container::pointer,
|
||||||
|
decltype(std::declval<Container>().data())>::value>>
|
||||||
|
constexpr span(const Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr span(const span& other) noexcept = default;
|
||||||
|
|
||||||
|
template <
|
||||||
|
class OtherElementType, std::ptrdiff_t OtherExtent,
|
||||||
|
class = std::enable_if_t<
|
||||||
|
details::is_allowed_extent_conversion<OtherExtent, Extent>::value &&
|
||||||
|
details::is_allowed_element_type_conversion<OtherElementType, element_type>::value>>
|
||||||
|
constexpr span(const span<OtherElementType, OtherExtent>& other)
|
||||||
|
: storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~span() noexcept = default;
|
||||||
|
constexpr span& operator=(const span& other) noexcept = default;
|
||||||
|
|
||||||
|
// [span.sub], span subviews
|
||||||
|
template <std::ptrdiff_t Count>
|
||||||
|
constexpr span<element_type, Count> first() const
|
||||||
|
{
|
||||||
|
Expects(Count >= 0 && Count <= size());
|
||||||
|
return {data(), Count};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Count>
|
||||||
|
constexpr span<element_type, Count> last() const
|
||||||
|
{
|
||||||
|
Expects(Count >= 0 && size() - Count >= 0);
|
||||||
|
return {data() + (size() - Count), Count};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Offset, std::ptrdiff_t Count = dynamic_extent>
|
||||||
|
constexpr auto subspan() const -> typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
|
||||||
|
{
|
||||||
|
Expects((Offset >= 0 && size() - Offset >= 0) &&
|
||||||
|
(Count == dynamic_extent || (Count >= 0 && Offset + Count <= size())));
|
||||||
|
|
||||||
|
return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr span<element_type, dynamic_extent> first(index_type count) const
|
||||||
|
{
|
||||||
|
Expects(count >= 0 && count <= size());
|
||||||
|
return {data(), count};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr span<element_type, dynamic_extent> last(index_type count) const
|
||||||
|
{
|
||||||
|
return make_subspan(size() - count, dynamic_extent, subspan_selector<Extent>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr span<element_type, dynamic_extent> subspan(index_type offset,
|
||||||
|
index_type count = dynamic_extent) const
|
||||||
|
{
|
||||||
|
return make_subspan(offset, count, subspan_selector<Extent>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// [span.obs], span observers
|
||||||
|
constexpr index_type size() const noexcept { return storage_.size(); }
|
||||||
|
constexpr index_type size_bytes() const noexcept
|
||||||
|
{
|
||||||
|
return size() * narrow_cast<index_type>(sizeof(element_type));
|
||||||
|
}
|
||||||
|
constexpr bool empty() const noexcept { return size() == 0; }
|
||||||
|
|
||||||
|
// [span.elem], span element access
|
||||||
|
constexpr reference operator[](index_type idx) const
|
||||||
|
{
|
||||||
|
Expects(idx >= 0 && idx < storage_.size());
|
||||||
|
return data()[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr reference at(index_type idx) const { return this->operator[](idx); }
|
||||||
|
constexpr reference operator()(index_type idx) const { return this->operator[](idx); }
|
||||||
|
constexpr pointer data() const noexcept { return storage_.data(); }
|
||||||
|
|
||||||
|
// [span.iter], span iterator support
|
||||||
|
constexpr iterator begin() const noexcept { return {this, 0}; }
|
||||||
|
constexpr iterator end() const noexcept { return {this, size()}; }
|
||||||
|
|
||||||
|
constexpr const_iterator cbegin() const noexcept { return {this, 0}; }
|
||||||
|
constexpr const_iterator cend() const noexcept { return {this, size()}; }
|
||||||
|
|
||||||
|
constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
|
||||||
|
constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
|
||||||
|
|
||||||
|
constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{cend()}; }
|
||||||
|
constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator{cbegin()}; }
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// Tell MSVC how to unwrap spans in range-based-for
|
||||||
|
constexpr pointer _Unchecked_begin() const noexcept { return data(); }
|
||||||
|
constexpr pointer _Unchecked_end() const noexcept { return data() + size(); }
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Needed to remove unnecessary null check in subspans
|
||||||
|
struct KnownNotNull
|
||||||
|
{
|
||||||
|
pointer p;
|
||||||
|
};
|
||||||
|
|
||||||
|
// this implementation detail class lets us take advantage of the
|
||||||
|
// empty base class optimization to pay for only storage of a single
|
||||||
|
// pointer in the case of fixed-size spans
|
||||||
|
template <class ExtentType>
|
||||||
|
class storage_type : public ExtentType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// KnownNotNull parameter is needed to remove unnecessary null check
|
||||||
|
// in subspans and constructors from arrays
|
||||||
|
template <class OtherExtentType>
|
||||||
|
constexpr storage_type(KnownNotNull data, OtherExtentType ext) : ExtentType(ext), data_(data.p)
|
||||||
|
{
|
||||||
|
Expects(ExtentType::size() >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class OtherExtentType>
|
||||||
|
constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
|
||||||
|
{
|
||||||
|
Expects(ExtentType::size() >= 0);
|
||||||
|
Expects(data || ExtentType::size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr pointer data() const noexcept { return data_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
pointer data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
storage_type<details::extent_type<Extent>> storage_;
|
||||||
|
|
||||||
|
// The rest is needed to remove unnecessary null check
|
||||||
|
// in subspans and constructors from arrays
|
||||||
|
constexpr span(KnownNotNull ptr, index_type count) : storage_(ptr, count) {}
|
||||||
|
|
||||||
|
template <std::ptrdiff_t CallerExtent>
|
||||||
|
class subspan_selector {};
|
||||||
|
|
||||||
|
template <std::ptrdiff_t CallerExtent>
|
||||||
|
span<element_type, dynamic_extent> make_subspan(index_type offset,
|
||||||
|
index_type count,
|
||||||
|
subspan_selector<CallerExtent>) const
|
||||||
|
{
|
||||||
|
span<element_type, dynamic_extent> tmp(*this);
|
||||||
|
return tmp.subspan(offset, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
span<element_type, dynamic_extent> make_subspan(index_type offset,
|
||||||
|
index_type count,
|
||||||
|
subspan_selector<dynamic_extent>) const
|
||||||
|
{
|
||||||
|
Expects(offset >= 0 && size() - offset >= 0);
|
||||||
|
if (count == dynamic_extent)
|
||||||
|
{
|
||||||
|
return { KnownNotNull{ data() + offset }, size() - offset };
|
||||||
|
}
|
||||||
|
|
||||||
|
Expects(count >= 0 && size() - offset >= count);
|
||||||
|
return { KnownNotNull{ data() + offset }, count };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent>
|
||||||
|
constexpr const typename span<ElementType, Extent>::index_type span<ElementType, Extent>::extent;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// [span.comparison], span comparison operators
|
||||||
|
template <class ElementType, std::ptrdiff_t FirstExtent, std::ptrdiff_t SecondExtent>
|
||||||
|
constexpr bool operator==(span<ElementType, FirstExtent> l,
|
||||||
|
span<ElementType, SecondExtent> r)
|
||||||
|
{
|
||||||
|
return std::equal(l.begin(), l.end(), r.begin(), r.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent>
|
||||||
|
constexpr bool operator!=(span<ElementType, Extent> l,
|
||||||
|
span<ElementType, Extent> r)
|
||||||
|
{
|
||||||
|
return !(l == r);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent>
|
||||||
|
constexpr bool operator<(span<ElementType, Extent> l,
|
||||||
|
span<ElementType, Extent> r)
|
||||||
|
{
|
||||||
|
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent>
|
||||||
|
constexpr bool operator<=(span<ElementType, Extent> l,
|
||||||
|
span<ElementType, Extent> r)
|
||||||
|
{
|
||||||
|
return !(l > r);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent>
|
||||||
|
constexpr bool operator>(span<ElementType, Extent> l,
|
||||||
|
span<ElementType, Extent> r)
|
||||||
|
{
|
||||||
|
return r < l;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent>
|
||||||
|
constexpr bool operator>=(span<ElementType, Extent> l,
|
||||||
|
span<ElementType, Extent> r)
|
||||||
|
{
|
||||||
|
return !(l < r);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace details
|
||||||
|
{
|
||||||
|
// if we only supported compilers with good constexpr support then
|
||||||
|
// this pair of classes could collapse down to a constexpr function
|
||||||
|
|
||||||
|
// we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as
|
||||||
|
// constexpr
|
||||||
|
// and so will fail compilation of the template
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent>
|
||||||
|
struct calculate_byte_size
|
||||||
|
: std::integral_constant<std::ptrdiff_t,
|
||||||
|
static_cast<std::ptrdiff_t>(sizeof(ElementType) *
|
||||||
|
static_cast<std::size_t>(Extent))>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class ElementType>
|
||||||
|
struct calculate_byte_size<ElementType, dynamic_extent>
|
||||||
|
: std::integral_constant<std::ptrdiff_t, dynamic_extent>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// [span.objectrep], views of object representation
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent>
|
||||||
|
span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||||
|
as_bytes(span<ElementType, Extent> s) noexcept
|
||||||
|
{
|
||||||
|
return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent,
|
||||||
|
class = std::enable_if_t<!std::is_const<ElementType>::value>>
|
||||||
|
span<byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||||
|
as_writeable_bytes(span<ElementType, Extent> s) noexcept
|
||||||
|
{
|
||||||
|
return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// make_span() - Utility functions for creating spans
|
||||||
|
//
|
||||||
|
template <class ElementType>
|
||||||
|
constexpr span<ElementType> make_span(ElementType* ptr, typename span<ElementType>::index_type count)
|
||||||
|
{
|
||||||
|
return span<ElementType>(ptr, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ElementType>
|
||||||
|
constexpr span<ElementType> make_span(ElementType* firstElem, ElementType* lastElem)
|
||||||
|
{
|
||||||
|
return span<ElementType>(firstElem, lastElem);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ElementType, std::size_t N>
|
||||||
|
constexpr span<ElementType, N> make_span(ElementType (&arr)[N]) noexcept
|
||||||
|
{
|
||||||
|
return span<ElementType, N>(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Container>
|
||||||
|
constexpr span<typename Container::value_type> make_span(Container& cont)
|
||||||
|
{
|
||||||
|
return span<typename Container::value_type>(cont);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Container>
|
||||||
|
constexpr span<const typename Container::value_type> make_span(const Container& cont)
|
||||||
|
{
|
||||||
|
return span<const typename Container::value_type>(cont);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Ptr>
|
||||||
|
constexpr span<typename Ptr::element_type> make_span(Ptr& cont, std::ptrdiff_t count)
|
||||||
|
{
|
||||||
|
return span<typename Ptr::element_type>(cont, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Ptr>
|
||||||
|
constexpr span<typename Ptr::element_type> make_span(Ptr& cont)
|
||||||
|
{
|
||||||
|
return span<typename Ptr::element_type>(cont);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specialization of gsl::at for span
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent>
|
||||||
|
constexpr ElementType& at(span<ElementType, Extent> s, index i)
|
||||||
|
{
|
||||||
|
// No bounds checking here because it is done in span::operator[] called below
|
||||||
|
return s[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace gsl
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#if _MSC_VER < 1910
|
||||||
|
#undef constexpr
|
||||||
|
#pragma pop_macro("constexpr")
|
||||||
|
|
||||||
|
#endif // _MSC_VER < 1910
|
||||||
|
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
#if __GNUC__ > 6
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif // __GNUC__ > 6
|
||||||
|
|
||||||
|
#endif // GSL_SPAN_H
|
730
src/deps/stduuid/gsl/string_span
Normal file
730
src/deps/stduuid/gsl/string_span
Normal file
|
@ -0,0 +1,730 @@
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||||
|
//
|
||||||
|
// This code is licensed under the MIT License (MIT).
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef GSL_STRING_SPAN_H
|
||||||
|
#define GSL_STRING_SPAN_H
|
||||||
|
|
||||||
|
#include "gsl_assert" // for Ensures, Expects
|
||||||
|
#include "gsl_util" // for narrow_cast
|
||||||
|
#include "span" // for operator!=, operator==, dynamic_extent
|
||||||
|
|
||||||
|
#include <algorithm> // for equal, lexicographical_compare
|
||||||
|
#include <array> // for array
|
||||||
|
#include <cstddef> // for ptrdiff_t, size_t, nullptr_t
|
||||||
|
#include <cstdint> // for PTRDIFF_MAX
|
||||||
|
#include <cstring>
|
||||||
|
#include <string> // for basic_string, allocator, char_traits
|
||||||
|
#include <type_traits> // for declval, is_convertible, enable_if_t, add_...
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
|
||||||
|
// blanket turn off warnings from CppCoreCheck for now
|
||||||
|
// so people aren't annoyed by them when running the tool.
|
||||||
|
// more targeted suppressions will be added in a future update to the GSL
|
||||||
|
#pragma warning(disable : 26481 26482 26483 26485 26490 26491 26492 26493 26495)
|
||||||
|
|
||||||
|
#if _MSC_VER < 1910
|
||||||
|
#pragma push_macro("constexpr")
|
||||||
|
#define constexpr /*constexpr*/
|
||||||
|
|
||||||
|
#endif // _MSC_VER < 1910
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
// In order to test the library, we need it to throw exceptions that we can catch
|
||||||
|
#ifdef GSL_THROW_ON_CONTRACT_VIOLATION
|
||||||
|
#define GSL_NOEXCEPT /*noexcept*/
|
||||||
|
#else
|
||||||
|
#define GSL_NOEXCEPT noexcept
|
||||||
|
#endif // GSL_THROW_ON_CONTRACT_VIOLATION
|
||||||
|
|
||||||
|
namespace gsl
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// czstring and wzstring
|
||||||
|
//
|
||||||
|
// These are "tag" typedefs for C-style strings (i.e. null-terminated character arrays)
|
||||||
|
// that allow static analysis to help find bugs.
|
||||||
|
//
|
||||||
|
// There are no additional features/semantics that we can find a way to add inside the
|
||||||
|
// type system for these types that will not either incur significant runtime costs or
|
||||||
|
// (sometimes needlessly) break existing programs when introduced.
|
||||||
|
//
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using basic_zstring = CharT*;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using czstring = basic_zstring<const char, Extent>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using cwzstring = basic_zstring<const wchar_t, Extent>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using cu16zstring = basic_zstring<const char16_t, Extent>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using cu32zstring = basic_zstring<const char32_t, Extent>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using zstring = basic_zstring<char, Extent>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using wzstring = basic_zstring<wchar_t, Extent>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using u16zstring = basic_zstring<char16_t, Extent>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using u32zstring = basic_zstring<char32_t, Extent>;
|
||||||
|
|
||||||
|
namespace details
|
||||||
|
{
|
||||||
|
template <class CharT>
|
||||||
|
std::ptrdiff_t string_length(const CharT* str, std::ptrdiff_t n)
|
||||||
|
{
|
||||||
|
if (str == nullptr || n <= 0) return 0;
|
||||||
|
|
||||||
|
const span<const CharT> str_span{str, n};
|
||||||
|
|
||||||
|
std::ptrdiff_t len = 0;
|
||||||
|
while (len < n && str_span[len]) len++;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ensure_sentinel()
|
||||||
|
//
|
||||||
|
// Provides a way to obtain an span from a contiguous sequence
|
||||||
|
// that ends with a (non-inclusive) sentinel value.
|
||||||
|
//
|
||||||
|
// Will fail-fast if sentinel cannot be found before max elements are examined.
|
||||||
|
//
|
||||||
|
template <typename T, const T Sentinel>
|
||||||
|
span<T, dynamic_extent> ensure_sentinel(T* seq, std::ptrdiff_t max = PTRDIFF_MAX)
|
||||||
|
{
|
||||||
|
auto cur = seq;
|
||||||
|
while ((cur - seq) < max && *cur != Sentinel) ++cur;
|
||||||
|
Ensures(*cur == Sentinel);
|
||||||
|
return {seq, cur - seq};
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ensure_z - creates a span for a zero terminated strings.
|
||||||
|
// Will fail fast if a null-terminator cannot be found before
|
||||||
|
// the limit of size_type.
|
||||||
|
//
|
||||||
|
template <typename CharT>
|
||||||
|
span<CharT, dynamic_extent> ensure_z(CharT* const& sz, std::ptrdiff_t max = PTRDIFF_MAX)
|
||||||
|
{
|
||||||
|
return ensure_sentinel<CharT, CharT(0)>(sz, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, std::size_t N>
|
||||||
|
span<CharT, dynamic_extent> ensure_z(CharT (&sz)[N])
|
||||||
|
{
|
||||||
|
return ensure_z(&sz[0], static_cast<std::ptrdiff_t>(N));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Cont>
|
||||||
|
span<typename std::remove_pointer<typename Cont::pointer>::type, dynamic_extent>
|
||||||
|
ensure_z(Cont& cont)
|
||||||
|
{
|
||||||
|
return ensure_z(cont.data(), static_cast<std::ptrdiff_t>(cont.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t>
|
||||||
|
class basic_string_span;
|
||||||
|
|
||||||
|
namespace details
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
struct is_basic_string_span_oracle : std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent>
|
||||||
|
struct is_basic_string_span_oracle<basic_string_span<CharT, Extent>> : std::true_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_basic_string_span : is_basic_string_span_oracle<std::remove_cv_t<T>>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// string_span and relatives
|
||||||
|
//
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
class basic_string_span
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using element_type = CharT;
|
||||||
|
using pointer = std::add_pointer_t<element_type>;
|
||||||
|
using reference = std::add_lvalue_reference_t<element_type>;
|
||||||
|
using const_reference = std::add_lvalue_reference_t<std::add_const_t<element_type>>;
|
||||||
|
using impl_type = span<element_type, Extent>;
|
||||||
|
|
||||||
|
using index_type = typename impl_type::index_type;
|
||||||
|
using iterator = typename impl_type::iterator;
|
||||||
|
using const_iterator = typename impl_type::const_iterator;
|
||||||
|
using reverse_iterator = typename impl_type::reverse_iterator;
|
||||||
|
using const_reverse_iterator = typename impl_type::const_reverse_iterator;
|
||||||
|
|
||||||
|
// default (empty)
|
||||||
|
constexpr basic_string_span() GSL_NOEXCEPT = default;
|
||||||
|
|
||||||
|
// copy
|
||||||
|
constexpr basic_string_span(const basic_string_span& other) GSL_NOEXCEPT = default;
|
||||||
|
|
||||||
|
// assign
|
||||||
|
constexpr basic_string_span& operator=(const basic_string_span& other) GSL_NOEXCEPT = default;
|
||||||
|
|
||||||
|
constexpr basic_string_span(pointer ptr, index_type length) : span_(ptr, length) {}
|
||||||
|
constexpr basic_string_span(pointer firstElem, pointer lastElem) : span_(firstElem, lastElem) {}
|
||||||
|
|
||||||
|
// From static arrays - if 0-terminated, remove 0 from the view
|
||||||
|
// All other containers allow 0s within the length, so we do not remove them
|
||||||
|
template <std::size_t N>
|
||||||
|
constexpr basic_string_span(element_type (&arr)[N]) : span_(remove_z(arr))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
|
||||||
|
constexpr basic_string_span(std::array<ArrayElementType, N>& arr) GSL_NOEXCEPT : span_(arr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
|
||||||
|
constexpr basic_string_span(const std::array<ArrayElementType, N>& arr) GSL_NOEXCEPT
|
||||||
|
: span_(arr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container signature should work for basic_string after C++17 version exists
|
||||||
|
template <class Traits, class Allocator>
|
||||||
|
constexpr basic_string_span(std::basic_string<element_type, Traits, Allocator>& str)
|
||||||
|
: span_(&str[0], narrow_cast<std::ptrdiff_t>(str.length()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Traits, class Allocator>
|
||||||
|
constexpr basic_string_span(const std::basic_string<element_type, Traits, Allocator>& str)
|
||||||
|
: span_(&str[0], str.length())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// from containers. Containers must have a pointer type and data() function signatures
|
||||||
|
template <class Container,
|
||||||
|
class = std::enable_if_t<
|
||||||
|
!details::is_basic_string_span<Container>::value &&
|
||||||
|
std::is_convertible<typename Container::pointer, pointer>::value &&
|
||||||
|
std::is_convertible<typename Container::pointer,
|
||||||
|
decltype(std::declval<Container>().data())>::value>>
|
||||||
|
constexpr basic_string_span(Container& cont) : span_(cont)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Container,
|
||||||
|
class = std::enable_if_t<
|
||||||
|
!details::is_basic_string_span<Container>::value &&
|
||||||
|
std::is_convertible<typename Container::pointer, pointer>::value &&
|
||||||
|
std::is_convertible<typename Container::pointer,
|
||||||
|
decltype(std::declval<Container>().data())>::value>>
|
||||||
|
constexpr basic_string_span(const Container& cont) : span_(cont)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// from string_span
|
||||||
|
template <
|
||||||
|
class OtherValueType, std::ptrdiff_t OtherExtent,
|
||||||
|
class = std::enable_if_t<std::is_convertible<
|
||||||
|
typename basic_string_span<OtherValueType, OtherExtent>::impl_type, impl_type>::value>>
|
||||||
|
constexpr basic_string_span(basic_string_span<OtherValueType, OtherExtent> other)
|
||||||
|
: span_(other.data(), other.length())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <index_type Count>
|
||||||
|
constexpr basic_string_span<element_type, Count> first() const
|
||||||
|
{
|
||||||
|
return {span_.template first<Count>()};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr basic_string_span<element_type, dynamic_extent> first(index_type count) const
|
||||||
|
{
|
||||||
|
return {span_.first(count)};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <index_type Count>
|
||||||
|
constexpr basic_string_span<element_type, Count> last() const
|
||||||
|
{
|
||||||
|
return {span_.template last<Count>()};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr basic_string_span<element_type, dynamic_extent> last(index_type count) const
|
||||||
|
{
|
||||||
|
return {span_.last(count)};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <index_type Offset, index_type Count>
|
||||||
|
constexpr basic_string_span<element_type, Count> subspan() const
|
||||||
|
{
|
||||||
|
return {span_.template subspan<Offset, Count>()};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr basic_string_span<element_type, dynamic_extent>
|
||||||
|
subspan(index_type offset, index_type count = dynamic_extent) const
|
||||||
|
{
|
||||||
|
return {span_.subspan(offset, count)};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr reference operator[](index_type idx) const { return span_[idx]; }
|
||||||
|
constexpr reference operator()(index_type idx) const { return span_[idx]; }
|
||||||
|
|
||||||
|
constexpr pointer data() const { return span_.data(); }
|
||||||
|
|
||||||
|
constexpr index_type length() const GSL_NOEXCEPT { return span_.size(); }
|
||||||
|
constexpr index_type size() const GSL_NOEXCEPT { return span_.size(); }
|
||||||
|
constexpr index_type size_bytes() const GSL_NOEXCEPT { return span_.size_bytes(); }
|
||||||
|
constexpr index_type length_bytes() const GSL_NOEXCEPT { return span_.length_bytes(); }
|
||||||
|
constexpr bool empty() const GSL_NOEXCEPT { return size() == 0; }
|
||||||
|
|
||||||
|
constexpr iterator begin() const GSL_NOEXCEPT { return span_.begin(); }
|
||||||
|
constexpr iterator end() const GSL_NOEXCEPT { return span_.end(); }
|
||||||
|
|
||||||
|
constexpr const_iterator cbegin() const GSL_NOEXCEPT { return span_.cbegin(); }
|
||||||
|
constexpr const_iterator cend() const GSL_NOEXCEPT { return span_.cend(); }
|
||||||
|
|
||||||
|
constexpr reverse_iterator rbegin() const GSL_NOEXCEPT { return span_.rbegin(); }
|
||||||
|
constexpr reverse_iterator rend() const GSL_NOEXCEPT { return span_.rend(); }
|
||||||
|
|
||||||
|
constexpr const_reverse_iterator crbegin() const GSL_NOEXCEPT { return span_.crbegin(); }
|
||||||
|
constexpr const_reverse_iterator crend() const GSL_NOEXCEPT { return span_.crend(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static impl_type remove_z(pointer const& sz, std::ptrdiff_t max)
|
||||||
|
{
|
||||||
|
return {sz, details::string_length(sz, max)};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t N>
|
||||||
|
static impl_type remove_z(element_type (&sz)[N])
|
||||||
|
{
|
||||||
|
return remove_z(&sz[0], narrow_cast<std::ptrdiff_t>(N));
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_type span_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using string_span = basic_string_span<char, Extent>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using cstring_span = basic_string_span<const char, Extent>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using wstring_span = basic_string_span<wchar_t, Extent>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using cwstring_span = basic_string_span<const wchar_t, Extent>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using u16string_span = basic_string_span<char16_t, Extent>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using cu16string_span = basic_string_span<const char16_t, Extent>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using u32string_span = basic_string_span<char32_t, Extent>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
using cu32string_span = basic_string_span<const char32_t, Extent>;
|
||||||
|
|
||||||
|
//
|
||||||
|
// to_string() allow (explicit) conversions from string_span to string
|
||||||
|
//
|
||||||
|
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent>
|
||||||
|
std::basic_string<typename std::remove_const<CharT>::type>
|
||||||
|
to_string(basic_string_span<CharT, Extent> view)
|
||||||
|
{
|
||||||
|
return {view.data(), static_cast<std::size_t>(view.length())};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT, typename Traits = typename std::char_traits<CharT>,
|
||||||
|
typename Allocator = std::allocator<CharT>, typename gCharT, std::ptrdiff_t Extent>
|
||||||
|
std::basic_string<CharT, Traits, Allocator> to_basic_string(basic_string_span<gCharT, Extent> view)
|
||||||
|
{
|
||||||
|
return {view.data(), static_cast<std::size_t>(view.length())};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent>
|
||||||
|
basic_string_span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||||
|
as_bytes(basic_string_span<ElementType, Extent> s) noexcept
|
||||||
|
{
|
||||||
|
return { reinterpret_cast<const byte*>(s.data()), s.size_bytes() };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent,
|
||||||
|
class = std::enable_if_t<!std::is_const<ElementType>::value>>
|
||||||
|
basic_string_span<byte, details::calculate_byte_size<ElementType, Extent>::value>
|
||||||
|
as_writeable_bytes(basic_string_span<ElementType, Extent> s) noexcept
|
||||||
|
{
|
||||||
|
return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
|
||||||
|
}
|
||||||
|
|
||||||
|
// zero-terminated string span, used to convert
|
||||||
|
// zero-terminated spans to legacy strings
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = dynamic_extent>
|
||||||
|
class basic_zstring_span
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = CharT;
|
||||||
|
using const_value_type = std::add_const_t<CharT>;
|
||||||
|
|
||||||
|
using pointer = std::add_pointer_t<value_type>;
|
||||||
|
using const_pointer = std::add_pointer_t<const_value_type>;
|
||||||
|
|
||||||
|
using zstring_type = basic_zstring<value_type, Extent>;
|
||||||
|
using const_zstring_type = basic_zstring<const_value_type, Extent>;
|
||||||
|
|
||||||
|
using impl_type = span<value_type, Extent>;
|
||||||
|
using string_span_type = basic_string_span<value_type, Extent>;
|
||||||
|
|
||||||
|
constexpr basic_zstring_span(impl_type s) GSL_NOEXCEPT : span_(s)
|
||||||
|
{
|
||||||
|
// expects a zero-terminated span
|
||||||
|
Expects(s[s.size() - 1] == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy
|
||||||
|
constexpr basic_zstring_span(const basic_zstring_span& other) = default;
|
||||||
|
|
||||||
|
// move
|
||||||
|
constexpr basic_zstring_span(basic_zstring_span&& other) = default;
|
||||||
|
|
||||||
|
// assign
|
||||||
|
constexpr basic_zstring_span& operator=(const basic_zstring_span& other) = default;
|
||||||
|
|
||||||
|
// move assign
|
||||||
|
constexpr basic_zstring_span& operator=(basic_zstring_span&& other) = default;
|
||||||
|
|
||||||
|
constexpr bool empty() const GSL_NOEXCEPT { return span_.size() == 0; }
|
||||||
|
|
||||||
|
constexpr string_span_type as_string_span() const GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
auto sz = span_.size();
|
||||||
|
return { span_.data(), sz > 1 ? sz - 1 : 0 };
|
||||||
|
}
|
||||||
|
constexpr string_span_type ensure_z() const GSL_NOEXCEPT { return gsl::ensure_z(span_); }
|
||||||
|
|
||||||
|
constexpr const_zstring_type assume_z() const GSL_NOEXCEPT { return span_.data(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
impl_type span_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Max = dynamic_extent>
|
||||||
|
using zstring_span = basic_zstring_span<char, Max>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Max = dynamic_extent>
|
||||||
|
using wzstring_span = basic_zstring_span<wchar_t, Max>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Max = dynamic_extent>
|
||||||
|
using u16zstring_span = basic_zstring_span<char16_t, Max>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Max = dynamic_extent>
|
||||||
|
using u32zstring_span = basic_zstring_span<char32_t, Max>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Max = dynamic_extent>
|
||||||
|
using czstring_span = basic_zstring_span<const char, Max>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Max = dynamic_extent>
|
||||||
|
using cwzstring_span = basic_zstring_span<const wchar_t, Max>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Max = dynamic_extent>
|
||||||
|
using cu16zstring_span = basic_zstring_span<const char16_t, Max>;
|
||||||
|
|
||||||
|
template <std::ptrdiff_t Max = dynamic_extent>
|
||||||
|
using cu32zstring_span = basic_zstring_span<const char32_t, Max>;
|
||||||
|
|
||||||
|
// operator ==
|
||||||
|
template <class CharT, std::ptrdiff_t Extent, class T,
|
||||||
|
class = std::enable_if_t<
|
||||||
|
details::is_basic_string_span<T>::value ||
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>>>::value>>
|
||||||
|
bool operator==(const gsl::basic_string_span<CharT, Extent>& one, const T& other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
const gsl::basic_string_span<std::add_const_t<CharT>> tmp(other);
|
||||||
|
return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class CharT, std::ptrdiff_t Extent, class T,
|
||||||
|
class = std::enable_if_t<
|
||||||
|
!details::is_basic_string_span<T>::value &&
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>>>::value>>
|
||||||
|
bool operator==(const T& one, const gsl::basic_string_span<CharT, Extent>& other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
gsl::basic_string_span<std::add_const_t<CharT>> tmp(one);
|
||||||
|
return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// operator !=
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename = std::enable_if_t<std::is_convertible<
|
||||||
|
T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
|
||||||
|
bool operator!=(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return !(one == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
|
||||||
|
!gsl::details::is_basic_string_span<T>::value>>
|
||||||
|
bool operator!=(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return !(one == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
// operator<
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename = std::enable_if_t<std::is_convertible<
|
||||||
|
T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
|
||||||
|
bool operator<(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
const gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other);
|
||||||
|
return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
|
||||||
|
!gsl::details::is_basic_string_span<T>::value>>
|
||||||
|
bool operator<(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one);
|
||||||
|
return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
|
// so the cases below are already covered by the previous operators
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||||
|
std::is_convertible<DataType*, CharT*>::value &&
|
||||||
|
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||||
|
DataType>::value>>
|
||||||
|
bool operator<(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(other);
|
||||||
|
return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||||
|
std::is_convertible<DataType*, CharT*>::value &&
|
||||||
|
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||||
|
DataType>::value>>
|
||||||
|
bool operator<(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
gsl::basic_string_span<std::add_const_t<CharT>, Extent> tmp(one);
|
||||||
|
return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// operator <=
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename = std::enable_if_t<std::is_convertible<
|
||||||
|
T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
|
||||||
|
bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return !(other < one);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
|
||||||
|
!gsl::details::is_basic_string_span<T>::value>>
|
||||||
|
bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return !(other < one);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
|
// so the cases below are already covered by the previous operators
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||||
|
std::is_convertible<DataType*, CharT*>::value &&
|
||||||
|
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||||
|
DataType>::value>>
|
||||||
|
bool operator<=(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return !(other < one);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||||
|
std::is_convertible<DataType*, CharT*>::value &&
|
||||||
|
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||||
|
DataType>::value>>
|
||||||
|
bool operator<=(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return !(other < one);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// operator>
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename = std::enable_if_t<std::is_convertible<
|
||||||
|
T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
|
||||||
|
bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return other < one;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
|
||||||
|
!gsl::details::is_basic_string_span<T>::value>>
|
||||||
|
bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return other < one;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
|
// so the cases below are already covered by the previous operators
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||||
|
std::is_convertible<DataType*, CharT*>::value &&
|
||||||
|
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||||
|
DataType>::value>>
|
||||||
|
bool operator>(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return other < one;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||||
|
std::is_convertible<DataType*, CharT*>::value &&
|
||||||
|
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||||
|
DataType>::value>>
|
||||||
|
bool operator>(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return other < one;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// operator >=
|
||||||
|
template <typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename = std::enable_if_t<std::is_convertible<
|
||||||
|
T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value>>
|
||||||
|
bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return !(one < other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
std::is_convertible<T, gsl::basic_string_span<std::add_const_t<CharT>, Extent>>::value &&
|
||||||
|
!gsl::details::is_basic_string_span<T>::value>>
|
||||||
|
bool operator>=(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return !(one < other);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
|
// VS treats temp and const containers as convertible to basic_string_span,
|
||||||
|
// so the cases below are already covered by the previous operators
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||||
|
std::is_convertible<DataType*, CharT*>::value &&
|
||||||
|
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||||
|
DataType>::value>>
|
||||||
|
bool operator>=(gsl::basic_string_span<CharT, Extent> one, const T& other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return !(one < other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename CharT, std::ptrdiff_t Extent = gsl::dynamic_extent, typename T,
|
||||||
|
typename DataType = typename T::value_type,
|
||||||
|
typename = std::enable_if_t<
|
||||||
|
!gsl::details::is_span<T>::value && !gsl::details::is_basic_string_span<T>::value &&
|
||||||
|
std::is_convertible<DataType*, CharT*>::value &&
|
||||||
|
std::is_same<std::decay_t<decltype(std::declval<T>().size(), *std::declval<T>().data())>,
|
||||||
|
DataType>::value>>
|
||||||
|
bool operator>=(const T& one, gsl::basic_string_span<CharT, Extent> other) GSL_NOEXCEPT
|
||||||
|
{
|
||||||
|
return !(one < other);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace gsl
|
||||||
|
|
||||||
|
#undef GSL_NOEXCEPT
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
|
||||||
|
#if _MSC_VER < 1910
|
||||||
|
#undef constexpr
|
||||||
|
#pragma pop_macro("constexpr")
|
||||||
|
|
||||||
|
#endif // _MSC_VER < 1910
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
#endif // GSL_STRING_SPAN_H
|
40
src/deps/stduuid/how_to_build.md
Normal file
40
src/deps/stduuid/how_to_build.md
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# How to build
|
||||||
|
|
||||||
|
You can create projects to build the tests for the uuid library using CMake.
|
||||||
|
|
||||||
|
If you don't have CMake installed you can get it from https://cmake.org/.
|
||||||
|
|
||||||
|
## Windows
|
||||||
|
|
||||||
|
Do the Following:
|
||||||
|
|
||||||
|
* Create a folder called **build**
|
||||||
|
```
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
```
|
||||||
|
|
||||||
|
* Run the following CMake command from the **build** folder to generate projects to target the **x86** platform.
|
||||||
|
```
|
||||||
|
cmake -G "Visual Studio 15 2017" ..
|
||||||
|
```
|
||||||
|
|
||||||
|
To generate projects to target **x64** use the generator **"Visual Studio 15 2017 Win64"**.
|
||||||
|
|
||||||
|
To generate projects to target **ARM** use the generator **"Visual Studio 15 2017 ARM"**.
|
||||||
|
|
||||||
|
|
||||||
|
## Mac
|
||||||
|
|
||||||
|
Do the Following:
|
||||||
|
|
||||||
|
* Create a folder called **build**
|
||||||
|
```
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
```
|
||||||
|
|
||||||
|
* Run the following CMake command from the **build** folder to generate projects to target the **x86** platform.
|
||||||
|
```
|
||||||
|
cmake -G Xcode ..
|
||||||
|
```
|
943
src/deps/stduuid/include/uuid.h
Normal file
943
src/deps/stduuid/include/uuid.h
Normal file
|
@ -0,0 +1,943 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <array>
|
||||||
|
#include <string_view>
|
||||||
|
#include <iterator>
|
||||||
|
#include <random>
|
||||||
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <optional>
|
||||||
|
#include <chrono>
|
||||||
|
#include <numeric>
|
||||||
|
#include <atomic>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
#define NOMINMAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef UUID_SYSTEM_GENERATOR
|
||||||
|
#include <objbase.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <intrin.h>
|
||||||
|
#include <iphlpapi.h>
|
||||||
|
#pragma comment(lib, "IPHLPAPI.lib")
|
||||||
|
|
||||||
|
#elif defined(__linux__) || defined(__unix__)
|
||||||
|
|
||||||
|
#ifdef UUID_SYSTEM_GENERATOR
|
||||||
|
#include <uuid/uuid.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
|
||||||
|
#ifdef UUID_SYSTEM_GENERATOR
|
||||||
|
#include <CoreFoundation/CFUUID.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace uuids
|
||||||
|
{
|
||||||
|
#ifdef __cpp_lib_span
|
||||||
|
template <class ElementType, std::size_t Extent>
|
||||||
|
using span = std::span<ElementType, Extent>;
|
||||||
|
#else
|
||||||
|
template <class ElementType, std::ptrdiff_t Extent>
|
||||||
|
using span = gsl::span<ElementType, Extent>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
template <typename TChar>
|
||||||
|
constexpr inline unsigned char hex2char(TChar const ch)
|
||||||
|
{
|
||||||
|
if (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9'))
|
||||||
|
return ch - static_cast<TChar>('0');
|
||||||
|
if (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f'))
|
||||||
|
return 10 + ch - static_cast<TChar>('a');
|
||||||
|
if (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F'))
|
||||||
|
return 10 + ch - static_cast<TChar>('A');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TChar>
|
||||||
|
constexpr inline bool is_hex(TChar const ch)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9')) ||
|
||||||
|
(ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f')) ||
|
||||||
|
(ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F'));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TChar>
|
||||||
|
constexpr inline unsigned char hexpair2char(TChar const a, TChar const b)
|
||||||
|
{
|
||||||
|
return (hex2char(a) << 4) | hex2char(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
class sha1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using digest32_t = uint32_t[5];
|
||||||
|
using digest8_t = uint8_t[20];
|
||||||
|
|
||||||
|
static constexpr unsigned int block_bytes = 64;
|
||||||
|
|
||||||
|
inline static uint32_t left_rotate(uint32_t value, size_t const count)
|
||||||
|
{
|
||||||
|
return (value << count) ^ (value >> (32 - count));
|
||||||
|
}
|
||||||
|
|
||||||
|
sha1() { reset(); }
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
m_digest[0] = 0x67452301;
|
||||||
|
m_digest[1] = 0xEFCDAB89;
|
||||||
|
m_digest[2] = 0x98BADCFE;
|
||||||
|
m_digest[3] = 0x10325476;
|
||||||
|
m_digest[4] = 0xC3D2E1F0;
|
||||||
|
m_blockByteIndex = 0;
|
||||||
|
m_byteCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_byte(uint8_t octet)
|
||||||
|
{
|
||||||
|
this->m_block[this->m_blockByteIndex++] = octet;
|
||||||
|
++this->m_byteCount;
|
||||||
|
if (m_blockByteIndex == block_bytes)
|
||||||
|
{
|
||||||
|
this->m_blockByteIndex = 0;
|
||||||
|
process_block();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_block(void const * const start, void const * const end)
|
||||||
|
{
|
||||||
|
const uint8_t* begin = static_cast<const uint8_t*>(start);
|
||||||
|
const uint8_t* finish = static_cast<const uint8_t*>(end);
|
||||||
|
while (begin != finish)
|
||||||
|
{
|
||||||
|
process_byte(*begin);
|
||||||
|
begin++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_bytes(void const * const data, size_t const len)
|
||||||
|
{
|
||||||
|
const uint8_t* block = static_cast<const uint8_t*>(data);
|
||||||
|
process_block(block, block + len);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t const * get_digest(digest32_t digest)
|
||||||
|
{
|
||||||
|
size_t const bitCount = this->m_byteCount * 8;
|
||||||
|
process_byte(0x80);
|
||||||
|
if (this->m_blockByteIndex > 56) {
|
||||||
|
while (m_blockByteIndex != 0) {
|
||||||
|
process_byte(0);
|
||||||
|
}
|
||||||
|
while (m_blockByteIndex < 56) {
|
||||||
|
process_byte(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
while (m_blockByteIndex < 56) {
|
||||||
|
process_byte(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
process_byte(0);
|
||||||
|
process_byte(0);
|
||||||
|
process_byte(0);
|
||||||
|
process_byte(0);
|
||||||
|
process_byte(static_cast<unsigned char>((bitCount >> 24) & 0xFF));
|
||||||
|
process_byte(static_cast<unsigned char>((bitCount >> 16) & 0xFF));
|
||||||
|
process_byte(static_cast<unsigned char>((bitCount >> 8) & 0xFF));
|
||||||
|
process_byte(static_cast<unsigned char>((bitCount) & 0xFF));
|
||||||
|
|
||||||
|
memcpy(digest, m_digest, 5 * sizeof(uint32_t));
|
||||||
|
return digest;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t const * get_digest_bytes(digest8_t digest)
|
||||||
|
{
|
||||||
|
digest32_t d32;
|
||||||
|
get_digest(d32);
|
||||||
|
size_t di = 0;
|
||||||
|
digest[di++] = (uint8_t)(d32[0] >> 24);
|
||||||
|
digest[di++] = (uint8_t)(d32[0] >> 16);
|
||||||
|
digest[di++] = (uint8_t)(d32[0] >> 8);
|
||||||
|
digest[di++] = (uint8_t)(d32[0] >> 0);
|
||||||
|
|
||||||
|
digest[di++] = (uint8_t)(d32[1] >> 24);
|
||||||
|
digest[di++] = (uint8_t)(d32[1] >> 16);
|
||||||
|
digest[di++] = (uint8_t)(d32[1] >> 8);
|
||||||
|
digest[di++] = (uint8_t)(d32[1] >> 0);
|
||||||
|
|
||||||
|
digest[di++] = (uint8_t)(d32[2] >> 24);
|
||||||
|
digest[di++] = (uint8_t)(d32[2] >> 16);
|
||||||
|
digest[di++] = (uint8_t)(d32[2] >> 8);
|
||||||
|
digest[di++] = (uint8_t)(d32[2] >> 0);
|
||||||
|
|
||||||
|
digest[di++] = (uint8_t)(d32[3] >> 24);
|
||||||
|
digest[di++] = (uint8_t)(d32[3] >> 16);
|
||||||
|
digest[di++] = (uint8_t)(d32[3] >> 8);
|
||||||
|
digest[di++] = (uint8_t)(d32[3] >> 0);
|
||||||
|
|
||||||
|
digest[di++] = (uint8_t)(d32[4] >> 24);
|
||||||
|
digest[di++] = (uint8_t)(d32[4] >> 16);
|
||||||
|
digest[di++] = (uint8_t)(d32[4] >> 8);
|
||||||
|
digest[di++] = (uint8_t)(d32[4] >> 0);
|
||||||
|
|
||||||
|
return digest;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void process_block()
|
||||||
|
{
|
||||||
|
uint32_t w[80];
|
||||||
|
for (size_t i = 0; i < 16; i++) {
|
||||||
|
w[i] = (m_block[i * 4 + 0] << 24);
|
||||||
|
w[i] |= (m_block[i * 4 + 1] << 16);
|
||||||
|
w[i] |= (m_block[i * 4 + 2] << 8);
|
||||||
|
w[i] |= (m_block[i * 4 + 3]);
|
||||||
|
}
|
||||||
|
for (size_t i = 16; i < 80; i++) {
|
||||||
|
w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t a = m_digest[0];
|
||||||
|
uint32_t b = m_digest[1];
|
||||||
|
uint32_t c = m_digest[2];
|
||||||
|
uint32_t d = m_digest[3];
|
||||||
|
uint32_t e = m_digest[4];
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < 80; ++i)
|
||||||
|
{
|
||||||
|
uint32_t f = 0;
|
||||||
|
uint32_t k = 0;
|
||||||
|
|
||||||
|
if (i < 20) {
|
||||||
|
f = (b & c) | (~b & d);
|
||||||
|
k = 0x5A827999;
|
||||||
|
}
|
||||||
|
else if (i < 40) {
|
||||||
|
f = b ^ c ^ d;
|
||||||
|
k = 0x6ED9EBA1;
|
||||||
|
}
|
||||||
|
else if (i < 60) {
|
||||||
|
f = (b & c) | (b & d) | (c & d);
|
||||||
|
k = 0x8F1BBCDC;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f = b ^ c ^ d;
|
||||||
|
k = 0xCA62C1D6;
|
||||||
|
}
|
||||||
|
uint32_t temp = left_rotate(a, 5) + f + e + k + w[i];
|
||||||
|
e = d;
|
||||||
|
d = c;
|
||||||
|
c = left_rotate(b, 30);
|
||||||
|
b = a;
|
||||||
|
a = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_digest[0] += a;
|
||||||
|
m_digest[1] += b;
|
||||||
|
m_digest[2] += c;
|
||||||
|
m_digest[3] += d;
|
||||||
|
m_digest[4] += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
digest32_t m_digest;
|
||||||
|
uint8_t m_block[64];
|
||||||
|
size_t m_blockByteIndex;
|
||||||
|
size_t m_byteCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::mt19937 clock_gen(std::random_device{}());
|
||||||
|
static std::uniform_int_distribution<short> clock_dis{ -32768, 32767 };
|
||||||
|
static std::atomic_short clock_sequence = clock_dis(clock_gen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// UUID format https://tools.ietf.org/html/rfc4122
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Field NDR Data Type Octet # Note
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// time_low unsigned long 0 - 3 The low field of the timestamp.
|
||||||
|
// time_mid unsigned short 4 - 5 The middle field of the timestamp.
|
||||||
|
// time_hi_and_version unsigned short 6 - 7 The high field of the timestamp multiplexed with the version number.
|
||||||
|
// clock_seq_hi_and_reserved unsigned small 8 The high field of the clock sequence multiplexed with the variant.
|
||||||
|
// clock_seq_low unsigned small 9 The low field of the clock sequence.
|
||||||
|
// node character 10 - 15 The spatially unique node identifier.
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// 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) |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// enumerations
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// indicated by a bit pattern in octet 8, marked with N in xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx
|
||||||
|
enum class uuid_variant
|
||||||
|
{
|
||||||
|
// NCS backward compatibility (with the obsolete Apollo Network Computing System 1.5 UUID format)
|
||||||
|
// N bit pattern: 0xxx
|
||||||
|
// > the first 6 octets of the UUID are a 48-bit timestamp (the number of 4 microsecond units of time since 1 Jan 1980 UTC);
|
||||||
|
// > the next 2 octets are reserved;
|
||||||
|
// > the next octet is the "address family";
|
||||||
|
// > the final 7 octets are a 56-bit host ID in the form specified by the address family
|
||||||
|
ncs,
|
||||||
|
|
||||||
|
// RFC 4122/DCE 1.1
|
||||||
|
// N bit pattern: 10xx
|
||||||
|
// > big-endian byte order
|
||||||
|
rfc,
|
||||||
|
|
||||||
|
// Microsoft Corporation backward compatibility
|
||||||
|
// N bit pattern: 110x
|
||||||
|
// > little endian byte order
|
||||||
|
// > formely used in the Component Object Model (COM) library
|
||||||
|
microsoft,
|
||||||
|
|
||||||
|
// reserved for possible future definition
|
||||||
|
// N bit pattern: 111x
|
||||||
|
reserved
|
||||||
|
};
|
||||||
|
|
||||||
|
// indicated by a bit pattern in octet 6, marked with M in xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
enum class uuid_version
|
||||||
|
{
|
||||||
|
none = 0, // only possible for nil or invalid uuids
|
||||||
|
time_based = 1, // The time-based version specified in RFC 4122
|
||||||
|
dce_security = 2, // DCE Security version, with embedded POSIX UIDs.
|
||||||
|
name_based_md5 = 3, // The name-based version specified in RFS 4122 with MD5 hashing
|
||||||
|
random_number_based = 4, // The randomly or pseudo-randomly generated version specified in RFS 4122
|
||||||
|
name_based_sha1 = 5 // The name-based version specified in RFS 4122 with SHA1 hashing
|
||||||
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// uuid class
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------------
|
||||||
|
class uuid
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = uint8_t;
|
||||||
|
|
||||||
|
constexpr uuid() noexcept : data({}) {};
|
||||||
|
|
||||||
|
uuid(value_type(&arr)[16]) noexcept
|
||||||
|
{
|
||||||
|
std::copy(std::cbegin(arr), std::cend(arr), std::begin(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
uuid(std::array<value_type, 16> const & arr) noexcept
|
||||||
|
{
|
||||||
|
std::copy(std::cbegin(arr), std::cend(arr), std::begin(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit uuid(span<value_type, 16> bytes)
|
||||||
|
{
|
||||||
|
std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ForwardIterator>
|
||||||
|
explicit uuid(ForwardIterator first, ForwardIterator last)
|
||||||
|
{
|
||||||
|
if (std::distance(first, last) == 16)
|
||||||
|
std::copy(first, last, std::begin(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr uuid_variant variant() const noexcept
|
||||||
|
{
|
||||||
|
if ((data[8] & 0x80) == 0x00)
|
||||||
|
return uuid_variant::ncs;
|
||||||
|
else if ((data[8] & 0xC0) == 0x80)
|
||||||
|
return uuid_variant::rfc;
|
||||||
|
else if ((data[8] & 0xE0) == 0xC0)
|
||||||
|
return uuid_variant::microsoft;
|
||||||
|
else
|
||||||
|
return uuid_variant::reserved;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr uuid_version version() const noexcept
|
||||||
|
{
|
||||||
|
if ((data[6] & 0xF0) == 0x10)
|
||||||
|
return uuid_version::time_based;
|
||||||
|
else if ((data[6] & 0xF0) == 0x20)
|
||||||
|
return uuid_version::dce_security;
|
||||||
|
else if ((data[6] & 0xF0) == 0x30)
|
||||||
|
return uuid_version::name_based_md5;
|
||||||
|
else if ((data[6] & 0xF0) == 0x40)
|
||||||
|
return uuid_version::random_number_based;
|
||||||
|
else if ((data[6] & 0xF0) == 0x50)
|
||||||
|
return uuid_version::name_based_sha1;
|
||||||
|
else
|
||||||
|
return uuid_version::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_nil() const noexcept
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < data.size(); ++i) if (data[i] != 0) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(uuid & other) noexcept
|
||||||
|
{
|
||||||
|
data.swap(other.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline span<std::byte const, 16> as_bytes() const
|
||||||
|
{
|
||||||
|
return span<std::byte const, 16>(reinterpret_cast<std::byte const*>(data.data()), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class CharT = char>
|
||||||
|
static bool is_valid_uuid(CharT const * str) noexcept
|
||||||
|
{
|
||||||
|
bool firstDigit = true;
|
||||||
|
int hasBraces = 0;
|
||||||
|
size_t index = 0;
|
||||||
|
size_t size = 0;
|
||||||
|
if constexpr(std::is_same_v<CharT, char>)
|
||||||
|
size = strlen(str);
|
||||||
|
else
|
||||||
|
size = wcslen(str);
|
||||||
|
|
||||||
|
if (str == nullptr || size == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (str[0] == static_cast<CharT>('{'))
|
||||||
|
hasBraces = 1;
|
||||||
|
if (hasBraces && str[size - 1] != static_cast<CharT>('}'))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = hasBraces; i < size - hasBraces; ++i)
|
||||||
|
{
|
||||||
|
if (str[i] == static_cast<CharT>('-')) continue;
|
||||||
|
|
||||||
|
if (index >= 16 || !detail::is_hex(str[i]))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstDigit)
|
||||||
|
{
|
||||||
|
firstDigit = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
firstDigit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < 16)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
static bool is_valid_uuid(std::basic_string<CharT, Traits, Allocator> const & str) noexcept
|
||||||
|
{
|
||||||
|
return is_valid_uuid(str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class CharT = char>
|
||||||
|
static std::optional<uuid> from_string(CharT const * str) noexcept
|
||||||
|
{
|
||||||
|
CharT digit = 0;
|
||||||
|
bool firstDigit = true;
|
||||||
|
int hasBraces = 0;
|
||||||
|
size_t index = 0;
|
||||||
|
size_t size = 0;
|
||||||
|
if constexpr(std::is_same_v<CharT, char>)
|
||||||
|
size = strlen(str);
|
||||||
|
else
|
||||||
|
size = wcslen(str);
|
||||||
|
|
||||||
|
std::array<uint8_t, 16> data{ { 0 } };
|
||||||
|
|
||||||
|
if (str == nullptr || size == 0) return {};
|
||||||
|
|
||||||
|
if (str[0] == static_cast<CharT>('{'))
|
||||||
|
hasBraces = 1;
|
||||||
|
if (hasBraces && str[size - 1] != static_cast<CharT>('}'))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
for (size_t i = hasBraces; i < size - hasBraces; ++i)
|
||||||
|
{
|
||||||
|
if (str[i] == static_cast<CharT>('-')) continue;
|
||||||
|
|
||||||
|
if (index >= 16 || !detail::is_hex(str[i]))
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstDigit)
|
||||||
|
{
|
||||||
|
digit = str[i];
|
||||||
|
firstDigit = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data[index++] = detail::hexpair2char(digit, str[i]);
|
||||||
|
firstDigit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < 16)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return uuid{ std::cbegin(data), std::cend(data) };
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
static std::optional<uuid> from_string(std::basic_string<CharT, Traits, Allocator> const & str) noexcept
|
||||||
|
{
|
||||||
|
return from_string(str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<value_type, 16> data{ { 0 } };
|
||||||
|
|
||||||
|
friend bool operator==(uuid const & lhs, uuid const & rhs) noexcept;
|
||||||
|
friend bool operator<(uuid const & lhs, uuid const & rhs) noexcept;
|
||||||
|
|
||||||
|
template <class Elem, class Traits>
|
||||||
|
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
|
||||||
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// operators and non-member functions
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
inline bool operator== (uuid const& lhs, uuid const& rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.data == rhs.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!= (uuid const& lhs, uuid const& rhs) noexcept
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator< (uuid const& lhs, uuid const& rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.data < rhs.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Elem, class Traits>
|
||||||
|
std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id)
|
||||||
|
{
|
||||||
|
// save current flags
|
||||||
|
std::ios_base::fmtflags f(s.flags());
|
||||||
|
|
||||||
|
// manipulate stream as needed
|
||||||
|
s << std::hex << std::setfill(static_cast<Elem>('0'))
|
||||||
|
<< std::setw(2) << (int)id.data[0]
|
||||||
|
<< std::setw(2) << (int)id.data[1]
|
||||||
|
<< std::setw(2) << (int)id.data[2]
|
||||||
|
<< std::setw(2) << (int)id.data[3]
|
||||||
|
<< '-'
|
||||||
|
<< std::setw(2) << (int)id.data[4]
|
||||||
|
<< std::setw(2) << (int)id.data[5]
|
||||||
|
<< '-'
|
||||||
|
<< std::setw(2) << (int)id.data[6]
|
||||||
|
<< std::setw(2) << (int)id.data[7]
|
||||||
|
<< '-'
|
||||||
|
<< std::setw(2) << (int)id.data[8]
|
||||||
|
<< std::setw(2) << (int)id.data[9]
|
||||||
|
<< '-'
|
||||||
|
<< std::setw(2) << (int)id.data[10]
|
||||||
|
<< std::setw(2) << (int)id.data[11]
|
||||||
|
<< std::setw(2) << (int)id.data[12]
|
||||||
|
<< std::setw(2) << (int)id.data[13]
|
||||||
|
<< std::setw(2) << (int)id.data[14]
|
||||||
|
<< std::setw(2) << (int)id.data[15];
|
||||||
|
|
||||||
|
// restore original flags
|
||||||
|
s.flags(f);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
inline std::basic_string<CharT, Traits, Allocator> to_string(uuid const & id)
|
||||||
|
{
|
||||||
|
std::basic_stringstream<CharT, Traits, Allocator> sstr;
|
||||||
|
sstr << id;
|
||||||
|
return sstr.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void swap(uuids::uuid & lhs, uuids::uuid & rhs) noexcept
|
||||||
|
{
|
||||||
|
lhs.swap(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// namespace IDs that could be used for generating name-based uuids
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Name string is a fully-qualified domain name
|
||||||
|
static uuid uuid_namespace_dns{ {0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
|
||||||
|
|
||||||
|
// Name string is a URL
|
||||||
|
static uuid uuid_namespace_url{ {0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
|
||||||
|
|
||||||
|
// Name string is an ISO OID (See https://oidref.com/, https://en.wikipedia.org/wiki/Object_identifier)
|
||||||
|
static uuid uuid_namespace_oid{ {0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
static uuid uuid_namespace_x500{ {0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// uuid generators
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef UUID_SYSTEM_GENERATOR
|
||||||
|
class uuid_system_generator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using result_type = uuid;
|
||||||
|
|
||||||
|
uuid operator()()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
GUID newId;
|
||||||
|
::CoCreateGuid(&newId);
|
||||||
|
|
||||||
|
std::array<uint8_t, 16> bytes =
|
||||||
|
{ {
|
||||||
|
(unsigned char)((newId.Data1 >> 24) & 0xFF),
|
||||||
|
(unsigned char)((newId.Data1 >> 16) & 0xFF),
|
||||||
|
(unsigned char)((newId.Data1 >> 8) & 0xFF),
|
||||||
|
(unsigned char)((newId.Data1) & 0xFF),
|
||||||
|
|
||||||
|
(unsigned char)((newId.Data2 >> 8) & 0xFF),
|
||||||
|
(unsigned char)((newId.Data2) & 0xFF),
|
||||||
|
|
||||||
|
(unsigned char)((newId.Data3 >> 8) & 0xFF),
|
||||||
|
(unsigned char)((newId.Data3) & 0xFF),
|
||||||
|
|
||||||
|
newId.Data4[0],
|
||||||
|
newId.Data4[1],
|
||||||
|
newId.Data4[2],
|
||||||
|
newId.Data4[3],
|
||||||
|
newId.Data4[4],
|
||||||
|
newId.Data4[5],
|
||||||
|
newId.Data4[6],
|
||||||
|
newId.Data4[7]
|
||||||
|
} };
|
||||||
|
|
||||||
|
return uuid{ std::begin(bytes), std::end(bytes) };
|
||||||
|
|
||||||
|
#elif defined(__linux__) || defined(__unix__)
|
||||||
|
|
||||||
|
uuid_t id;
|
||||||
|
uuid_generate(id);
|
||||||
|
|
||||||
|
std::array<uint8_t, 16> bytes =
|
||||||
|
{ {
|
||||||
|
id[0],
|
||||||
|
id[1],
|
||||||
|
id[2],
|
||||||
|
id[3],
|
||||||
|
id[4],
|
||||||
|
id[5],
|
||||||
|
id[6],
|
||||||
|
id[7],
|
||||||
|
id[8],
|
||||||
|
id[9],
|
||||||
|
id[10],
|
||||||
|
id[11],
|
||||||
|
id[12],
|
||||||
|
id[13],
|
||||||
|
id[14],
|
||||||
|
id[15]
|
||||||
|
} };
|
||||||
|
|
||||||
|
return uuid{ std::begin(bytes), std::end(bytes) };
|
||||||
|
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
auto newId = CFUUIDCreate(NULL);
|
||||||
|
auto bytes = CFUUIDGetUUIDBytes(newId);
|
||||||
|
CFRelease(newId);
|
||||||
|
|
||||||
|
std::array<uint8_t, 16> arrbytes =
|
||||||
|
{ {
|
||||||
|
bytes.byte0,
|
||||||
|
bytes.byte1,
|
||||||
|
bytes.byte2,
|
||||||
|
bytes.byte3,
|
||||||
|
bytes.byte4,
|
||||||
|
bytes.byte5,
|
||||||
|
bytes.byte6,
|
||||||
|
bytes.byte7,
|
||||||
|
bytes.byte8,
|
||||||
|
bytes.byte9,
|
||||||
|
bytes.byte10,
|
||||||
|
bytes.byte11,
|
||||||
|
bytes.byte12,
|
||||||
|
bytes.byte13,
|
||||||
|
bytes.byte14,
|
||||||
|
bytes.byte15
|
||||||
|
} };
|
||||||
|
return uuid{ std::begin(arrbytes), std::end(arrbytes) };
|
||||||
|
#else
|
||||||
|
return uuid{};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename UniformRandomNumberGenerator>
|
||||||
|
class basic_uuid_random_generator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using engine_type = UniformRandomNumberGenerator;
|
||||||
|
|
||||||
|
explicit basic_uuid_random_generator(engine_type& gen) :
|
||||||
|
generator(&gen, [](auto) {}) {}
|
||||||
|
explicit basic_uuid_random_generator(engine_type* gen) :
|
||||||
|
generator(gen, [](auto) {}) {}
|
||||||
|
|
||||||
|
uuid operator()()
|
||||||
|
{
|
||||||
|
uint8_t bytes[16];
|
||||||
|
for (int i = 0; i < 16; i += 4)
|
||||||
|
*reinterpret_cast<uint32_t*>(bytes + i) = distribution(*generator);
|
||||||
|
|
||||||
|
// variant must be 10xxxxxx
|
||||||
|
bytes[8] &= 0xBF;
|
||||||
|
bytes[8] |= 0x80;
|
||||||
|
|
||||||
|
// version must be 0100xxxx
|
||||||
|
bytes[6] &= 0x4F;
|
||||||
|
bytes[6] |= 0x40;
|
||||||
|
|
||||||
|
return uuid{std::begin(bytes), std::end(bytes)};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::uniform_int_distribution<uint32_t> distribution;
|
||||||
|
std::shared_ptr<UniformRandomNumberGenerator> generator;
|
||||||
|
};
|
||||||
|
|
||||||
|
using uuid_random_generator = basic_uuid_random_generator<std::mt19937>;
|
||||||
|
|
||||||
|
class uuid_name_generator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit uuid_name_generator(uuid const& namespace_uuid) noexcept
|
||||||
|
: nsuuid(namespace_uuid)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<class CharT = char>
|
||||||
|
uuid operator()(CharT const * name)
|
||||||
|
{
|
||||||
|
size_t size = 0;
|
||||||
|
if constexpr (std::is_same_v<CharT, char>)
|
||||||
|
size = strlen(name);
|
||||||
|
else
|
||||||
|
size = wcslen(name);
|
||||||
|
|
||||||
|
reset();
|
||||||
|
process_characters(name, size);
|
||||||
|
return make_uuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
uuid operator()(std::basic_string<CharT, Traits, Allocator> const & name)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
process_characters(name.data(), name.size());
|
||||||
|
return make_uuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
hasher.reset();
|
||||||
|
std::byte bytes[16];
|
||||||
|
auto nsbytes = nsuuid.as_bytes();
|
||||||
|
std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes);
|
||||||
|
hasher.process_bytes(bytes, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename char_type,
|
||||||
|
typename = std::enable_if_t<std::is_integral<char_type>::value>>
|
||||||
|
void process_characters(char_type const * const characters, size_t const count)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
uint32_t c = characters[i];
|
||||||
|
hasher.process_byte(static_cast<unsigned char>((c >> 0) & 0xFF));
|
||||||
|
hasher.process_byte(static_cast<unsigned char>((c >> 8) & 0xFF));
|
||||||
|
hasher.process_byte(static_cast<unsigned char>((c >> 16) & 0xFF));
|
||||||
|
hasher.process_byte(static_cast<unsigned char>((c >> 24) & 0xFF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_characters(const char * const characters, size_t const count)
|
||||||
|
{
|
||||||
|
hasher.process_bytes(characters, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
uuid make_uuid()
|
||||||
|
{
|
||||||
|
detail::sha1::digest8_t digest;
|
||||||
|
hasher.get_digest_bytes(digest);
|
||||||
|
|
||||||
|
// variant must be 0b10xxxxxx
|
||||||
|
digest[8] &= 0xBF;
|
||||||
|
digest[8] |= 0x80;
|
||||||
|
|
||||||
|
// version must be 0b0101xxxx
|
||||||
|
digest[6] &= 0x5F;
|
||||||
|
digest[6] |= 0x50;
|
||||||
|
|
||||||
|
return uuid{ digest, digest + 16 };
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uuid nsuuid;
|
||||||
|
detail::sha1 hasher;
|
||||||
|
};
|
||||||
|
|
||||||
|
// !!! DO NOT USE THIS IN PRODUCTION
|
||||||
|
// this implementation is unreliable for good uuids
|
||||||
|
class uuid_time_generator
|
||||||
|
{
|
||||||
|
using mac_address = std::array<unsigned char, 6>;
|
||||||
|
|
||||||
|
std::optional<mac_address> device_address;
|
||||||
|
|
||||||
|
bool get_mac_address()
|
||||||
|
{
|
||||||
|
if (device_address.has_value())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
DWORD len = 0;
|
||||||
|
auto ret = GetAdaptersInfo(nullptr, &len);
|
||||||
|
if (ret != ERROR_BUFFER_OVERFLOW) return false;
|
||||||
|
std::vector<unsigned char> buf(len);
|
||||||
|
auto pips = reinterpret_cast<PIP_ADAPTER_INFO>(&buf.front());
|
||||||
|
ret = GetAdaptersInfo(pips, &len);
|
||||||
|
if (ret != ERROR_SUCCESS) return false;
|
||||||
|
mac_address addr;
|
||||||
|
std::copy(pips->Address, pips->Address + 6, std::begin(addr));
|
||||||
|
device_address = addr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return device_address.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
long long get_time_intervals()
|
||||||
|
{
|
||||||
|
auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800));
|
||||||
|
auto diff = std::chrono::system_clock::now() - start;
|
||||||
|
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count();
|
||||||
|
return ns / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
uuid_time_generator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uuid operator()()
|
||||||
|
{
|
||||||
|
if (get_mac_address())
|
||||||
|
{
|
||||||
|
std::array<uuids::uuid::value_type, 16> data;
|
||||||
|
|
||||||
|
auto tm = get_time_intervals();
|
||||||
|
|
||||||
|
short clock_seq = detail::clock_sequence++;
|
||||||
|
|
||||||
|
clock_seq &= 0x3FFF;
|
||||||
|
|
||||||
|
auto ptm = reinterpret_cast<uuids::uuid::value_type*>(&tm);
|
||||||
|
ptm[0] &= 0x0F;
|
||||||
|
|
||||||
|
memcpy(&data[0], ptm + 4, 4);
|
||||||
|
memcpy(&data[4], ptm + 2, 2);
|
||||||
|
memcpy(&data[6], ptm, 2);
|
||||||
|
|
||||||
|
memcpy(&data[8], reinterpret_cast<uuids::uuid::value_type*>(&clock_seq), 2);
|
||||||
|
|
||||||
|
// variant must be 0b10xxxxxx
|
||||||
|
data[8] &= 0xBF;
|
||||||
|
data[8] |= 0x80;
|
||||||
|
|
||||||
|
// version must be 0b0001xxxx
|
||||||
|
data[6] &= 0x5F;
|
||||||
|
data[6] |= 0x10;
|
||||||
|
|
||||||
|
memcpy(&data[10], &device_address.value()[0], 6);
|
||||||
|
|
||||||
|
return uuids::uuid{std::cbegin(data), std::cend(data)};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
template <>
|
||||||
|
struct hash<uuids::uuid>
|
||||||
|
{
|
||||||
|
using argument_type = uuids::uuid;
|
||||||
|
using result_type = std::size_t;
|
||||||
|
|
||||||
|
result_type operator()(argument_type const &uuid) const
|
||||||
|
{
|
||||||
|
std::hash<std::string> hasher;
|
||||||
|
return static_cast<result_type>(hasher(uuids::to_string(uuid)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
5
src/deps/stduuid/lgtm.yml
Normal file
5
src/deps/stduuid/lgtm.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
path_classifiers:
|
||||||
|
test:
|
||||||
|
- "test"
|
||||||
|
- exclude: "catch"
|
||||||
|
|
31
src/deps/stduuid/test/CMakeLists.txt
Normal file
31
src/deps/stduuid/test/CMakeLists.txt
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# Test target
|
||||||
|
add_executable(test_${PROJECT_NAME} main.cpp test_generators.cpp test_uuid.cpp)
|
||||||
|
target_include_directories(test_${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/catch)
|
||||||
|
target_link_libraries(test_${PROJECT_NAME} PRIVATE ${PROJECT_NAME})
|
||||||
|
if (UUID_USING_CXX20_SPAN)
|
||||||
|
set_target_properties(test_${PROJECT_NAME} PROPERTIES CXX_STANDARD 20)
|
||||||
|
else ()
|
||||||
|
set_target_properties(test_${PROJECT_NAME} PROPERTIES CXX_STANDARD 17)
|
||||||
|
endif ()
|
||||||
|
if (WIN32)
|
||||||
|
target_compile_options(test_${PROJECT_NAME} PRIVATE /EHc)
|
||||||
|
target_compile_definitions(test_${PROJECT_NAME} PRIVATE _SCL_SECURE_NO_WARNINGS)
|
||||||
|
elseif (APPLE)
|
||||||
|
target_compile_options(test_${PROJECT_NAME} PRIVATE -fexceptions -g -Wall)
|
||||||
|
else ()
|
||||||
|
target_compile_options(test_${PROJECT_NAME} PRIVATE -fexceptions -g -Wall)
|
||||||
|
endif ()
|
||||||
|
get_target_property(CURRENT_COMPILE_OPTIONS test_${PROJECT_NAME} COMPILE_OPTIONS)
|
||||||
|
message(STATUS "** ${CMAKE_CXX_COMPILER_ID} flags: ${CURRENT_COMPILE_OPTIONS}")
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
add_test(NAME "test_${PROJECT_NAME}" COMMAND "test_${PROJECT_NAME}" "-r compact")
|
||||||
|
set_tests_properties("test_${PROJECT_NAME}"
|
||||||
|
PROPERTIES
|
||||||
|
PASS_REGULAR_EXPRESSION "Passed all.*")
|
||||||
|
set_tests_properties("test_${PROJECT_NAME}"
|
||||||
|
PROPERTIES
|
||||||
|
FAIL_REGULAR_EXPRESSION "Failed \\d+ test cases")
|
||||||
|
set_tests_properties("test_${PROJECT_NAME}"
|
||||||
|
PROPERTIES
|
||||||
|
TIMEOUT 120)
|
3
src/deps/stduuid/test/main.cpp
Normal file
3
src/deps/stduuid/test/main.cpp
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#define CATCH_CONFIG_MAIN
|
||||||
|
#include "catch.hpp"
|
||||||
|
|
279
src/deps/stduuid/test/test_generators.cpp
Normal file
279
src/deps/stduuid/test/test_generators.cpp
Normal file
|
@ -0,0 +1,279 @@
|
||||||
|
#include "uuid.h"
|
||||||
|
#include "catch.hpp"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <random>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace uuids;
|
||||||
|
|
||||||
|
TEST_CASE("Test multiple default generators", "[gen][rand]")
|
||||||
|
{
|
||||||
|
uuid id1;
|
||||||
|
uuid id2;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
auto seed_data = std::array<int, std::mt19937::state_size> {};
|
||||||
|
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);
|
||||||
|
|
||||||
|
id1 = uuids::uuid_random_generator{ generator }();
|
||||||
|
REQUIRE(!id1.is_nil());
|
||||||
|
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
||||||
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
auto seed_data = std::array<int, std::mt19937::state_size> {};
|
||||||
|
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);
|
||||||
|
|
||||||
|
id2 = uuids::uuid_random_generator{ generator }();
|
||||||
|
REQUIRE(!id2.is_nil());
|
||||||
|
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||||
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(id1 != id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test default generator", "[gen][rand]")
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
auto seed_data = std::array<int, std::mt19937::state_size> {};
|
||||||
|
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);
|
||||||
|
|
||||||
|
uuid const guid = uuids::uuid_random_generator{generator}();
|
||||||
|
REQUIRE(!guid.is_nil());
|
||||||
|
REQUIRE(guid.version() == uuids::uuid_version::random_number_based);
|
||||||
|
REQUIRE(guid.variant() == uuids::uuid_variant::rfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test random generator (conversion ctor w/ smart ptr)", "[gen][rand]")
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
auto seed_data = std::array<int, std::mt19937::state_size> {};
|
||||||
|
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 dgen(&generator);
|
||||||
|
auto id1 = dgen();
|
||||||
|
REQUIRE(!id1.is_nil());
|
||||||
|
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
||||||
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
auto id2 = dgen();
|
||||||
|
REQUIRE(!id2.is_nil());
|
||||||
|
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||||
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
REQUIRE(id1 != id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test random generator (conversion ctor w/ ptr)", "[gen][rand]")
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
auto seed_data = std::array<int, std::mt19937::state_size> {};
|
||||||
|
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 generator = std::make_unique<std::mt19937>(seq);
|
||||||
|
|
||||||
|
uuids::uuid_random_generator dgen(generator.get());
|
||||||
|
auto id1 = dgen();
|
||||||
|
REQUIRE(!id1.is_nil());
|
||||||
|
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
||||||
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
auto id2 = dgen();
|
||||||
|
REQUIRE(!id1.is_nil());
|
||||||
|
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||||
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
REQUIRE(id1 != id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test random generator (conversion ctor w/ ref)", "[gen][rand]")
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
auto seed_data = std::array<int, std::mt19937::state_size> {};
|
||||||
|
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 dgen(generator);
|
||||||
|
auto id1 = dgen();
|
||||||
|
REQUIRE(!id1.is_nil());
|
||||||
|
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
||||||
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
auto id2 = dgen();
|
||||||
|
REQUIRE(!id2.is_nil());
|
||||||
|
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||||
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
REQUIRE(id1 != id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test basic random generator (conversion ctor w/ ptr) w/ ranlux48_base", "[gen][rand]")
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
auto seed_data = std::array<int, 6> {};
|
||||||
|
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<std::ranlux48_base> dgen(&generator);
|
||||||
|
auto id1 = dgen();
|
||||||
|
REQUIRE(!id1.is_nil());
|
||||||
|
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
||||||
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
auto id2 = dgen();
|
||||||
|
REQUIRE(!id2.is_nil());
|
||||||
|
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||||
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
REQUIRE(id1 != id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test basic random generator (conversion ctor w/ smart ptr) w/ ranlux48_base", "[gen][rand]")
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
auto seed_data = std::array<int, 6> {};
|
||||||
|
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 generator = std::make_unique<std::ranlux48_base>(seq);
|
||||||
|
|
||||||
|
uuids::basic_uuid_random_generator<std::ranlux48_base> dgen(generator.get());
|
||||||
|
auto id1 = dgen();
|
||||||
|
REQUIRE(!id1.is_nil());
|
||||||
|
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
||||||
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
auto id2 = dgen();
|
||||||
|
REQUIRE(!id2.is_nil());
|
||||||
|
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||||
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
REQUIRE(id1 != id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test basic random generator (conversion ctor w/ ref) w/ ranlux48_base", "[gen][rand]")
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
auto seed_data = std::array<int, 6> {};
|
||||||
|
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<std::ranlux48_base> dgen(generator);
|
||||||
|
auto id1 = dgen();
|
||||||
|
REQUIRE(!id1.is_nil());
|
||||||
|
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
||||||
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
auto id2 = dgen();
|
||||||
|
REQUIRE(!id2.is_nil());
|
||||||
|
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||||
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
REQUIRE(id1 != id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test namespaces", "[gen][name]")
|
||||||
|
{
|
||||||
|
REQUIRE(uuid_namespace_dns == uuids::uuid::from_string("6ba7b810-9dad-11d1-80b4-00c04fd430c8"));
|
||||||
|
REQUIRE(uuid_namespace_url == uuids::uuid::from_string("6ba7b811-9dad-11d1-80b4-00c04fd430c8"));
|
||||||
|
REQUIRE(uuid_namespace_oid == uuids::uuid::from_string("6ba7b812-9dad-11d1-80b4-00c04fd430c8"));
|
||||||
|
REQUIRE(uuid_namespace_x500 == uuids::uuid::from_string("6ba7b814-9dad-11d1-80b4-00c04fd430c8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test name generator (char*)", "[gen][name]")
|
||||||
|
{
|
||||||
|
uuids::uuid_name_generator dgen(uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value());
|
||||||
|
auto id1 = dgen("john");
|
||||||
|
REQUIRE(!id1.is_nil());
|
||||||
|
REQUIRE(id1.version() == uuids::uuid_version::name_based_sha1);
|
||||||
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
auto id2 = dgen("jane");
|
||||||
|
REQUIRE(!id2.is_nil());
|
||||||
|
REQUIRE(id2.version() == uuids::uuid_version::name_based_sha1);
|
||||||
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
auto id3 = dgen("jane");
|
||||||
|
REQUIRE(!id3.is_nil());
|
||||||
|
REQUIRE(id3.version() == uuids::uuid_version::name_based_sha1);
|
||||||
|
REQUIRE(id3.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
auto id4 = dgen(L"jane");
|
||||||
|
REQUIRE(!id4.is_nil());
|
||||||
|
REQUIRE(id4.version() == uuids::uuid_version::name_based_sha1);
|
||||||
|
REQUIRE(id4.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
REQUIRE(id1 != id2);
|
||||||
|
REQUIRE(id2 == id3);
|
||||||
|
REQUIRE(id3 != id4);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test name generator (std::string)", "[gen][name]")
|
||||||
|
{
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
uuids::uuid_name_generator dgen(uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value());
|
||||||
|
auto id1 = dgen("john"s);
|
||||||
|
REQUIRE(!id1.is_nil());
|
||||||
|
REQUIRE(id1.version() == uuids::uuid_version::name_based_sha1);
|
||||||
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
auto id2 = dgen("jane"s);
|
||||||
|
REQUIRE(!id2.is_nil());
|
||||||
|
REQUIRE(id2.version() == uuids::uuid_version::name_based_sha1);
|
||||||
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
auto id3 = dgen("jane"s);
|
||||||
|
REQUIRE(!id3.is_nil());
|
||||||
|
REQUIRE(id3.version() == uuids::uuid_version::name_based_sha1);
|
||||||
|
REQUIRE(id3.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
auto id4 = dgen(L"jane"s);
|
||||||
|
REQUIRE(!id4.is_nil());
|
||||||
|
REQUIRE(id4.version() == uuids::uuid_version::name_based_sha1);
|
||||||
|
REQUIRE(id4.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
REQUIRE(id1 != id2);
|
||||||
|
REQUIRE(id2 == id3);
|
||||||
|
REQUIRE(id3 != id4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
TEST_CASE("Test time generator", "[gen][time]")
|
||||||
|
{
|
||||||
|
uuid_time_generator gen;
|
||||||
|
auto id1 = gen();
|
||||||
|
auto id2 = gen();
|
||||||
|
REQUIRE(!id1.is_nil());
|
||||||
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
REQUIRE(id1.version() == uuids::uuid_version::time_based);
|
||||||
|
|
||||||
|
REQUIRE(!id2.is_nil());
|
||||||
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
REQUIRE(id2.version() == uuids::uuid_version::time_based);
|
||||||
|
|
||||||
|
REQUIRE(id1 != id2);
|
||||||
|
|
||||||
|
std::set<uuids::uuid> ids;
|
||||||
|
for (int i = 0; i < 100; ++i)
|
||||||
|
ids.insert(gen());
|
||||||
|
|
||||||
|
REQUIRE(ids.size() == 100);
|
||||||
|
}
|
||||||
|
#endif
|
520
src/deps/stduuid/test/test_uuid.cpp
Normal file
520
src/deps/stduuid/test/test_uuid.cpp
Normal file
|
@ -0,0 +1,520 @@
|
||||||
|
#include "uuid.h"
|
||||||
|
#include "catch.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <set>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace uuids;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0205r0.html
|
||||||
|
template <typename EngineT, std::size_t StateSize = EngineT::state_size>
|
||||||
|
void seed_rng(EngineT& engine)
|
||||||
|
{
|
||||||
|
using engine_type = typename EngineT::result_type;
|
||||||
|
using device_type = std::random_device::result_type;
|
||||||
|
using seedseq_type = std::seed_seq::result_type;
|
||||||
|
constexpr auto bytes_needed = StateSize * sizeof(engine_type);
|
||||||
|
constexpr auto numbers_needed = (sizeof(device_type) < sizeof(seedseq_type))
|
||||||
|
? (bytes_needed / sizeof(device_type))
|
||||||
|
: (bytes_needed / sizeof(seedseq_type));
|
||||||
|
std::array<device_type, numbers_needed> numbers{};
|
||||||
|
std::random_device rnddev{};
|
||||||
|
std::generate(std::begin(numbers), std::end(numbers), std::ref(rnddev));
|
||||||
|
std::seed_seq seedseq(std::cbegin(numbers), std::cend(numbers));
|
||||||
|
engine.seed(seedseq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test default constructor", "[ctors]")
|
||||||
|
{
|
||||||
|
uuid empty;
|
||||||
|
REQUIRE(empty.is_nil());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test string conversion", "[ops]")
|
||||||
|
{
|
||||||
|
uuid empty;
|
||||||
|
REQUIRE(uuids::to_string(empty) == "00000000-0000-0000-0000-000000000000");
|
||||||
|
REQUIRE(uuids::to_string<wchar_t>(empty) == L"00000000-0000-0000-0000-000000000000");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test is_valid_uuid(char*)", "[parse]")
|
||||||
|
{
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid("47183823-2574-4bfd-b411-99ed177d3e43"));
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid("{47183823-2574-4bfd-b411-99ed177d3e43}"));
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid(L"47183823-2574-4bfd-b411-99ed177d3e43"));
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid(L"{47183823-2574-4bfd-b411-99ed177d3e43}"));
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid("00000000-0000-0000-0000-000000000000"));
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid("{00000000-0000-0000-0000-000000000000}"));
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid(L"00000000-0000-0000-0000-000000000000"));
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid(L"{00000000-0000-0000-0000-000000000000}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test is_valid_uuid(basic_string)", "[parse]")
|
||||||
|
{
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43}"s;
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"{47183823-2574-4bfd-b411-99ed177d3e43}"s;
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "00000000-0000-0000-0000-000000000000"s;
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{00000000-0000-0000-0000-000000000000}"s;
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"00000000-0000-0000-0000-000000000000"s;
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"{00000000-0000-0000-0000-000000000000}"s;
|
||||||
|
REQUIRE(uuids::uuid::is_valid_uuid(str));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test is_valid_uuid(char*) invalid format", "[parse]")
|
||||||
|
{
|
||||||
|
REQUIRE(!uuids::uuid::is_valid_uuid(""));
|
||||||
|
REQUIRE(!uuids::uuid::is_valid_uuid("{}"));
|
||||||
|
REQUIRE(!uuids::uuid::is_valid_uuid("47183823-2574-4bfd-b411-99ed177d3e4"));
|
||||||
|
REQUIRE(!uuids::uuid::is_valid_uuid("47183823-2574-4bfd-b411-99ed177d3e430"));
|
||||||
|
REQUIRE(!uuids::uuid::is_valid_uuid("{47183823-2574-4bfd-b411-99ed177d3e43"));
|
||||||
|
REQUIRE(!uuids::uuid::is_valid_uuid("47183823-2574-4bfd-b411-99ed177d3e43}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test is_valid_uuid(basic_string) invalid format", "[parse]")
|
||||||
|
{
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = ""s;
|
||||||
|
REQUIRE(!uuids::uuid::is_valid_uuid(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{}"s;
|
||||||
|
REQUIRE(!uuids::uuid::is_valid_uuid(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e4"s;
|
||||||
|
REQUIRE(!uuids::uuid::is_valid_uuid(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e430"s;
|
||||||
|
REQUIRE(!uuids::uuid::is_valid_uuid(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||||
|
REQUIRE(!uuids::uuid::is_valid_uuid(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e43}"s;
|
||||||
|
REQUIRE(!uuids::uuid::is_valid_uuid(str));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test from_string(char*)", "[parse]")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e43";
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(uuids::to_string(guid) == str);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43}";
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto guid = uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value();
|
||||||
|
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||||
|
REQUIRE(uuids::to_string<wchar_t>(guid) == L"47183823-2574-4bfd-b411-99ed177d3e43");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"47183823-2574-4bfd-b411-99ed177d3e43";
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(uuids::to_string<wchar_t>(guid) == str);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "4718382325744bfdb41199ed177d3e43";
|
||||||
|
REQUIRE_NOTHROW(uuids::uuid::from_string(str));
|
||||||
|
REQUIRE(uuids::uuid::from_string(str).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "00000000-0000-0000-0000-000000000000";
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{00000000-0000-0000-0000-000000000000}";
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"00000000-0000-0000-0000-000000000000";
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"{00000000-0000-0000-0000-000000000000}";
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test from_string(basic_string)", "[parse]")
|
||||||
|
{
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(uuids::to_string(guid) == str);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43}"s;
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto guid = uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value();
|
||||||
|
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||||
|
REQUIRE(uuids::to_string<wchar_t>(guid) == L"47183823-2574-4bfd-b411-99ed177d3e43");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(uuids::to_string<wchar_t>(guid) == str);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "4718382325744bfdb41199ed177d3e43"s;
|
||||||
|
REQUIRE_NOTHROW(uuids::uuid::from_string(str));
|
||||||
|
REQUIRE(uuids::uuid::from_string(str).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "00000000-0000-0000-0000-000000000000"s;
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{00000000-0000-0000-0000-000000000000}"s;
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"00000000-0000-0000-0000-000000000000"s;
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"{00000000-0000-0000-0000-000000000000}"s;
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test from_string(char*) invalid format", "[parse]")
|
||||||
|
{
|
||||||
|
REQUIRE(!uuids::uuid::from_string("").has_value());
|
||||||
|
REQUIRE(!uuids::uuid::from_string("{}").has_value());
|
||||||
|
REQUIRE(!uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e4").has_value());
|
||||||
|
REQUIRE(!uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e430").has_value());
|
||||||
|
REQUIRE(!uuids::uuid::from_string("{47183823-2574-4bfd-b411-99ed177d3e43").has_value());
|
||||||
|
REQUIRE(!uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43}").has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test from_string(basic_string) invalid format", "[parse]")
|
||||||
|
{
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = ""s;
|
||||||
|
REQUIRE(!uuids::uuid::from_string(str).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{}"s;
|
||||||
|
REQUIRE(!uuids::uuid::from_string(str).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e4"s;
|
||||||
|
REQUIRE(!uuids::uuid::from_string(str).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e430"s;
|
||||||
|
REQUIRE(!uuids::uuid::from_string(str).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||||
|
REQUIRE(!uuids::uuid::from_string(str).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e43}"s;
|
||||||
|
REQUIRE(!uuids::uuid::from_string(str).has_value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test iterators constructor", "[ctors]")
|
||||||
|
{
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::array<uuids::uuid::value_type, 16> arr{ {
|
||||||
|
0x47, 0x18, 0x38, 0x23,
|
||||||
|
0x25, 0x74,
|
||||||
|
0x4b, 0xfd,
|
||||||
|
0xb4, 0x11,
|
||||||
|
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 } };
|
||||||
|
|
||||||
|
uuid guid(std::begin(arr), std::end(arr));
|
||||||
|
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43"s);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
uuids::uuid::value_type arr[16] = {
|
||||||
|
0x47, 0x18, 0x38, 0x23,
|
||||||
|
0x25, 0x74,
|
||||||
|
0x4b, 0xfd,
|
||||||
|
0xb4, 0x11,
|
||||||
|
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 };
|
||||||
|
|
||||||
|
uuid guid(std::begin(arr), std::end(arr));
|
||||||
|
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43"s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test array constructors", "[ctors]")
|
||||||
|
{
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
{
|
||||||
|
uuids::uuid guid{
|
||||||
|
{0x47, 0x18, 0x38, 0x23,
|
||||||
|
0x25, 0x74,
|
||||||
|
0x4b, 0xfd,
|
||||||
|
0xb4, 0x11,
|
||||||
|
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 } };
|
||||||
|
|
||||||
|
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43"s);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::array<uuids::uuid::value_type, 16> arr{ {
|
||||||
|
0x47, 0x18, 0x38, 0x23,
|
||||||
|
0x25, 0x74,
|
||||||
|
0x4b, 0xfd,
|
||||||
|
0xb4, 0x11,
|
||||||
|
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 } };
|
||||||
|
|
||||||
|
uuid guid(arr);
|
||||||
|
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43"s);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
uuids::uuid::value_type arr[16] {
|
||||||
|
0x47, 0x18, 0x38, 0x23,
|
||||||
|
0x25, 0x74,
|
||||||
|
0x4b, 0xfd,
|
||||||
|
0xb4, 0x11,
|
||||||
|
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 };
|
||||||
|
|
||||||
|
uuid guid(arr);
|
||||||
|
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43"s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test equality", "[operators]")
|
||||||
|
{
|
||||||
|
uuid empty;
|
||||||
|
|
||||||
|
auto engine = uuids::uuid_random_generator::engine_type{};
|
||||||
|
seed_rng(engine);
|
||||||
|
uuid guid = uuids::uuid_random_generator{engine}();
|
||||||
|
|
||||||
|
REQUIRE(empty == empty);
|
||||||
|
REQUIRE(guid == guid);
|
||||||
|
REQUIRE(empty != guid);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test comparison", "[operators]")
|
||||||
|
{
|
||||||
|
auto empty = uuid{};
|
||||||
|
|
||||||
|
auto engine = uuids::uuid_random_generator::engine_type{};
|
||||||
|
seed_rng(engine);
|
||||||
|
|
||||||
|
uuids::uuid_random_generator gen{ engine };
|
||||||
|
auto id = gen();
|
||||||
|
|
||||||
|
REQUIRE(empty < id);
|
||||||
|
|
||||||
|
std::set<uuids::uuid> ids{
|
||||||
|
uuid{},
|
||||||
|
gen(),
|
||||||
|
gen(),
|
||||||
|
gen(),
|
||||||
|
gen()
|
||||||
|
};
|
||||||
|
|
||||||
|
REQUIRE(ids.size() == 5);
|
||||||
|
REQUIRE(ids.find(uuid{}) != ids.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test hashing", "[ops]")
|
||||||
|
{
|
||||||
|
using namespace std::string_literals;
|
||||||
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
|
||||||
|
auto h1 = std::hash<std::string>{};
|
||||||
|
auto h2 = std::hash<uuid>{};
|
||||||
|
REQUIRE(h1(str) == h2(guid));
|
||||||
|
|
||||||
|
auto engine = uuids::uuid_random_generator::engine_type{};
|
||||||
|
seed_rng(engine);
|
||||||
|
uuids::uuid_random_generator gen{ engine };
|
||||||
|
|
||||||
|
std::unordered_set<uuids::uuid> ids{
|
||||||
|
uuid{},
|
||||||
|
gen(),
|
||||||
|
gen(),
|
||||||
|
gen(),
|
||||||
|
gen()
|
||||||
|
};
|
||||||
|
|
||||||
|
REQUIRE(ids.size() == 5);
|
||||||
|
REQUIRE(ids.find(uuid{}) != ids.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test swap", "[ops]")
|
||||||
|
{
|
||||||
|
uuid empty;
|
||||||
|
|
||||||
|
auto engine = uuids::uuid_random_generator::engine_type{};
|
||||||
|
seed_rng(engine);
|
||||||
|
uuid guid = uuids::uuid_random_generator{engine}();
|
||||||
|
|
||||||
|
REQUIRE(empty.is_nil());
|
||||||
|
REQUIRE(!guid.is_nil());
|
||||||
|
|
||||||
|
std::swap(empty, guid);
|
||||||
|
|
||||||
|
REQUIRE(!empty.is_nil());
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
|
||||||
|
empty.swap(guid);
|
||||||
|
|
||||||
|
REQUIRE(empty.is_nil());
|
||||||
|
REQUIRE(!guid.is_nil());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test constexpr", "[const]")
|
||||||
|
{
|
||||||
|
constexpr uuid empty;
|
||||||
|
[[maybe_unused]] constexpr bool isnil = empty.is_nil();
|
||||||
|
[[maybe_unused]] constexpr uuids::uuid_variant variant = empty.variant();
|
||||||
|
[[maybe_unused]] constexpr uuid_version version = empty.version();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test size", "[operators]")
|
||||||
|
{
|
||||||
|
REQUIRE(sizeof(uuid) == 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test assignment", "[ops]")
|
||||||
|
{
|
||||||
|
auto id1 = uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value();
|
||||||
|
auto id2 = id1;
|
||||||
|
REQUIRE(id1 == id2);
|
||||||
|
|
||||||
|
id1 = uuids::uuid::from_string("{fea43102-064f-4444-adc2-02cec42623f8}").value();
|
||||||
|
REQUIRE(id1 != id2);
|
||||||
|
|
||||||
|
auto id3 = std::move(id2);
|
||||||
|
REQUIRE(uuids::to_string(id3) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test trivial", "[trivial]")
|
||||||
|
{
|
||||||
|
REQUIRE(std::is_trivially_copyable_v<uuids::uuid>);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test as_bytes", "[ops]")
|
||||||
|
{
|
||||||
|
std::array<uuids::uuid::value_type, 16> arr{ {
|
||||||
|
0x47, 0x18, 0x38, 0x23,
|
||||||
|
0x25, 0x74,
|
||||||
|
0x4b, 0xfd,
|
||||||
|
0xb4, 0x11,
|
||||||
|
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43
|
||||||
|
} };
|
||||||
|
|
||||||
|
{
|
||||||
|
uuids::uuid id{ arr };
|
||||||
|
REQUIRE(!id.is_nil());
|
||||||
|
|
||||||
|
auto view = id.as_bytes();
|
||||||
|
REQUIRE(memcmp(view.data(), arr.data(), arr.size()) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uuids::uuid id{ arr };
|
||||||
|
REQUIRE(!id.is_nil());
|
||||||
|
|
||||||
|
auto view = id.as_bytes();
|
||||||
|
REQUIRE(memcmp(view.data(), arr.data(), arr.size()) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue