Compare commits
106 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3afe7193fa | ||
|
|
e5da05d8de | ||
|
|
30b95f9c8f | ||
|
|
3dca9d816c | ||
|
|
d1f0f7f0ba | ||
|
|
cd9ca5e7d7 | ||
|
|
dfe3d39c10 | ||
|
|
979ba59e41 | ||
|
|
db4963048d | ||
|
|
44160cca3f | ||
|
|
2ff6222e9f | ||
|
|
c1e1c144af | ||
|
|
9341e579f7 | ||
|
|
39b505ee95 | ||
|
|
11a678d7fe | ||
|
|
02e2989771 | ||
|
|
1d3720fbcd | ||
|
|
cdebc5b78d | ||
|
|
5c538cca02 | ||
|
|
f58993d041 | ||
|
|
66a4adec66 | ||
|
|
c4728ee83b | ||
|
|
1da3294a8b | ||
|
|
76c4651202 | ||
|
|
5f739d3e26 | ||
|
|
9357e5280c | ||
|
|
8723ae1a33 | ||
|
|
4400e13797 | ||
|
|
d393e00037 | ||
|
|
487f364da7 | ||
|
|
b6f1515be5 | ||
|
|
7a3e380c21 | ||
|
|
5458877f2c | ||
|
|
8e9d0f87f5 | ||
|
|
c6ad65304b | ||
|
|
9857cd372a | ||
|
|
50482c3c07 | ||
|
|
8068131ec3 | ||
|
|
889fffda69 | ||
|
|
197905e841 | ||
|
|
5baab46e60 | ||
|
|
4959d46eb4 | ||
|
|
1562616dab | ||
|
|
85c8e28973 | ||
|
|
297cd66004 | ||
|
|
6f8258b170 | ||
|
|
9e5162c3d3 | ||
|
|
500cd57084 | ||
|
|
260b1f1f6a | ||
|
|
8836cbcaf1 | ||
|
|
36778b41ae | ||
|
|
4ff25c702f | ||
|
|
dca30fff7f | ||
|
|
2e49ce59f4 | ||
|
|
b16884a774 | ||
|
|
359b195c78 | ||
|
|
5890c94bfa | ||
|
|
74b6b8be48 | ||
|
|
a9b5941914 | ||
|
|
1b74bbc183 | ||
|
|
afef8d228d | ||
|
|
d55abecb97 | ||
|
|
0d74ad6a26 | ||
|
|
c8f730e77c | ||
|
|
40c08315a7 | ||
|
|
a268dfbdb6 | ||
|
|
ca94985a90 | ||
|
|
150f589fb1 | ||
|
|
85ff00a004 | ||
|
|
6ac13af81a | ||
|
|
da98fcf5ee | ||
|
|
efc6744581 | ||
|
|
845fcf9d13 | ||
|
|
c2408b92e4 | ||
|
|
cda38dd952 | ||
|
|
324ebf37fc | ||
|
|
9184792fc3 | ||
|
|
6452aadcbe | ||
|
|
987edad167 | ||
|
|
921f01fbea | ||
|
|
1b12059d1a | ||
|
|
f08b54b88e | ||
|
|
904224fbfc | ||
|
|
48a02dd8da | ||
|
|
6bd1e3bb78 | ||
|
|
4179dacce4 | ||
|
|
207f06bd56 | ||
|
|
60769168bc | ||
|
|
7bd86a11e3 | ||
|
|
b74a5eb7e9 | ||
|
|
f7a15f1e72 | ||
|
|
e0a781d245 | ||
|
|
dee14f660d | ||
|
|
d660780bc4 | ||
|
|
8a056e7436 | ||
|
|
7a0f71cb10 | ||
|
|
58c7031c33 | ||
|
|
29ce84bac9 | ||
|
|
bc37fa250b | ||
|
|
0ebaceee2f | ||
|
|
c2e8aa2b65 | ||
|
|
e5b8debe5e | ||
|
|
81fc825a5b | ||
|
|
cb5a727a4a | ||
|
|
de9a01803c | ||
|
|
d1538cb326 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -32,4 +32,6 @@
|
||||
*.app
|
||||
/build/.gitignore
|
||||
|
||||
build
|
||||
build
|
||||
/test/CMakeFiles/3.10.0/CompilerIdC/Debug/CompilerIdC.tlog
|
||||
/.vs
|
||||
|
||||
28
.travis.yml
Normal file
28
.travis.yml
Normal file
@ -0,0 +1,28 @@
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- cppcheck
|
||||
- g++-8
|
||||
- uuid-dev
|
||||
|
||||
before_install:
|
||||
- sudo apt-cache search libuuid
|
||||
|
||||
install:
|
||||
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-8 90
|
||||
|
||||
before_script:
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
- cmake -H. -BBuild -DCMAKE_BUILD_TYPE=Release -Wdev
|
||||
- cd Build
|
||||
|
||||
script:
|
||||
- make -j 2
|
||||
- ctest -V -j 2 -C Release
|
||||
- cppcheck --quiet --error-exitcode=1 .
|
||||
|
||||
106
CMakeLists.txt
106
CMakeLists.txt
@ -1,38 +1,82 @@
|
||||
cmake_minimum_required(VERSION 3.7.0)
|
||||
project(test_uuid CXX)
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/catch)
|
||||
|
||||
file(GLOB headers ${CMAKE_SOURCE_DIR}/include/*.h)
|
||||
file(GLOB SOURCES "test/*.cpp" "include/*.cpp")
|
||||
|
||||
if(WIN32)
|
||||
message(status "Setting MSVC flags")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHc /std:c++latest")
|
||||
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
|
||||
elseif(APPLE)
|
||||
message(status "Setting Clang flags")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1z -fexceptions -g -Wall")
|
||||
else()
|
||||
include_directories(${LIBUUID_INCLUDE_DIR})
|
||||
message(status "Setting GCC flags")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1z -fexceptions -g -Wall")
|
||||
set(UUID_MAIN_PROJECT OFF)
|
||||
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
set(UUID_MAIN_PROJECT ON)
|
||||
endif()
|
||||
|
||||
add_executable(test_uuid ${SOURCES} ${headers})
|
||||
project(stduuid CXX)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
|
||||
|
||||
if(WIN32)
|
||||
elseif(APPLE)
|
||||
find_library(CFLIB CoreFoundation)
|
||||
target_link_libraries(test_uuid ${CFLIB})
|
||||
else()
|
||||
find_package(Libuuid REQUIRED)
|
||||
if (NOT LIBUUID_FOUND)
|
||||
message(FATAL_ERROR
|
||||
"You might need to run 'sudo apt-get install uuid-dev' or similar")
|
||||
endif()
|
||||
target_link_libraries(test_uuid ${LIBUUID_LIBRARY})
|
||||
option(UUID_BUILD_TESTS "Build the unit tests" ${UUID_MAIN_PROJECT})
|
||||
option(UUID_SYSTEM_GENERATOR "Enable operating system uuid generator" OFF)
|
||||
option(UUID_TIME_GENERATOR "Enable experimental time-based uuid generator" OFF)
|
||||
option(UUID_USING_CXX20_SPAN "Using span from std instead of gsl" OFF)
|
||||
option(UUID_ENABLE_INSTALL "Create an install target" ${UUID_MAIN_PROJECT})
|
||||
|
||||
# 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 time-based generator
|
||||
if (UUID_TIME_GENERATOR)
|
||||
target_compile_definitions(${PROJECT_NAME} INTERFACE UUID_TIME_GENERATOR)
|
||||
endif()
|
||||
|
||||
message(status "** CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
|
||||
# Using span from std
|
||||
if (NOT UUID_USING_CXX20_SPAN)
|
||||
target_include_directories(${PROJECT_NAME} INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
install(DIRECTORY gsl DESTINATION include)
|
||||
endif ()
|
||||
|
||||
if(UUID_ENABLE_INSTALL)
|
||||
# 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")
|
||||
endif()
|
||||
|
||||
# Tests
|
||||
if (UUID_BUILD_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
endif ()
|
||||
|
||||
493
P0959.md
493
P0959.md
@ -1,8 +1,8 @@
|
||||
| ___ | ___ |
|
||||
| --- | --- |
|
||||
| Doc. No.: | P0959R1 |
|
||||
| Date: | 2018-09-05 |
|
||||
| Reply to: | Marius Bancila |
|
||||
| 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 |
|
||||
|
||||
@ -24,7 +24,7 @@ Revised with feedback from the LWG and the community.
|
||||
* 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 `<=>`
|
||||
* 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.
|
||||
@ -33,6 +33,85 @@ Revised with feedback from the LWG and the community.
|
||||
* 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`.
|
||||
* `from_string()` and `is_valid_uuid()` declared with `constexpr`.
|
||||
* 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
|
||||
|
||||
@ -51,9 +130,8 @@ This proposal is a pure library extension. It does not require changes to any st
|
||||
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
|
||||
* a class called `uuid_error` representing an exception type for `uuid` operations
|
||||
* function objects that generate UUIDs, called generators: `basic_uuid_random_generator<T>`, `uuid_random_generator`, `uuid_name_generator`
|
||||
* conversion functions from strings `from_string()` and to strings `std::to_string()` \ `std::to_wstring()`, as well as an overloaded `operator<<` for `std::basic_ostream`
|
||||
* 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`
|
||||
|
||||
@ -91,6 +169,30 @@ uuid::value_type arr[16] = {
|
||||
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.
|
||||
@ -111,14 +213,6 @@ uuid id{ data };
|
||||
assert(to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
```
|
||||
|
||||
### Size
|
||||
|
||||
Member function `size()` indicates the number of bytes in the UUID. Because this is a fixed size structure this function always returns 16.
|
||||
```cpp
|
||||
uuid id;
|
||||
assert(id.size() == 16);
|
||||
```
|
||||
|
||||
### 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}`.
|
||||
@ -127,39 +221,16 @@ A nil UUID is a special UUID that has all the bits set to 0. Its canonical textu
|
||||
uuid id;
|
||||
assert(id.is_nil());
|
||||
|
||||
uuid id = uuid::from_string("00000000-0000-0000-0000-000000000000");
|
||||
assert(id.is_nil());
|
||||
std::optional<uuid> id = uuid::from_string("00000000-0000-0000-0000-000000000000");
|
||||
assert(id.has_value() && id.value().is_nil());
|
||||
```
|
||||
|
||||
### Iterators
|
||||
|
||||
Constant iterators allow direct access to the underlaying `uuid` data. This enables both direct reading of the `uuid` bits. The `uuid` class has const `begin()` and `end()` members to return constant iterators to the first and the one-past-last element of the UUID data.
|
||||
|
||||
```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));
|
||||
assert(to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
|
||||
size_t i = 0;
|
||||
for (auto const & b : id)
|
||||
assert(arr[i++] == b);
|
||||
```
|
||||
|
||||
Because the internal representation may not be a straightforward array of bytes and may have arbitrary endianness iterators are not defined as pointers.
|
||||
|
||||
### `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");
|
||||
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);
|
||||
```
|
||||
@ -178,12 +249,12 @@ std::array<uuid::value_type, 16> arr{ {
|
||||
} };
|
||||
|
||||
uuid id1{ std::span<uuid::value_type, 16>{arr} };
|
||||
uuid id2 = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
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")
|
||||
uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value()
|
||||
};
|
||||
|
||||
assert(ids.size() == 2);
|
||||
@ -201,7 +272,7 @@ std::array<uuids::uuid::value_type, 16> arr{ {
|
||||
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43
|
||||
} };
|
||||
|
||||
const uuid id{ arr };
|
||||
uuid const id{ arr };
|
||||
assert(!id.is_nil());
|
||||
|
||||
auto view = id.as_bytes();
|
||||
@ -214,7 +285,7 @@ Both member and non-member `swap()` functions are available to perform the swapp
|
||||
|
||||
```cpp
|
||||
uuid empty;
|
||||
uuid id = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
uuid id = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value();
|
||||
|
||||
assert(empty.is_nil());
|
||||
assert(!id.is_nil());
|
||||
@ -232,25 +303,29 @@ assert(!id.is_nil());
|
||||
|
||||
### String parsing
|
||||
|
||||
Static overloaded member function `from_string()` allows to create `uuid` instances from various strings.
|
||||
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. Should the argument be of a different format, an `uuid_error` exception is thrown.
|
||||
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 functions `to_string()` and `to_wstring()` return a string with the UUID formatted to the canonical textual representation `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`, where `x` is a lower case hexadecimal digit.
|
||||
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
|
||||
uuid id = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
assert(to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
assert(to_wstring(id) == L"47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
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"`.
|
||||
@ -262,7 +337,7 @@ A `std::hash<>` specialization for `uuid` is provided in order to enable the use
|
||||
```cpp
|
||||
std::unordered_set<uuid> ids{
|
||||
uuid{},
|
||||
uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43"),
|
||||
uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value(),
|
||||
};
|
||||
|
||||
assert(ids.size() == 2);
|
||||
@ -275,37 +350,43 @@ Several function objects, called generators, are provided in order to create dif
|
||||
Examples for generating new UUIDs with the `basic_uuid_random_generator` class:
|
||||
```cpp
|
||||
{
|
||||
basic_uuid_random_generator<std::mt19937> dgen;
|
||||
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);
|
||||
}
|
||||
{
|
||||
basic_uuid_random_generator<std::ranlux48_base> dgen;
|
||||
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;
|
||||
std::ranlux48_base generator(rd());
|
||||
|
||||
basic_uuid_random_generator<std::ranlux48_base> dgen(&generator);
|
||||
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 generator = std::make_unique<std::mt19937>(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(generator.get());
|
||||
basic_uuid_random_generator<std::mt19937> dgen(engine.get());
|
||||
auto id1 = dgen();
|
||||
assert(!id1.is_nil());
|
||||
assert(id1.size() == 16);
|
||||
@ -313,18 +394,26 @@ Examples for generating new UUIDs with the `basic_uuid_random_generator` class:
|
||||
assert(id1.variant() == uuid_variant::rfc);
|
||||
}
|
||||
```
|
||||
|
||||
Examples for generating new UUIDs with the `uuid_random_generator` type alias:
|
||||
```cpp
|
||||
uuid_random_generator dgen;
|
||||
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"));
|
||||
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);
|
||||
@ -373,6 +462,8 @@ namespace std {
|
||||
}
|
||||
```
|
||||
|
||||
**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
|
||||
@ -389,55 +480,43 @@ namespace std {
|
||||
}
|
||||
```
|
||||
|
||||
### `uuid_error` class
|
||||
```cpp
|
||||
namespace std {
|
||||
struct uuid_error : public std::runtime_error
|
||||
{
|
||||
explicit uuid_error(std::string_view message);
|
||||
explicit uuid_error(char const * message);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### `uuid` class
|
||||
|
||||
```cpp
|
||||
namespace std {
|
||||
struct uuid
|
||||
class uuid
|
||||
{
|
||||
using value_type = uint8_t;
|
||||
using const_iterator = /*implementation-defined*/;
|
||||
public:
|
||||
using value_type = uint8_t;
|
||||
|
||||
constexpr uuid() noexcept = default;
|
||||
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;
|
||||
|
||||
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 std::size_t size() const noexcept;
|
||||
constexpr bool is_nil() const noexcept;
|
||||
|
||||
constexpr void swap(uuid & other) noexcept;
|
||||
|
||||
constexpr const_iterator begin() const noexcept;
|
||||
constexpr const_iterator end() const noexcept;
|
||||
|
||||
constexpr std::span<std::byte const, 16> as_bytes() const;
|
||||
|
||||
constexpr std::strong_ordering operator<=>(uuid const&) const noexcept = default;
|
||||
|
||||
template <typename TChar>
|
||||
static uuid from_string(TChar const * const str, size_t const size);
|
||||
static uuid from_string(std::string_view str);
|
||||
static uuid from_string(std::wstring_view str);
|
||||
|
||||
template<typename StringType>
|
||||
constexpr static bool is_valid_uuid(StringType const & str) noexcept;
|
||||
|
||||
template<typename StringType>
|
||||
constexpr static uuid from_string(StringType 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);
|
||||
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
|
||||
};
|
||||
}
|
||||
```
|
||||
@ -446,29 +525,44 @@ namespace std {
|
||||
|
||||
```cpp
|
||||
namespace std {
|
||||
inline constexpr void swap(uuid & lhs, uuid & rhs);
|
||||
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);
|
||||
|
||||
inline std::string to_string(uuid const & id);
|
||||
inline std::wstring to_wstring(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
|
||||
`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 either default constructed or constructed with a reference or pointer to a an objects that satisfies the `UniformRandomNumberGenerator` requirements.
|
||||
#### 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 result_type = uuid;
|
||||
|
||||
basic_uuid_random_generator();
|
||||
explicit basic_uuid_random_generator(UniformRandomNumberGenerator& gen);
|
||||
explicit basic_uuid_random_generator(UniformRandomNumberGenerator* gen);
|
||||
using engine_type = UniformRandomNumberGenerator;
|
||||
|
||||
explicit basic_uuid_random_generator(engine_type& gen);
|
||||
explicit basic_uuid_random_generator(engine_type* gen);
|
||||
|
||||
uuid operator()();
|
||||
};
|
||||
@ -480,21 +574,75 @@ namespace std {
|
||||
using uuid_random_generator = basic_uuid_random_generator<std::mt19937>;
|
||||
}
|
||||
```
|
||||
`uuid_name_generator` is a function object that generates new UUIDs from a name. It has to be initialized with another UUID and has overloaded `operator()` for both `std::string_view` and `std::wstring_view`.
|
||||
|
||||
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:
|
||||
using result_type = uuid;
|
||||
|
||||
explicit uuid_name_generator(uuid const& namespace_uuid) noexcept;
|
||||
|
||||
uuid operator()(std::string_view name);
|
||||
uuid operator()(std::wstring_view name);
|
||||
template<typename StringType>
|
||||
uuid operator()(StringType 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.
|
||||
@ -531,38 +679,37 @@ using uuid_map = std::map<std::uuid, Value, std::uuid_lexicographical_order, All
|
||||
In this case, the `uuid` class should be defined as follows:
|
||||
```cpp
|
||||
namespace std {
|
||||
struct uuid
|
||||
class uuid
|
||||
{
|
||||
using value_type = uint8_t;
|
||||
using const_iterator = /*implementation-defined*/;
|
||||
public:
|
||||
using value_type = uint8_t;
|
||||
|
||||
constexpr uuid() noexcept = default;
|
||||
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 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 std::size_t size() const noexcept;
|
||||
constexpr bool is_nil() const noexcept;
|
||||
|
||||
constexpr void swap(uuid & other) noexcept;
|
||||
|
||||
constexpr const_iterator begin() const noexcept;
|
||||
constexpr const_iterator end() const noexcept;
|
||||
|
||||
constexpr std::span<std::byte const, 16> as_bytes() const;
|
||||
|
||||
template <typename TChar>
|
||||
static uuid from_string(TChar const * const str, size_t const size);
|
||||
static uuid from_string(std::string_view str);
|
||||
static uuid from_string(std::wstring_view str);
|
||||
|
||||
template<typename StringType>
|
||||
constexpr static bool is_valid_uuid(StringType const & str) noexcept;
|
||||
|
||||
template<typename StringType>
|
||||
constexpr static uuid from_string(StringType 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);
|
||||
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
|
||||
};
|
||||
}
|
||||
```
|
||||
@ -642,7 +789,49 @@ As an implementation note, equality comparison can be performed on many systems
|
||||
|
||||
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. References
|
||||
### 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]
|
||||
```
|
||||
However, to simplify the definition, these two overloads have been replaced with a single one:
|
||||
```
|
||||
template <typename StringType>
|
||||
constexpr static std::optional<uuid> from_string(StringType const & str);
|
||||
```
|
||||
The `is_valid_uuid()` function and the `uuid_name_generator`'s call operator are now defined in the same manner.
|
||||
|
||||
#### 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
|
||||
|
||||
340
README.md
340
README.md
@ -1,5 +1,8 @@
|
||||
# stduuid
|
||||
A C++ 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.
|
||||
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)
|
||||
@ -15,16 +18,16 @@ Basic types:
|
||||
| `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 |
|
||||
| `uuid_error` | a class representing an exception type for `uuid` operations |
|
||||
|
||||
Generators:
|
||||
|
||||
| Name | Description |
|
||||
| ---- | ----------- |
|
||||
| `uuid_system_generator` | a function object that generates new UUIDs using operating system resources (`CoCreateGuid` on Windows, `uuid_generate` on Linux, `CFUUIDCreate` on Mac) |
|
||||
| `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, i.e. `basic_uuid_random_generator<std::mt19937>` |
|
||||
| `uuid_random_generator` | a `basic_uuid_random_generator` using the Mersenne 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. |
|
||||
| `uuid_time_generator` | an experimental function object that generates time-based UUIDs.<br><br> **Note**:This is an experimental feature and should not be used in any production code. It is available only if the `UUID_TIME_GENERATOR` macro is defined. |
|
||||
|
||||
Utilities:
|
||||
|
||||
@ -33,6 +36,15 @@ Utilities:
|
||||
| `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 |
|
||||
@ -40,200 +52,232 @@ Other:
|
||||
| `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 `std::string` with the canonical textual representation of a UUID. |
|
||||
| `to_wstring()` | creates a `std::wstring` with the canonical textual representation of a UUID. |
|
||||
|
||||
This project is currently under development and should be ignored until further notice.
|
||||
| `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 commity and the C++ community feedback, this library implementation will reflect those changes. See the revision history of the proposal for history of changes.
|
||||
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());
|
||||
assert(empty.size() == 16);
|
||||
```
|
||||
```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.size() == 16);
|
||||
assert(id.version() == uuids::uuid_version::random_number_based);
|
||||
assert(id.variant() == uuids::uuid_variant::rfc);
|
||||
```
|
||||
```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
|
||||
uuids::uuid_random_generator gen;
|
||||
uuid const id = gen();
|
||||
assert(!id.is_nil());
|
||||
assert(id.size() == 16);
|
||||
assert(id.version() == uuids::uuid_version::random_number_based);
|
||||
assert(id.variant() == uuids::uuid_variant::rfc);
|
||||
```
|
||||
```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;
|
||||
std::ranlux48_base generator(rd());
|
||||
uuids::basic_uuid_random_generator<std::ranlux48_base> gen(&generator);
|
||||
uuid const id = gen();
|
||||
assert(!id.is_nil());
|
||||
assert(id.size() == 16);
|
||||
assert(id.version() == uuids::uuid_version::random_number_based);
|
||||
assert(id.variant() == uuids::uuid_variant::rfc);
|
||||
```
|
||||
```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;
|
||||
uuid const id = gen();
|
||||
```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.size() == 16);
|
||||
assert(id.version() == uuids::uuid_version::name_based_sha1);
|
||||
assert(id.variant() == uuids::uuid_variant::rfc);
|
||||
```
|
||||
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
|
||||
using namespace std::string_literals;
|
||||
```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);
|
||||
|
||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||
uuid id(uuids::uuid::from_string(str));
|
||||
assert(uuids::to_string(id) == str);
|
||||
// or
|
||||
|
||||
// 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);
|
||||
```
|
||||
|
||||
uuid id(uuids::uuid::from_string(L"{47183823-2574-4bfd-b411-99ed177d3e43}"s));
|
||||
assert(id.wstring() == str);
|
||||
```
|
||||
* Creating a UUID from a sequence of 16 bytes
|
||||
|
||||
* Creating a UUID from 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);
|
||||
|
||||
```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");
|
||||
|
||||
assert(uuids::to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
// or
|
||||
|
||||
// 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}};
|
||||
|
||||
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");
|
||||
```
|
||||
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);
|
||||
```
|
||||
```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{}();
|
||||
```cpp
|
||||
uuid empty;
|
||||
uuid id = uuids::uuid_system_generator{}();
|
||||
|
||||
assert(empty.is_nil());
|
||||
assert(!id.is_nil());
|
||||
assert(empty.is_nil());
|
||||
assert(!id.is_nil());
|
||||
|
||||
std::swap(empty, id);
|
||||
std::swap(empty, id);
|
||||
|
||||
assert(!empty.is_nil());
|
||||
assert(id.is_nil());
|
||||
assert(!empty.is_nil());
|
||||
assert(id.is_nil());
|
||||
|
||||
empty.swap(id);
|
||||
empty.swap(id);
|
||||
|
||||
assert(empty.is_nil());
|
||||
assert(!id.is_nil());
|
||||
```
|
||||
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_wstring(empty) == L"00000000-0000-0000-0000-000000000000");
|
||||
```
|
||||
|
||||
* Iterating through the UUID data
|
||||
|
||||
```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);
|
||||
|
||||
size_t i = 0;
|
||||
for (auto const & b : id)
|
||||
assert(arr[i++] == b);
|
||||
```
|
||||
```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
|
||||
uuids::uuid_random_generator gen;
|
||||
std::set<uuids::uuid> ids{uuid{}, gen(), gen(), gen(), gen()};
|
||||
```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());
|
||||
```
|
||||
assert(ids.size() == 5);
|
||||
assert(ids.find(uuid{}) != ids.end());
|
||||
```
|
||||
|
||||
* Using in an unordered associative container
|
||||
|
||||
```cpp
|
||||
uuids::uuid_random_generator gen;
|
||||
std::unordered_set<uuids::uuid> ids{uuid{}, gen(), gen(), gen(), gen()};
|
||||
```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);
|
||||
|
||||
assert(ids.size() == 5);
|
||||
assert(ids.find(uuid{}) != ids.end());
|
||||
```
|
||||
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));
|
||||
```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));
|
||||
```
|
||||
auto h1 = std::hash<std::string>{};
|
||||
auto h2 = std::hash<uuid>{};
|
||||
assert(h1(str) == h2(id));
|
||||
```
|
||||
|
||||
### Random uuids
|
||||
|
||||
If you generate uuids using the `basic_uuid_random_generator` and [std::random_device](https://en.cppreference.com/w/cpp/numeric/random/random_device) to seed a generator, keep in mind that this might not be non-deterministic and actually generate the same sequence of numbers:
|
||||
|
||||
> std::random_device may be implemented in terms of an implementation-defined pseudo-random number engine if a non-deterministic source (e.g. a hardware device) is not available to the implementation. In this case each std::random_device object may generate the same number sequence.
|
||||
|
||||
This could be a problem with MinGW. See [Bug 85494 - implementation of random_device on mingw is useless](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85494). This was fixed in GCC 9.2.
|
||||
|
||||
A portable alternative is to use the [Boost.Random](https://www.boost.org/doc/libs/1_78_0/doc/html/boost_random.html) library.
|
||||
|
||||
## 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).
|
||||
If you use the library in a project built with C++20, then you can use `std::span`. This is used by default, if the header is supported by your compiler. The check is done with the [__cpp_lib_span](https://en.cppreference.com/w/cpp/utility/feature_test) feature-test macro.
|
||||
|
||||
Otherwise, such as when building with C++17, `std::span` is not available. However, the [Microsoft Guidelines Support Library](https://github.com/Microsoft/GSL) (aka GSL) can be used for its `span` implementation (from which the standard version was defined). The stduuid library defaults to use this implementation if `std::span` is not available.
|
||||
|
||||
To ensure `gsl::span` can be used, make sure the GSL library is available, and the GSL include directory is listed in the include directories for the project.
|
||||
|
||||
If you use cmake to build the test project, make sure the variable called `UUID_USING_CXX20_SPAN` is not defined, or it's value is `OFF` (this is the default value). This will ensure the `gsl` directory will be included in the search list of header directories.
|
||||
|
||||
## Testing
|
||||
A testing project is available in the sources. To build and execute the tests do the following:
|
||||
@ -243,5 +287,25 @@ A testing project is available in the sources. To build and execute the tests do
|
||||
* Build the project created in the previous step
|
||||
* Run the executable.
|
||||
|
||||
**Examples**
|
||||
|
||||
To generate a project files for Visual Studio 2019, you can run the following commands:
|
||||
```
|
||||
cd build
|
||||
cmake -G "Visual Studio 17" -A x64 ..
|
||||
```
|
||||
|
||||
To enable the operating system uuid generator set the `UUID_SYSTEM_GENERATOR` variable to `ON`.
|
||||
```
|
||||
cd build
|
||||
cmake -G "Visual Studio 17" -A x64 -DUUID_SYSTEM_GENERATOR=ON ..
|
||||
```
|
||||
|
||||
To enable the experimental time-based uuid generator set the `UUID_TIME_GENERATOR` variable to `ON`.
|
||||
```
|
||||
cd build
|
||||
cmake -G "Visual Studio 17" -A x64 -DUUID_TIME_GENERATOR=ON ..
|
||||
```
|
||||
|
||||
## Credits
|
||||
The SHA1 implementation is based on the [TinySHA1](https://github.com/mohaps/TinySHA1) library.
|
||||
|
||||
35
appveyor.yml
Normal file
35
appveyor.yml
Normal file
@ -0,0 +1,35 @@
|
||||
version: '{build}'
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
CMAKE_GENERATOR: Visual Studio 16 2019
|
||||
CMAKE_GENERATOR_PLATFORM: Win32
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
CMAKE_GENERATOR: Visual Studio 16 2019
|
||||
CMAKE_GENERATOR_PLATFORM: x64
|
||||
CMAKE_CLI_FLAGS: -DUUID_SYSTEM_GENERATOR=ON -DUUID_TIME_GENERATOR=ON
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
CMAKE_GENERATOR: Visual Studio 17 2022
|
||||
CMAKE_GENERATOR_PLATFORM: Win32
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
CMAKE_GENERATOR: Visual Studio 17 2022
|
||||
CMAKE_GENERATOR_PLATFORM: x64
|
||||
CMAKE_CLI_FLAGS: -DUUID_SYSTEM_GENERATOR=ON -DUUID_TIME_GENERATOR=ON
|
||||
|
||||
init:
|
||||
- cmake --version
|
||||
- msbuild /version
|
||||
|
||||
before_build:
|
||||
- cmake %CMAKE_CLI_FLAGS% -S . -B build
|
||||
- cd build
|
||||
|
||||
build_script:
|
||||
- cmake --build . --config Release
|
||||
|
||||
test_script:
|
||||
- ctest -C Release -V -j
|
||||
8995
catch/catch.hpp
8995
catch/catch.hpp
File diff suppressed because it is too large
Load Diff
181
catch/catch_reporter_sonarqube.hpp
Normal file
181
catch/catch_reporter_sonarqube.hpp
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Created by Daniel Garcia on 2018-12-04.
|
||||
* Copyright Social Point SL. 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 CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
|
||||
#define CATCH_REPORTER_SONARQUBE_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 <map>
|
||||
|
||||
namespace Catch {
|
||||
|
||||
struct SonarQubeReporter : CumulativeReporterBase<SonarQubeReporter> {
|
||||
|
||||
SonarQubeReporter(ReporterConfig const& config)
|
||||
: CumulativeReporterBase(config)
|
||||
, xml(config.stream()) {
|
||||
m_reporterPrefs.shouldRedirectStdOut = true;
|
||||
m_reporterPrefs.shouldReportAllAssertions = true;
|
||||
}
|
||||
|
||||
~SonarQubeReporter() override;
|
||||
|
||||
static std::string getDescription() {
|
||||
return "Reports test results in the Generic Test Data SonarQube XML format";
|
||||
}
|
||||
|
||||
static std::set<Verbosity> getSupportedVerbosities() {
|
||||
return { Verbosity::Normal };
|
||||
}
|
||||
|
||||
void noMatchingTestCases(std::string const& /*spec*/) override {}
|
||||
|
||||
void testRunStarting(TestRunInfo const& testRunInfo) override {
|
||||
CumulativeReporterBase::testRunStarting(testRunInfo);
|
||||
xml.startElement("testExecutions");
|
||||
xml.writeAttribute("version", "1");
|
||||
}
|
||||
|
||||
void testGroupEnded(TestGroupStats const& testGroupStats) override {
|
||||
CumulativeReporterBase::testGroupEnded(testGroupStats);
|
||||
writeGroup(*m_testGroups.back());
|
||||
}
|
||||
|
||||
void testRunEndedCumulative() override {
|
||||
xml.endElement();
|
||||
}
|
||||
|
||||
void writeGroup(TestGroupNode const& groupNode) {
|
||||
std::map<std::string, TestGroupNode::ChildNodes> testsPerFile;
|
||||
for(auto const& child : groupNode.children)
|
||||
testsPerFile[child->value.testInfo.lineInfo.file].push_back(child);
|
||||
|
||||
for(auto const& kv : testsPerFile)
|
||||
writeTestFile(kv.first.c_str(), kv.second);
|
||||
}
|
||||
|
||||
void writeTestFile(const char* filename, TestGroupNode::ChildNodes const& testCaseNodes) {
|
||||
XmlWriter::ScopedElement e = xml.scopedElement("file");
|
||||
xml.writeAttribute("path", filename);
|
||||
|
||||
for(auto const& child : testCaseNodes)
|
||||
writeTestCase(*child);
|
||||
}
|
||||
|
||||
void writeTestCase(TestCaseNode const& testCaseNode) {
|
||||
// All test cases have exactly one section - which represents the
|
||||
// test case itself. That section may have 0-n nested sections
|
||||
assert(testCaseNode.children.size() == 1);
|
||||
SectionNode const& rootSection = *testCaseNode.children.front();
|
||||
writeSection("", rootSection, testCaseNode.value.testInfo.okToFail());
|
||||
}
|
||||
|
||||
void writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) {
|
||||
std::string name = trim(sectionNode.stats.sectionInfo.name);
|
||||
if(!rootName.empty())
|
||||
name = rootName + '/' + name;
|
||||
|
||||
if(!sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty()) {
|
||||
XmlWriter::ScopedElement e = xml.scopedElement("testCase");
|
||||
xml.writeAttribute("name", name);
|
||||
xml.writeAttribute("duration", static_cast<long>(sectionNode.stats.durationInSeconds * 1000));
|
||||
|
||||
writeAssertions(sectionNode, okToFail);
|
||||
}
|
||||
|
||||
for(auto const& childNode : sectionNode.childSections)
|
||||
writeSection(name, *childNode, okToFail);
|
||||
}
|
||||
|
||||
void writeAssertions(SectionNode const& sectionNode, bool okToFail) {
|
||||
for(auto const& assertion : sectionNode.assertions)
|
||||
writeAssertion( assertion, okToFail);
|
||||
}
|
||||
|
||||
void writeAssertion(AssertionStats const& stats, bool okToFail) {
|
||||
AssertionResult const& result = stats.assertionResult;
|
||||
if(!result.isOk()) {
|
||||
std::string elementName;
|
||||
if(okToFail) {
|
||||
elementName = "skipped";
|
||||
}
|
||||
else {
|
||||
switch(result.getResultType()) {
|
||||
case ResultWas::ThrewException:
|
||||
case ResultWas::FatalErrorCondition:
|
||||
elementName = "error";
|
||||
break;
|
||||
case ResultWas::ExplicitFailure:
|
||||
elementName = "failure";
|
||||
break;
|
||||
case ResultWas::ExpressionFailed:
|
||||
elementName = "failure";
|
||||
break;
|
||||
case ResultWas::DidntThrowException:
|
||||
elementName = "failure";
|
||||
break;
|
||||
|
||||
// We should never see these here:
|
||||
case ResultWas::Info:
|
||||
case ResultWas::Warning:
|
||||
case ResultWas::Ok:
|
||||
case ResultWas::Unknown:
|
||||
case ResultWas::FailureBit:
|
||||
case ResultWas::Exception:
|
||||
elementName = "internalError";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XmlWriter::ScopedElement e = xml.scopedElement(elementName);
|
||||
|
||||
ReusableStringStream messageRss;
|
||||
messageRss << result.getTestMacroName() << "(" << result.getExpression() << ")";
|
||||
xml.writeAttribute("message", messageRss.str());
|
||||
|
||||
ReusableStringStream textRss;
|
||||
if (stats.totals.assertions.total() > 0) {
|
||||
textRss << "FAILED:\n";
|
||||
if (result.hasExpression()) {
|
||||
textRss << "\t" << result.getExpressionInMacro() << "\n";
|
||||
}
|
||||
if (result.hasExpandedExpression()) {
|
||||
textRss << "with expansion:\n\t" << result.getExpandedExpression() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if(!result.getMessage().empty())
|
||||
textRss << result.getMessage() << "\n";
|
||||
|
||||
for(auto const& msg : stats.infoMessages)
|
||||
if(msg.type == ResultWas::Info)
|
||||
textRss << msg.message << "\n";
|
||||
|
||||
textRss << "at " << result.getSourceInfo();
|
||||
xml.writeText(textRss.str(), XmlFormatting::Newline);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
XmlWriter xml;
|
||||
};
|
||||
|
||||
#ifdef CATCH_IMPL
|
||||
SonarQubeReporter::~SonarQubeReporter() {}
|
||||
#endif
|
||||
|
||||
CATCH_REGISTER_REPORTER( "sonarqube", SonarQubeReporter )
|
||||
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
|
||||
@ -23,18 +23,17 @@ namespace Catch {
|
||||
|
||||
using StreamingReporterBase::StreamingReporterBase;
|
||||
|
||||
TAPReporter( ReporterConfig const& config ):
|
||||
StreamingReporterBase( config ) {
|
||||
m_reporterPrefs.shouldReportAllAssertions = true;
|
||||
}
|
||||
|
||||
~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;
|
||||
}
|
||||
@ -44,9 +43,9 @@ namespace Catch {
|
||||
bool assertionEnded( AssertionStats const& _assertionStats ) override {
|
||||
++counter;
|
||||
|
||||
stream << "# " << currentTestCaseInfo->name << std::endl;
|
||||
AssertionPrinter printer( stream, _assertionStats, counter );
|
||||
printer.print();
|
||||
stream << " # " << currentTestCaseInfo->name ;
|
||||
|
||||
stream << std::endl;
|
||||
return true;
|
||||
@ -205,16 +204,15 @@ namespace Catch {
|
||||
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 ) );
|
||||
const auto itEnd = messages.cend();
|
||||
const auto N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
|
||||
|
||||
{
|
||||
Colour colourGuard( colour );
|
||||
stream << " with " << pluralise( N, "message" ) << ":";
|
||||
}
|
||||
|
||||
for(; itMessage != itEnd; ) {
|
||||
while( itMessage != itEnd ) {
|
||||
// If this assertion is a warning ignore any INFO messages
|
||||
if( printInfoMessages || itMessage->type != ResultWas::Info ) {
|
||||
stream << " '" << itMessage->message << "'";
|
||||
@ -222,7 +220,9 @@ namespace Catch {
|
||||
Colour colourGuard( dimColour() );
|
||||
stream << " and";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
++itMessage;
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,10 +236,9 @@ namespace Catch {
|
||||
};
|
||||
|
||||
void printTotals( const Totals& totals ) const {
|
||||
stream << "1.." << totals.assertions.total();
|
||||
if( totals.testCases.total() == 0 ) {
|
||||
stream << "1..0 # Skipped: No tests ran.";
|
||||
} else {
|
||||
stream << "1.." << counter;
|
||||
stream << " # Skipped: No tests ran.";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -97,12 +97,12 @@ namespace Catch {
|
||||
case ResultWas::Ok:
|
||||
case ResultWas::Info:
|
||||
case ResultWas::Warning:
|
||||
throw std::domain_error( "Internal error in TeamCity reporter" );
|
||||
CATCH_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" );
|
||||
CATCH_ERROR( "Not implemented" );
|
||||
}
|
||||
if( assertionStats.infoMessages.size() == 1 )
|
||||
msg << " with message:";
|
||||
@ -183,8 +183,7 @@ namespace Catch {
|
||||
|
||||
SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
|
||||
|
||||
if( !lineInfo.empty() )
|
||||
os << lineInfo << "\n";
|
||||
os << lineInfo << "\n";
|
||||
os << getLineOfChars<'.'>() << "\n\n";
|
||||
}
|
||||
|
||||
|
||||
14
cmake/Config.cmake.in
Normal file
14
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
cmake/FindLibuuid.cmake
Normal file
17
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 ()
|
||||
@ -17,13 +17,13 @@
|
||||
#ifndef GSL_GSL_H
|
||||
#define GSL_GSL_H
|
||||
|
||||
#include <gsl/gsl_algorithm> // copy
|
||||
#include <gsl/gsl_assert> // Ensures/Expects
|
||||
#include <gsl/gsl_byte> // byte
|
||||
#include <gsl/gsl_util> // finally()/narrow()/narrow_cast()...
|
||||
#include <gsl/multi_span> // multi_span, strided_span...
|
||||
#include <gsl/pointers> // owner, not_null
|
||||
#include <gsl/span> // span
|
||||
#include <gsl/string_span> // zstring, string_span, zstring_builder...
|
||||
#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
|
||||
@ -17,8 +17,8 @@
|
||||
#ifndef GSL_ALGORITHM_H
|
||||
#define GSL_ALGORITHM_H
|
||||
|
||||
#include <gsl/gsl_assert> // for Expects
|
||||
#include <gsl/span> // for dynamic_extent, span
|
||||
#include "gsl_assert" // for Expects
|
||||
#include "span" // for dynamic_extent, span
|
||||
|
||||
#include <algorithm> // for copy_n
|
||||
#include <cstddef> // for ptrdiff_t
|
||||
@ -17,7 +17,7 @@
|
||||
#ifndef GSL_UTIL_H
|
||||
#define GSL_UTIL_H
|
||||
|
||||
#include <gsl/gsl_assert> // for Expects
|
||||
#include "gsl_assert" // for Expects
|
||||
|
||||
#include <array>
|
||||
#include <cstddef> // for ptrdiff_t, size_t
|
||||
@ -17,9 +17,9 @@
|
||||
#ifndef GSL_MULTI_SPAN_H
|
||||
#define GSL_MULTI_SPAN_H
|
||||
|
||||
#include <gsl/gsl_assert> // for Expects
|
||||
#include <gsl/gsl_byte> // for byte
|
||||
#include <gsl/gsl_util> // for narrow_cast
|
||||
#include "gsl_assert" // for Expects
|
||||
#include "gsl_byte" // for byte
|
||||
#include "gsl_util" // for narrow_cast
|
||||
|
||||
#include <algorithm> // for transform, lexicographical_compare
|
||||
#include <array> // for array
|
||||
@ -17,7 +17,7 @@
|
||||
#ifndef GSL_POINTERS_H
|
||||
#define GSL_POINTERS_H
|
||||
|
||||
#include <gsl/gsl_assert> // for Ensures, Expects
|
||||
#include "gsl_assert" // for Ensures, Expects
|
||||
|
||||
#include <algorithm> // for forward
|
||||
#include <iosfwd> // for ptrdiff_t, nullptr_t, ostream, size_t
|
||||
@ -17,9 +17,9 @@
|
||||
#ifndef GSL_SPAN_H
|
||||
#define GSL_SPAN_H
|
||||
|
||||
#include <gsl/gsl_assert> // for Expects
|
||||
#include <gsl/gsl_byte> // for byte
|
||||
#include <gsl/gsl_util> // for narrow_cast, narrow
|
||||
#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
|
||||
@ -17,9 +17,9 @@
|
||||
#ifndef GSL_STRING_SPAN_H
|
||||
#define GSL_STRING_SPAN_H
|
||||
|
||||
#include <gsl/gsl_assert> // for Ensures, Expects
|
||||
#include <gsl/gsl_util> // for narrow_cast
|
||||
#include <gsl/span> // for operator!=, operator==, dynamic_extent
|
||||
#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
|
||||
736
include/uuid.h
736
include/uuid.h
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef STDUUID_H
|
||||
#define STDUUID_H
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
@ -11,35 +12,84 @@
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <assert.h>
|
||||
#include <optional>
|
||||
#include <chrono>
|
||||
#include <numeric>
|
||||
#include <atomic>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
# if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
|
||||
# define LIBUUID_CPP20_OR_GREATER
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef LIBUUID_CPP20_OR_GREATER
|
||||
#include <span>
|
||||
#else
|
||||
#include <gsl/span>
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#ifdef UUID_TIME_GENERATOR
|
||||
#include <iphlpapi.h>
|
||||
#pragma comment(lib, "IPHLPAPI.lib")
|
||||
#endif
|
||||
|
||||
#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)
|
||||
[[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept
|
||||
{
|
||||
if (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9'))
|
||||
return ch - static_cast<TChar>('0');
|
||||
return static_cast<unsigned char>(ch - static_cast<TChar>('0'));
|
||||
if (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f'))
|
||||
return 10 + ch - static_cast<TChar>('a');
|
||||
return static_cast<unsigned char>(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 static_cast<unsigned char>(10 + ch - static_cast<TChar>('A'));
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename TChar>
|
||||
constexpr inline bool is_hex(TChar const ch)
|
||||
[[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept
|
||||
{
|
||||
return
|
||||
(ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9')) ||
|
||||
@ -48,9 +98,20 @@ namespace uuids
|
||||
}
|
||||
|
||||
template <typename TChar>
|
||||
constexpr inline unsigned char hexpair2char(TChar const a, TChar const b)
|
||||
[[nodiscard]] constexpr std::basic_string_view<TChar> to_string_view(TChar const * str) noexcept
|
||||
{
|
||||
return (hex2char(a) << 4) | hex2char(b);
|
||||
if (str) return str;
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename StringType>
|
||||
[[nodiscard]]
|
||||
constexpr std::basic_string_view<
|
||||
typename StringType::value_type,
|
||||
typename StringType::traits_type>
|
||||
to_string_view(StringType const & str) noexcept
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
class sha1
|
||||
@ -61,14 +122,14 @@ namespace uuids
|
||||
|
||||
static constexpr unsigned int block_bytes = 64;
|
||||
|
||||
inline static uint32_t left_rotate(uint32_t value, size_t const count)
|
||||
[[nodiscard]] inline static uint32_t left_rotate(uint32_t value, size_t const count) noexcept
|
||||
{
|
||||
return (value << count) ^ (value >> (32 - count));
|
||||
}
|
||||
|
||||
sha1() { reset(); }
|
||||
|
||||
void reset()
|
||||
void reset() noexcept
|
||||
{
|
||||
m_digest[0] = 0x67452301;
|
||||
m_digest[1] = 0xEFCDAB89;
|
||||
@ -142,30 +203,30 @@ namespace uuids
|
||||
digest32_t d32;
|
||||
get_digest(d32);
|
||||
size_t di = 0;
|
||||
digest[di++] = ((d32[0] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[0] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[0] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[0]) & 0xFF);
|
||||
digest[di++] = static_cast<uint8_t>(d32[0] >> 24);
|
||||
digest[di++] = static_cast<uint8_t>(d32[0] >> 16);
|
||||
digest[di++] = static_cast<uint8_t>(d32[0] >> 8);
|
||||
digest[di++] = static_cast<uint8_t>(d32[0] >> 0);
|
||||
|
||||
digest[di++] = ((d32[1] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[1] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[1] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[1]) & 0xFF);
|
||||
digest[di++] = static_cast<uint8_t>(d32[1] >> 24);
|
||||
digest[di++] = static_cast<uint8_t>(d32[1] >> 16);
|
||||
digest[di++] = static_cast<uint8_t>(d32[1] >> 8);
|
||||
digest[di++] = static_cast<uint8_t>(d32[1] >> 0);
|
||||
|
||||
digest[di++] = ((d32[2] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[2] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[2] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[2]) & 0xFF);
|
||||
digest[di++] = static_cast<uint8_t>(d32[2] >> 24);
|
||||
digest[di++] = static_cast<uint8_t>(d32[2] >> 16);
|
||||
digest[di++] = static_cast<uint8_t>(d32[2] >> 8);
|
||||
digest[di++] = static_cast<uint8_t>(d32[2] >> 0);
|
||||
|
||||
digest[di++] = ((d32[3] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[3] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[3] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[3]) & 0xFF);
|
||||
digest[di++] = static_cast<uint8_t>(d32[3] >> 24);
|
||||
digest[di++] = static_cast<uint8_t>(d32[3] >> 16);
|
||||
digest[di++] = static_cast<uint8_t>(d32[3] >> 8);
|
||||
digest[di++] = static_cast<uint8_t>(d32[3] >> 0);
|
||||
|
||||
digest[di++] = ((d32[4] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[4] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[4] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[4]) & 0xFF);
|
||||
digest[di++] = static_cast<uint8_t>(d32[4] >> 24);
|
||||
digest[di++] = static_cast<uint8_t>(d32[4] >> 16);
|
||||
digest[di++] = static_cast<uint8_t>(d32[4] >> 8);
|
||||
digest[di++] = static_cast<uint8_t>(d32[4] >> 0);
|
||||
|
||||
return digest;
|
||||
}
|
||||
@ -175,10 +236,10 @@ namespace uuids
|
||||
{
|
||||
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]);
|
||||
w[i] = static_cast<uint32_t>(m_block[i * 4 + 0] << 24);
|
||||
w[i] |= static_cast<uint32_t>(m_block[i * 4 + 1] << 16);
|
||||
w[i] |= static_cast<uint32_t>(m_block[i * 4 + 2] << 8);
|
||||
w[i] |= static_cast<uint32_t>(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);
|
||||
@ -232,9 +293,25 @@ namespace uuids
|
||||
size_t m_blockByteIndex;
|
||||
size_t m_byteCount;
|
||||
};
|
||||
|
||||
template <typename CharT>
|
||||
inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000";
|
||||
|
||||
template <>
|
||||
inline constexpr wchar_t empty_guid<wchar_t>[37] = L"00000000-0000-0000-0000-000000000000";
|
||||
|
||||
template <typename CharT>
|
||||
inline constexpr CharT guid_encoder[17] = "0123456789abcdef";
|
||||
|
||||
template <>
|
||||
inline constexpr wchar_t guid_encoder<wchar_t>[17] = L"0123456789abcdef";
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------------
|
||||
// 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.
|
||||
@ -256,6 +333,10 @@ namespace uuids
|
||||
// | 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
|
||||
{
|
||||
@ -283,20 +364,7 @@ namespace uuids
|
||||
reserved
|
||||
};
|
||||
|
||||
struct uuid_error : public std::runtime_error
|
||||
{
|
||||
explicit uuid_error(std::string_view message)
|
||||
: std::runtime_error(message.data())
|
||||
{
|
||||
}
|
||||
|
||||
explicit uuid_error(char const * message)
|
||||
: std::runtime_error(message)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// indicated by a bit pattern in octet 6, marked with M in xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx
|
||||
// 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
|
||||
@ -307,159 +375,31 @@ namespace uuids
|
||||
name_based_sha1 = 5 // The name-based version specified in RFS 4122 with SHA1 hashing
|
||||
};
|
||||
|
||||
struct uuid
|
||||
// Forward declare uuid & to_string so that we can declare to_string as a friend later.
|
||||
class uuid;
|
||||
template <class CharT = char,
|
||||
class Traits = std::char_traits<CharT>,
|
||||
class Allocator = std::allocator<CharT>>
|
||||
std::basic_string<CharT, Traits, Allocator> to_string(uuid const &id);
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------------
|
||||
// uuid class
|
||||
// --------------------------------------------------------------------------------------------------------------------------
|
||||
class uuid
|
||||
{
|
||||
struct uuid_const_iterator
|
||||
{
|
||||
using self_type = uuid_const_iterator;
|
||||
using value_type = uint8_t;
|
||||
using reference = uint8_t const &;
|
||||
using pointer = uint8_t const *;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
protected:
|
||||
pointer ptr = nullptr;
|
||||
size_t index = 0;
|
||||
|
||||
bool compatible(self_type const & other) const noexcept
|
||||
{
|
||||
return ptr == other.ptr;
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr explicit uuid_const_iterator(pointer ptr, size_t const index) :
|
||||
ptr(ptr), index(index)
|
||||
{
|
||||
}
|
||||
|
||||
uuid_const_iterator(uuid_const_iterator const & o) = default;
|
||||
uuid_const_iterator& operator=(uuid_const_iterator const & o) = default;
|
||||
~uuid_const_iterator() = default;
|
||||
|
||||
self_type & operator++ ()
|
||||
{
|
||||
if (index >= 16)
|
||||
throw std::out_of_range("Iterator cannot be incremented past the end of the data.");
|
||||
++index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
self_type operator++ (int)
|
||||
{
|
||||
self_type tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator== (self_type const & other) const
|
||||
{
|
||||
assert(compatible(other));
|
||||
return index == other.index;
|
||||
}
|
||||
|
||||
bool operator!= (self_type const & other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
reference operator* () const
|
||||
{
|
||||
if (ptr == nullptr)
|
||||
throw std::bad_function_call();
|
||||
return *(ptr + index);
|
||||
}
|
||||
|
||||
reference operator-> () const
|
||||
{
|
||||
if (ptr == nullptr)
|
||||
throw std::bad_function_call();
|
||||
return *(ptr + index);
|
||||
}
|
||||
|
||||
uuid_const_iterator() = default;
|
||||
|
||||
self_type & operator--()
|
||||
{
|
||||
if (index <= 0)
|
||||
throw std::out_of_range("Iterator cannot be decremented past the beginning of the data.");
|
||||
--index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
self_type operator--(int)
|
||||
{
|
||||
self_type tmp = *this;
|
||||
--*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
self_type operator+(difference_type offset) const
|
||||
{
|
||||
self_type tmp = *this;
|
||||
return tmp += offset;
|
||||
}
|
||||
|
||||
self_type operator-(difference_type offset) const
|
||||
{
|
||||
self_type tmp = *this;
|
||||
return tmp -= offset;
|
||||
}
|
||||
|
||||
difference_type operator-(self_type const & other) const
|
||||
{
|
||||
assert(compatible(other));
|
||||
return (index - other.index);
|
||||
}
|
||||
|
||||
bool operator<(self_type const & other) const
|
||||
{
|
||||
assert(compatible(other));
|
||||
return index < other.index;
|
||||
}
|
||||
|
||||
bool operator>(self_type const & other) const
|
||||
{
|
||||
return other < *this;
|
||||
}
|
||||
|
||||
bool operator<=(self_type const & other) const
|
||||
{
|
||||
return !(other < *this);
|
||||
}
|
||||
|
||||
bool operator>=(self_type const & other) const
|
||||
{
|
||||
return !(*this < other);
|
||||
}
|
||||
|
||||
self_type & operator+=(difference_type const offset)
|
||||
{
|
||||
if (static_cast<difference_type>(index) + offset < 0 ||
|
||||
static_cast<difference_type>(index) + offset > 16)
|
||||
throw std::out_of_range("Iterator cannot be incremented outside data bounds.");
|
||||
|
||||
index += offset;
|
||||
return *this;
|
||||
}
|
||||
|
||||
self_type & operator-=(difference_type const offset)
|
||||
{
|
||||
return *this += -offset;
|
||||
}
|
||||
|
||||
value_type const & operator[](difference_type const offset) const
|
||||
{
|
||||
return (*(*this + offset));
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
using value_type = uint8_t;
|
||||
|
||||
public:
|
||||
constexpr uuid() noexcept : data({}) {};
|
||||
constexpr uuid() noexcept = default;
|
||||
|
||||
explicit uuid(gsl::span<value_type, 16> bytes)
|
||||
uuid(value_type(&arr)[16]) noexcept
|
||||
{
|
||||
std::copy(std::cbegin(arr), std::cend(arr), std::begin(data));
|
||||
}
|
||||
|
||||
constexpr uuid(std::array<value_type, 16> const & arr) noexcept : data{arr} {}
|
||||
|
||||
explicit uuid(span<value_type, 16> bytes)
|
||||
{
|
||||
std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data));
|
||||
}
|
||||
@ -471,7 +411,7 @@ namespace uuids
|
||||
std::copy(first, last, std::begin(data));
|
||||
}
|
||||
|
||||
constexpr uuid_variant variant() const noexcept
|
||||
[[nodiscard]] constexpr uuid_variant variant() const noexcept
|
||||
{
|
||||
if ((data[8] & 0x80) == 0x00)
|
||||
return uuid_variant::ncs;
|
||||
@ -483,7 +423,7 @@ namespace uuids
|
||||
return uuid_variant::reserved;
|
||||
}
|
||||
|
||||
constexpr uuid_version version() const noexcept
|
||||
[[nodiscard]] constexpr uuid_version version() const noexcept
|
||||
{
|
||||
if ((data[6] & 0xF0) == 0x10)
|
||||
return uuid_version::time_based;
|
||||
@ -499,9 +439,7 @@ namespace uuids
|
||||
return uuid_version::none;
|
||||
}
|
||||
|
||||
constexpr std::size_t size() const noexcept { return 16; }
|
||||
|
||||
constexpr bool is_nil() const noexcept
|
||||
[[nodiscard]] constexpr bool is_nil() const noexcept
|
||||
{
|
||||
for (size_t i = 0; i < data.size(); ++i) if (data[i] != 0) return false;
|
||||
return true;
|
||||
@ -512,68 +450,100 @@ namespace uuids
|
||||
data.swap(other.data);
|
||||
}
|
||||
|
||||
constexpr uuid_const_iterator begin() const noexcept { return uuid_const_iterator(&data[0], 0); }
|
||||
constexpr uuid_const_iterator end() const noexcept { return uuid_const_iterator(&data[0], 16); }
|
||||
|
||||
inline gsl::span<std::byte const, 16> as_bytes() const
|
||||
[[nodiscard]] inline span<std::byte const, 16> as_bytes() const
|
||||
{
|
||||
return gsl::span<std::byte const, 16>(reinterpret_cast<std::byte const*>(data.data()), 16);
|
||||
return span<std::byte const, 16>(reinterpret_cast<std::byte const*>(data.data()), 16);
|
||||
}
|
||||
|
||||
template <typename TChar>
|
||||
static uuid from_string(TChar const * const str, size_t const size)
|
||||
template <typename StringType>
|
||||
[[nodiscard]] constexpr static bool is_valid_uuid(StringType const & in_str) noexcept
|
||||
{
|
||||
TChar digit = 0;
|
||||
auto str = detail::to_string_view(in_str);
|
||||
bool firstDigit = true;
|
||||
int hasBraces = 0;
|
||||
size_t hasBraces = 0;
|
||||
size_t index = 0;
|
||||
std::array<uint8_t, 16> data{ { 0 } };
|
||||
|
||||
if (str == nullptr || size == 0)
|
||||
throw uuid_error{ "Wrong uuid format" };
|
||||
if (str.empty())
|
||||
return false;
|
||||
|
||||
if (str[0] == static_cast<TChar>('{'))
|
||||
if (str.front() == '{')
|
||||
hasBraces = 1;
|
||||
if (hasBraces && str[size - 1] != static_cast<TChar>('}'))
|
||||
throw uuid_error{ "Wrong uuid format" };
|
||||
if (hasBraces && str.back() != '}')
|
||||
return false;
|
||||
|
||||
for (size_t i = hasBraces; i < size - hasBraces; ++i)
|
||||
for (size_t i = hasBraces; i < str.size() - hasBraces; ++i)
|
||||
{
|
||||
if (str[i] == static_cast<TChar>('-')) continue;
|
||||
if (str[i] == '-') continue;
|
||||
|
||||
if (index >= 16 || !detail::is_hex(str[i]))
|
||||
{
|
||||
throw uuid_error{ "Wrong uuid format" };
|
||||
return false;
|
||||
}
|
||||
|
||||
if (firstDigit)
|
||||
{
|
||||
digit = str[i];
|
||||
firstDigit = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
data[index++] = detail::hexpair2char(digit, str[i]);
|
||||
index++;
|
||||
firstDigit = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 16)
|
||||
{
|
||||
throw uuid_error{ "Wrong uuid format" };
|
||||
return false;
|
||||
}
|
||||
|
||||
return uuid{ std::cbegin(data), std::cend(data) };
|
||||
return true;
|
||||
}
|
||||
|
||||
static uuid from_string(std::string_view str)
|
||||
template <typename StringType>
|
||||
[[nodiscard]] constexpr static std::optional<uuid> from_string(StringType const & in_str) noexcept
|
||||
{
|
||||
return from_string(str.data(), str.size());
|
||||
}
|
||||
auto str = detail::to_string_view(in_str);
|
||||
bool firstDigit = true;
|
||||
size_t hasBraces = 0;
|
||||
size_t index = 0;
|
||||
|
||||
static uuid from_string(std::wstring_view str)
|
||||
{
|
||||
return from_string(str.data(), str.size());
|
||||
std::array<uint8_t, 16> data{ { 0 } };
|
||||
|
||||
if (str.empty()) return {};
|
||||
|
||||
if (str.front() == '{')
|
||||
hasBraces = 1;
|
||||
if (hasBraces && str.back() != '}')
|
||||
return {};
|
||||
|
||||
for (size_t i = hasBraces; i < str.size() - hasBraces; ++i)
|
||||
{
|
||||
if (str[i] == '-') continue;
|
||||
|
||||
if (index >= 16 || !detail::is_hex(str[i]))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
if (firstDigit)
|
||||
{
|
||||
data[index] = static_cast<uint8_t>(detail::hex2char(str[i]) << 4);
|
||||
firstDigit = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
data[index] = static_cast<uint8_t>(data[index] | detail::hex2char(str[i]));
|
||||
index++;
|
||||
firstDigit = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 16)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return uuid{ data };
|
||||
}
|
||||
|
||||
private:
|
||||
@ -583,69 +553,87 @@ namespace uuids
|
||||
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);
|
||||
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
|
||||
|
||||
template<class CharT, class Traits, class Allocator>
|
||||
friend std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id);
|
||||
|
||||
friend std::hash<uuid>;
|
||||
};
|
||||
|
||||
inline bool operator== (uuid const& lhs, uuid const& rhs) noexcept
|
||||
// --------------------------------------------------------------------------------------------------------------------------
|
||||
// operators and non-member functions
|
||||
// --------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] 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
|
||||
[[nodiscard]] inline bool operator!= (uuid const& lhs, uuid const& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
inline bool operator< (uuid const& lhs, uuid const& rhs) noexcept
|
||||
[[nodiscard]] inline bool operator< (uuid const& lhs, uuid const& rhs) noexcept
|
||||
{
|
||||
return lhs.data < rhs.data;
|
||||
}
|
||||
|
||||
template <class CharT,
|
||||
class Traits,
|
||||
class Allocator>
|
||||
[[nodiscard]] inline std::basic_string<CharT, Traits, Allocator> to_string(uuid const & id)
|
||||
{
|
||||
std::basic_string<CharT, Traits, Allocator> uustr{detail::empty_guid<CharT>};
|
||||
|
||||
for (size_t i = 0, index = 0; i < 36; ++i)
|
||||
{
|
||||
if (i == 8 || i == 13 || i == 18 || i == 23)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
uustr[i] = detail::guid_encoder<CharT>[id.data[index] >> 4 & 0x0f];
|
||||
uustr[++i] = detail::guid_encoder<CharT>[id.data[index] & 0x0f];
|
||||
index++;
|
||||
}
|
||||
|
||||
return uustr;
|
||||
}
|
||||
|
||||
template <class Elem, class Traits>
|
||||
std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id)
|
||||
std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& s, uuid const& id)
|
||||
{
|
||||
return 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];
|
||||
s << to_string(id);
|
||||
return s;
|
||||
}
|
||||
|
||||
inline std::string to_string(uuid const & id)
|
||||
inline void swap(uuids::uuid & lhs, uuids::uuid & rhs) noexcept
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << id;
|
||||
return sstr.str();
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
inline std::wstring to_wstring(uuid const & id)
|
||||
{
|
||||
std::wstringstream sstr;
|
||||
sstr << id;
|
||||
return sstr.str();
|
||||
}
|
||||
// --------------------------------------------------------------------------------------------------------------------------
|
||||
// namespace IDs that could be used for generating name-based uuids
|
||||
// --------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
inline void swap(uuids::uuid & lhs, uuids::uuid & rhs)
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
// 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:
|
||||
@ -656,14 +644,19 @@ namespace uuids
|
||||
#ifdef _WIN32
|
||||
|
||||
GUID newId;
|
||||
::CoCreateGuid(&newId);
|
||||
HRESULT hr = ::CoCreateGuid(&newId);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
throw std::system_error(hr, std::system_category(), "CoCreateGuid failed");
|
||||
}
|
||||
|
||||
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),
|
||||
static_cast<unsigned char>((newId.Data1 >> 24) & 0xFF),
|
||||
static_cast<unsigned char>((newId.Data1 >> 16) & 0xFF),
|
||||
static_cast<unsigned char>((newId.Data1 >> 8) & 0xFF),
|
||||
static_cast<unsigned char>((newId.Data1) & 0xFF),
|
||||
|
||||
(unsigned char)((newId.Data2 >> 8) & 0xFF),
|
||||
(unsigned char)((newId.Data2) & 0xFF),
|
||||
@ -735,33 +728,27 @@ namespace uuids
|
||||
bytes.byte15
|
||||
} };
|
||||
return uuid{ std::begin(arrbytes), std::end(arrbytes) };
|
||||
#elif
|
||||
#else
|
||||
return uuid{};
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename UniformRandomNumberGenerator>
|
||||
class basic_uuid_random_generator
|
||||
class basic_uuid_random_generator
|
||||
{
|
||||
public:
|
||||
using result_type = uuid;
|
||||
using engine_type = UniformRandomNumberGenerator;
|
||||
|
||||
basic_uuid_random_generator()
|
||||
:generator(new UniformRandomNumberGenerator)
|
||||
{
|
||||
std::random_device rd;
|
||||
generator->seed(rd());
|
||||
}
|
||||
|
||||
explicit basic_uuid_random_generator(UniformRandomNumberGenerator& gen) :
|
||||
explicit basic_uuid_random_generator(engine_type& gen) :
|
||||
generator(&gen, [](auto) {}) {}
|
||||
explicit basic_uuid_random_generator(UniformRandomNumberGenerator* gen) :
|
||||
explicit basic_uuid_random_generator(engine_type* gen) :
|
||||
generator(gen, [](auto) {}) {}
|
||||
|
||||
uuid operator()()
|
||||
[[nodiscard]] uuid operator()()
|
||||
{
|
||||
uint8_t bytes[16];
|
||||
alignas(uint32_t) uint8_t bytes[16];
|
||||
for (int i = 0; i < 16; i += 4)
|
||||
*reinterpret_cast<uint32_t*>(bytes + i) = distribution(*generator);
|
||||
|
||||
@ -786,23 +773,15 @@ namespace uuids
|
||||
class uuid_name_generator
|
||||
{
|
||||
public:
|
||||
using result_type = uuid;
|
||||
|
||||
explicit uuid_name_generator(uuid const& namespace_uuid) noexcept
|
||||
: nsuuid(namespace_uuid)
|
||||
{}
|
||||
|
||||
uuid operator()(std::string_view name)
|
||||
template <typename StringType>
|
||||
[[nodiscard]] uuid operator()(StringType const & name)
|
||||
{
|
||||
reset();
|
||||
process_characters(name.data(), name.size());
|
||||
return make_uuid();
|
||||
}
|
||||
|
||||
uuid operator()(std::wstring_view name)
|
||||
{
|
||||
reset();
|
||||
process_characters(name.data(), name.size());
|
||||
process_characters(detail::to_string_view(name));
|
||||
return make_uuid();
|
||||
}
|
||||
|
||||
@ -810,31 +789,28 @@ namespace uuids
|
||||
void reset()
|
||||
{
|
||||
hasher.reset();
|
||||
uint8_t bytes[16];
|
||||
std::copy(std::begin(nsuuid), std::end(nsuuid), bytes);
|
||||
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)
|
||||
|
||||
template <typename CharT, typename Traits>
|
||||
void process_characters(std::basic_string_view<CharT, Traits> const str)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
for (uint32_t c : str)
|
||||
{
|
||||
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));
|
||||
hasher.process_byte(static_cast<uint8_t>(c & 0xFF));
|
||||
if constexpr (!std::is_same_v<CharT, char>)
|
||||
{
|
||||
hasher.process_byte(static_cast<uint8_t>((c >> 8) & 0xFF));
|
||||
hasher.process_byte(static_cast<uint8_t>((c >> 16) & 0xFF));
|
||||
hasher.process_byte(static_cast<uint8_t>((c >> 24) & 0xFF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void process_characters(const char * const characters, size_t const count)
|
||||
{
|
||||
hasher.process_bytes(characters, count);
|
||||
}
|
||||
|
||||
uuid make_uuid()
|
||||
[[nodiscard]] uuid make_uuid()
|
||||
{
|
||||
detail::sha1::digest8_t digest;
|
||||
hasher.get_digest_bytes(digest);
|
||||
@ -853,7 +829,92 @@ namespace uuids
|
||||
private:
|
||||
uuid nsuuid;
|
||||
detail::sha1 hasher;
|
||||
};
|
||||
};
|
||||
|
||||
#ifdef UUID_TIME_GENERATOR
|
||||
// !!! 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;
|
||||
|
||||
[[nodiscard]] 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();
|
||||
}
|
||||
|
||||
[[nodiscard]] 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;
|
||||
}
|
||||
|
||||
[[nodiscard]] static unsigned short get_clock_sequence()
|
||||
{
|
||||
static std::mt19937 clock_gen(std::random_device{}());
|
||||
static std::uniform_int_distribution<unsigned short> clock_dis;
|
||||
static std::atomic_ushort clock_sequence = clock_dis(clock_gen);
|
||||
return clock_sequence++;
|
||||
}
|
||||
|
||||
public:
|
||||
[[nodiscard]] uuid operator()()
|
||||
{
|
||||
if (get_mac_address())
|
||||
{
|
||||
std::array<uuids::uuid::value_type, 16> data;
|
||||
|
||||
auto tm = get_time_intervals();
|
||||
|
||||
auto clock_seq = get_clock_sequence();
|
||||
|
||||
auto ptm = reinterpret_cast<uuids::uuid::value_type*>(&tm);
|
||||
|
||||
memcpy(&data[0], ptm + 4, 4);
|
||||
memcpy(&data[4], ptm + 2, 2);
|
||||
memcpy(&data[6], ptm, 2);
|
||||
|
||||
memcpy(&data[8], &clock_seq, 2);
|
||||
|
||||
// variant must be 0b10xxxxxx
|
||||
data[8] &= 0xBF;
|
||||
data[8] |= 0x80;
|
||||
|
||||
// version must be 0b0001xxxx
|
||||
data[6] &= 0x1F;
|
||||
data[6] |= 0x10;
|
||||
|
||||
memcpy(&data[10], &device_address.value()[0], 6);
|
||||
|
||||
return uuids::uuid{std::cbegin(data), std::cend(data)};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace std
|
||||
@ -864,10 +925,43 @@ namespace std
|
||||
using argument_type = uuids::uuid;
|
||||
using result_type = std::size_t;
|
||||
|
||||
result_type operator()(argument_type const &uuid) const
|
||||
[[nodiscard]] result_type operator()(argument_type const &uuid) const
|
||||
{
|
||||
#ifdef UUID_HASH_STRING_BASED
|
||||
std::hash<std::string> hasher;
|
||||
return static_cast<result_type>(hasher(uuids::to_string(uuid)));
|
||||
#else
|
||||
uint64_t l =
|
||||
static_cast<uint64_t>(uuid.data[0]) << 56 |
|
||||
static_cast<uint64_t>(uuid.data[1]) << 48 |
|
||||
static_cast<uint64_t>(uuid.data[2]) << 40 |
|
||||
static_cast<uint64_t>(uuid.data[3]) << 32 |
|
||||
static_cast<uint64_t>(uuid.data[4]) << 24 |
|
||||
static_cast<uint64_t>(uuid.data[5]) << 16 |
|
||||
static_cast<uint64_t>(uuid.data[6]) << 8 |
|
||||
static_cast<uint64_t>(uuid.data[7]);
|
||||
uint64_t h =
|
||||
static_cast<uint64_t>(uuid.data[8]) << 56 |
|
||||
static_cast<uint64_t>(uuid.data[9]) << 48 |
|
||||
static_cast<uint64_t>(uuid.data[10]) << 40 |
|
||||
static_cast<uint64_t>(uuid.data[11]) << 32 |
|
||||
static_cast<uint64_t>(uuid.data[12]) << 24 |
|
||||
static_cast<uint64_t>(uuid.data[13]) << 16 |
|
||||
static_cast<uint64_t>(uuid.data[14]) << 8 |
|
||||
static_cast<uint64_t>(uuid.data[15]);
|
||||
|
||||
if constexpr (sizeof(result_type) > 4)
|
||||
{
|
||||
return result_type(l ^ h);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t hash64 = l ^ h;
|
||||
return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* STDUUID_H */
|
||||
|
||||
31
test/CMakeLists.txt
Normal file
31
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 /Zc:hiddenFriend)
|
||||
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)
|
||||
@ -8,33 +8,54 @@
|
||||
|
||||
using namespace uuids;
|
||||
|
||||
TEST_CASE("Test default generator", "[gen][rand]")
|
||||
TEST_CASE("Test multiple default generators", "[gen][rand]")
|
||||
{
|
||||
uuid const guid = uuids::uuid_random_generator{}();
|
||||
REQUIRE(!guid.is_nil());
|
||||
REQUIRE(guid.size() == 16);
|
||||
REQUIRE(guid.version() == uuids::uuid_version::random_number_based);
|
||||
REQUIRE(guid.variant() == uuids::uuid_variant::rfc);
|
||||
}
|
||||
uuid id1;
|
||||
uuid id2;
|
||||
|
||||
TEST_CASE("Test random generator (default ctor)", "[gen][rand]")
|
||||
{
|
||||
uuids::uuid_random_generator dgen;
|
||||
auto id1 = dgen();
|
||||
REQUIRE(!id1.is_nil());
|
||||
REQUIRE(id1.size() == 16);
|
||||
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);
|
||||
|
||||
auto id2 = dgen();
|
||||
REQUIRE(!id2.is_nil());
|
||||
REQUIRE(id2.size() == 16);
|
||||
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||
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;
|
||||
@ -46,13 +67,11 @@ TEST_CASE("Test random generator (conversion ctor w/ smart ptr)", "[gen][rand]")
|
||||
uuids::uuid_random_generator dgen(&generator);
|
||||
auto id1 = dgen();
|
||||
REQUIRE(!id1.is_nil());
|
||||
REQUIRE(id1.size() == 16);
|
||||
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.size() == 16);
|
||||
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||
|
||||
@ -70,13 +89,11 @@ TEST_CASE("Test random generator (conversion ctor w/ ptr)", "[gen][rand]")
|
||||
uuids::uuid_random_generator dgen(generator.get());
|
||||
auto id1 = dgen();
|
||||
REQUIRE(!id1.is_nil());
|
||||
REQUIRE(id1.size() == 16);
|
||||
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.size() == 16);
|
||||
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||
|
||||
@ -94,31 +111,11 @@ TEST_CASE("Test random generator (conversion ctor w/ ref)", "[gen][rand]")
|
||||
uuids::uuid_random_generator dgen(generator);
|
||||
auto id1 = dgen();
|
||||
REQUIRE(!id1.is_nil());
|
||||
REQUIRE(id1.size() == 16);
|
||||
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.size() == 16);
|
||||
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 (default ctor) w/ ranlux48_base", "[gen][rand]")
|
||||
{
|
||||
uuids::basic_uuid_random_generator<std::ranlux48_base> dgen;
|
||||
auto id1 = dgen();
|
||||
REQUIRE(!id1.is_nil());
|
||||
REQUIRE(id1.size() == 16);
|
||||
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.size() == 16);
|
||||
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||
|
||||
@ -128,18 +125,19 @@ TEST_CASE("Test basic random generator (default ctor) w/ ranlux48_base", "[gen][
|
||||
TEST_CASE("Test basic random generator (conversion ctor w/ ptr) w/ ranlux48_base", "[gen][rand]")
|
||||
{
|
||||
std::random_device rd;
|
||||
std::ranlux48_base generator(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.size() == 16);
|
||||
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.size() == 16);
|
||||
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||
|
||||
@ -149,18 +147,19 @@ TEST_CASE("Test basic random generator (conversion ctor w/ ptr) w/ ranlux48_base
|
||||
TEST_CASE("Test basic random generator (conversion ctor w/ smart ptr) w/ ranlux48_base", "[gen][rand]")
|
||||
{
|
||||
std::random_device rd;
|
||||
auto generator = std::make_unique<std::ranlux48_base>(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.size() == 16);
|
||||
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.size() == 16);
|
||||
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||
|
||||
@ -170,48 +169,53 @@ TEST_CASE("Test basic random generator (conversion ctor w/ smart ptr) w/ ranlux4
|
||||
TEST_CASE("Test basic random generator (conversion ctor w/ ref) w/ ranlux48_base", "[gen][rand]")
|
||||
{
|
||||
std::random_device rd;
|
||||
std::ranlux48_base generator(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.size() == 16);
|
||||
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.size() == 16);
|
||||
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||
|
||||
REQUIRE(id1 != id2);
|
||||
}
|
||||
|
||||
TEST_CASE("Test name generator", "[gen][name]")
|
||||
TEST_CASE("Test namespaces", "[gen][name]")
|
||||
{
|
||||
uuids::uuid_name_generator dgen(uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43"));
|
||||
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.size() == 16);
|
||||
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.size() == 16);
|
||||
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.size() == 16);
|
||||
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.size() == 16);
|
||||
REQUIRE(id4.version() == uuids::uuid_version::name_based_sha1);
|
||||
REQUIRE(id4.variant() == uuids::uuid_variant::rfc);
|
||||
|
||||
@ -219,3 +223,100 @@ TEST_CASE("Test name generator", "[gen][name]")
|
||||
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);
|
||||
}
|
||||
|
||||
TEST_CASE("Test name generator (std::string_view)", "[gen][name]")
|
||||
{
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
uuids::uuid_name_generator dgen(uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value());
|
||||
auto id1 = dgen("john"sv);
|
||||
REQUIRE(!id1.is_nil());
|
||||
REQUIRE(id1.version() == uuids::uuid_version::name_based_sha1);
|
||||
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||
|
||||
auto id2 = dgen("jane"sv);
|
||||
REQUIRE(!id2.is_nil());
|
||||
REQUIRE(id2.version() == uuids::uuid_version::name_based_sha1);
|
||||
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||
|
||||
auto id3 = dgen("jane"sv);
|
||||
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"sv);
|
||||
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 equality (char const*, std::string, std::string_view)", "[gen][name]")
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
uuids::uuid_name_generator dgen(uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value());
|
||||
auto id1 = dgen("john");
|
||||
auto id2 = dgen("john"s);
|
||||
auto id3 = dgen("john"sv);
|
||||
|
||||
REQUIRE(id1 == id2);
|
||||
REQUIRE(id2 == id3);
|
||||
}
|
||||
|
||||
#ifdef UUID_TIME_GENERATOR
|
||||
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
|
||||
@ -9,85 +9,408 @@
|
||||
|
||||
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());
|
||||
REQUIRE(empty.size() == 16);
|
||||
}
|
||||
|
||||
TEST_CASE("Test from_string(string_view)", "[parse]")
|
||||
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;
|
||||
auto guid = uuids::uuid::from_string(str);
|
||||
REQUIRE(uuids::to_string(guid) == str);
|
||||
REQUIRE(uuids::uuid::is_valid_uuid(str));
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43}"s;
|
||||
auto guid = uuids::uuid::from_string(str);
|
||||
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
REQUIRE(uuids::uuid::is_valid_uuid(str));
|
||||
}
|
||||
|
||||
{
|
||||
auto guid = uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
REQUIRE(uuids::to_wstring(guid) == L"47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
auto str = L"47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||
REQUIRE(uuids::uuid::is_valid_uuid(str));
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "4718382325744bfdb41199ed177d3e43"s;
|
||||
REQUIRE_NOTHROW(uuids::uuid::from_string(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 from_string(wstring_view)", "[parse]")
|
||||
TEST_CASE("Test is_valid_uuid(basic_string_view)", "[parse]")
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
auto str = L"47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||
auto guid = uuids::uuid::from_string(str);
|
||||
REQUIRE(uuids::to_wstring(guid) == str);
|
||||
REQUIRE(uuids::uuid::is_valid_uuid("47183823-2574-4bfd-b411-99ed177d3e43"sv));
|
||||
REQUIRE(uuids::uuid::is_valid_uuid("{47183823-2574-4bfd-b411-99ed177d3e43}"sv));
|
||||
REQUIRE(uuids::uuid::is_valid_uuid(L"47183823-2574-4bfd-b411-99ed177d3e43"sv));
|
||||
REQUIRE(uuids::uuid::is_valid_uuid(L"{47183823-2574-4bfd-b411-99ed177d3e43}"sv));
|
||||
REQUIRE(uuids::uuid::is_valid_uuid("00000000-0000-0000-0000-000000000000"sv));
|
||||
REQUIRE(uuids::uuid::is_valid_uuid("{00000000-0000-0000-0000-000000000000}"sv));
|
||||
REQUIRE(uuids::uuid::is_valid_uuid(L"00000000-0000-0000-0000-000000000000"sv));
|
||||
REQUIRE(uuids::uuid::is_valid_uuid(L"{00000000-0000-0000-0000-000000000000}"sv));
|
||||
}
|
||||
|
||||
TEST_CASE("Test from_string invalid format", "[parse]")
|
||||
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_THROWS_AS(uuids::uuid::from_string(str), uuids::uuid_error);
|
||||
REQUIRE(!uuids::uuid::is_valid_uuid(str));
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "{}"s;
|
||||
REQUIRE_THROWS_AS(uuids::uuid::from_string(str), uuids::uuid_error);
|
||||
REQUIRE(!uuids::uuid::is_valid_uuid(str));
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e4"s;
|
||||
REQUIRE_THROWS_AS(uuids::uuid::from_string(str), uuids::uuid_error);
|
||||
REQUIRE(!uuids::uuid::is_valid_uuid(str));
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e430"s;
|
||||
REQUIRE_THROWS_AS(uuids::uuid::from_string(str), uuids::uuid_error);
|
||||
REQUIRE(!uuids::uuid::is_valid_uuid(str));
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||
REQUIRE_THROWS_AS(uuids::uuid::from_string(str), uuids::uuid_error);
|
||||
REQUIRE(!uuids::uuid::is_valid_uuid(str));
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e43}"s;
|
||||
REQUIRE_THROWS_AS(uuids::uuid::from_string(str), uuids::uuid_error);
|
||||
REQUIRE(!uuids::uuid::is_valid_uuid(str));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Test is_valid_uuid(basic_string_view) invalid format", "[parse]")
|
||||
{
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
REQUIRE(!uuids::uuid::is_valid_uuid(""sv));
|
||||
REQUIRE(!uuids::uuid::is_valid_uuid("{}"sv));
|
||||
REQUIRE(!uuids::uuid::is_valid_uuid("47183823-2574-4bfd-b411-99ed177d3e4"sv));
|
||||
REQUIRE(!uuids::uuid::is_valid_uuid("47183823-2574-4bfd-b411-99ed177d3e430"sv));
|
||||
REQUIRE(!uuids::uuid::is_valid_uuid("{47183823-2574-4bfd-b411-99ed177d3e43"sv));
|
||||
REQUIRE(!uuids::uuid::is_valid_uuid("47183823-2574-4bfd-b411-99ed177d3e43}"sv));
|
||||
}
|
||||
|
||||
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"s).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(basic_string_view)", "[parse]")
|
||||
{
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
{
|
||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"sv;
|
||||
auto guid = uuids::uuid::from_string(str).value();
|
||||
REQUIRE(uuids::to_string(guid) == str);
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43}"sv;
|
||||
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"sv).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"sv;
|
||||
auto guid = uuids::uuid::from_string(str).value();
|
||||
REQUIRE(uuids::to_string<wchar_t>(guid) == str);
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "4718382325744bfdb41199ed177d3e43"sv;
|
||||
REQUIRE_NOTHROW(uuids::uuid::from_string(str));
|
||||
REQUIRE(uuids::uuid::from_string(str).has_value());
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "00000000-0000-0000-0000-000000000000"sv;
|
||||
auto guid = uuids::uuid::from_string(str).value();
|
||||
REQUIRE(guid.is_nil());
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "{00000000-0000-0000-0000-000000000000}"sv;
|
||||
auto guid = uuids::uuid::from_string(str).value();
|
||||
REQUIRE(guid.is_nil());
|
||||
}
|
||||
|
||||
{
|
||||
auto str = L"00000000-0000-0000-0000-000000000000"sv;
|
||||
auto guid = uuids::uuid::from_string(str).value();
|
||||
REQUIRE(guid.is_nil());
|
||||
}
|
||||
|
||||
{
|
||||
auto str = L"{00000000-0000-0000-0000-000000000000}"sv;
|
||||
auto guid = uuids::uuid::from_string(str).value();
|
||||
REQUIRE(guid.is_nil());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Test constexpr from_string", "[const]")
|
||||
{
|
||||
constexpr uuid value = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value();
|
||||
static_assert(!value.is_nil());
|
||||
static_assert(value.variant() == uuid_variant::rfc);
|
||||
static_assert(value.version() != uuid_version::none);
|
||||
}
|
||||
|
||||
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 from_string(basic_string_view) invalid format", "[parse]")
|
||||
{
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
REQUIRE(!uuids::uuid::from_string(""sv).has_value());
|
||||
REQUIRE(!uuids::uuid::from_string("{}"sv).has_value());
|
||||
REQUIRE(!uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e4"sv).has_value());
|
||||
REQUIRE(!uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e430"sv).has_value());
|
||||
REQUIRE(!uuids::uuid::from_string("{47183823-2574-4bfd-b411-99ed177d3e43"sv).has_value());
|
||||
REQUIRE(!uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43}"sv).has_value());
|
||||
}
|
||||
|
||||
TEST_CASE("Test iterators constructor", "[ctors]")
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
@ -117,10 +440,53 @@ TEST_CASE("Test iterators constructor", "[ctors]")
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
uuid guid = uuids::uuid_random_generator{}();
|
||||
|
||||
auto engine = uuids::uuid_random_generator::engine_type{};
|
||||
seed_rng(engine);
|
||||
uuid guid = uuids::uuid_random_generator{engine}();
|
||||
|
||||
REQUIRE(empty == empty);
|
||||
REQUIRE(guid == guid);
|
||||
@ -130,7 +496,11 @@ TEST_CASE("Test equality", "[operators]")
|
||||
TEST_CASE("Test comparison", "[operators]")
|
||||
{
|
||||
auto empty = uuid{};
|
||||
uuids::uuid_random_generator gen;
|
||||
|
||||
auto engine = uuids::uuid_random_generator::engine_type{};
|
||||
seed_rng(engine);
|
||||
|
||||
uuids::uuid_random_generator gen{ engine };
|
||||
auto id = gen();
|
||||
|
||||
REQUIRE(empty < id);
|
||||
@ -151,13 +521,19 @@ 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);
|
||||
auto guid = uuids::uuid::from_string(str).value();
|
||||
|
||||
auto h1 = std::hash<std::string>{};
|
||||
auto h2 = std::hash<uuid>{};
|
||||
#ifdef UUID_HASH_STRING_BASED
|
||||
REQUIRE(h1(str) == h2(guid));
|
||||
#else
|
||||
REQUIRE(h1(str) != h2(guid));
|
||||
#endif
|
||||
|
||||
uuids::uuid_random_generator gen;
|
||||
auto engine = uuids::uuid_random_generator::engine_type{};
|
||||
seed_rng(engine);
|
||||
uuids::uuid_random_generator gen{ engine };
|
||||
|
||||
std::unordered_set<uuids::uuid> ids{
|
||||
uuid{},
|
||||
@ -174,7 +550,10 @@ TEST_CASE("Test hashing", "[ops]")
|
||||
TEST_CASE("Test swap", "[ops]")
|
||||
{
|
||||
uuid empty;
|
||||
uuid guid = uuids::uuid_random_generator{}();
|
||||
|
||||
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());
|
||||
@ -190,54 +569,12 @@ TEST_CASE("Test swap", "[ops]")
|
||||
REQUIRE(!guid.is_nil());
|
||||
}
|
||||
|
||||
TEST_CASE("Test string conversion", "[ops]")
|
||||
{
|
||||
uuid empty;
|
||||
REQUIRE(uuids::to_string(empty) == "00000000-0000-0000-0000-000000000000");
|
||||
REQUIRE(uuids::to_wstring(empty) == L"00000000-0000-0000-0000-000000000000");
|
||||
}
|
||||
|
||||
TEST_CASE("Test iterators", "[iter]")
|
||||
{
|
||||
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");
|
||||
|
||||
size_t i = 0;
|
||||
for (auto const & b : guid)
|
||||
{
|
||||
REQUIRE(arr[i++] == b);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const uuid guid = uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
REQUIRE(!guid.is_nil());
|
||||
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
|
||||
size_t i = 0;
|
||||
for (auto const & b : guid)
|
||||
{
|
||||
REQUIRE(arr[i++] == b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Test constexpr", "[const]")
|
||||
{
|
||||
constexpr uuid empty;
|
||||
[[maybe_unused]] constexpr bool isnil = empty.is_nil();
|
||||
[[maybe_unused]] constexpr size_t size = empty.size();
|
||||
[[maybe_unused]] constexpr uuids::uuid_variant variant = empty.variant();
|
||||
[[maybe_unused]] constexpr uuid_version version = empty.version();
|
||||
static_assert(empty.is_nil());
|
||||
static_assert(empty.variant() == uuid_variant::ncs);
|
||||
static_assert(empty.version() == uuid_version::none);
|
||||
}
|
||||
|
||||
TEST_CASE("Test size", "[operators]")
|
||||
@ -247,11 +584,11 @@ TEST_CASE("Test size", "[operators]")
|
||||
|
||||
TEST_CASE("Test assignment", "[ops]")
|
||||
{
|
||||
auto id1 = uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
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}");
|
||||
id1 = uuids::uuid::from_string("{fea43102-064f-4444-adc2-02cec42623f8}").value();
|
||||
REQUIRE(id1 != id2);
|
||||
|
||||
auto id3 = std::move(id2);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user