revision based on LEWGI feedback from San Diego
This commit is contained in:
parent
0ebaceee2f
commit
bc37fa250b
268
P0959.md
268
P0959.md
@ -1,8 +1,8 @@
|
|||||||
| ___ | ___ |
|
| ___ | ___ |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Doc. No.: | P0959R1 |
|
| Doc. No.: | P0959R1 |
|
||||||
| Date: | 2018-09-05 |
|
| Date: | 2019-01-08 |
|
||||||
| Reply to: | Marius Bancila |
|
| Reply to: | Marius Bancila, Tony van Eerd |
|
||||||
| Audience: | Library WG |
|
| Audience: | Library WG |
|
||||||
| Title: | A Proposal for a Universally Unique Identifier Library |
|
| 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 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.
|
* 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.
|
* 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 mutable iterators (but preserved the constant iterators).
|
||||||
* Removed typedefs and others container-like parts.
|
* Removed typedefs and others container-like parts.
|
||||||
* Defined the correlation between the internal UUID bytes and the string representation.
|
* Defined the correlation between the internal UUID bytes and the string representation.
|
||||||
@ -33,6 +33,62 @@ Revised with feedback from the LWG and the community.
|
|||||||
* Most functions are constexpr.
|
* Most functions are constexpr.
|
||||||
* Replaced typedefs with using statements.
|
* 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 (TODO: formal specification)
|
||||||
|
* 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
|
||||||
|
* added `is_valid_uuid()` a non-throwing function template that checks if a string contains is a valid uuid
|
||||||
|
* `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
|
||||||
|
|
||||||
## II. Motivation
|
## II. Motivation
|
||||||
|
|
||||||
@ -51,9 +107,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:
|
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
|
* 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
|
* 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`, `uuid_time_generator`
|
||||||
* 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()`, as well as an overloaded `operator<<` for `std::basic_ostream`
|
||||||
* 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`
|
|
||||||
* `std::swap()` overload for `uuid`
|
* `std::swap()` overload for `uuid`
|
||||||
* `std::hash<>` specialization for `uuid`
|
* `std::hash<>` specialization for `uuid`
|
||||||
|
|
||||||
@ -111,14 +166,6 @@ uuid id{ data };
|
|||||||
assert(to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
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
|
### 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}`.
|
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,33 +174,10 @@ A nil UUID is a special UUID that has all the bits set to 0. Its canonical textu
|
|||||||
uuid id;
|
uuid id;
|
||||||
assert(id.is_nil());
|
assert(id.is_nil());
|
||||||
|
|
||||||
uuid id = uuid::from_string("00000000-0000-0000-0000-000000000000");
|
std::optional<uuid> id = uuid::from_string("00000000-0000-0000-0000-000000000000");
|
||||||
assert(id.is_nil());
|
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`
|
### `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`.
|
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`.
|
||||||
@ -178,12 +202,12 @@ std::array<uuid::value_type, 16> arr{ {
|
|||||||
} };
|
} };
|
||||||
|
|
||||||
uuid id1{ std::span<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);
|
assert(id1 == id2);
|
||||||
|
|
||||||
std::set<std::uuid> ids{
|
std::set<std::uuid> ids{
|
||||||
uuid{},
|
uuid{},
|
||||||
uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43")
|
uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value()
|
||||||
};
|
};
|
||||||
|
|
||||||
assert(ids.size() == 2);
|
assert(ids.size() == 2);
|
||||||
@ -201,7 +225,7 @@ std::array<uuids::uuid::value_type, 16> arr{ {
|
|||||||
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43
|
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43
|
||||||
} };
|
} };
|
||||||
|
|
||||||
const uuid id{ arr };
|
uuid const id{ arr };
|
||||||
assert(!id.is_nil());
|
assert(!id.is_nil());
|
||||||
|
|
||||||
auto view = id.as_bytes();
|
auto view = id.as_bytes();
|
||||||
@ -214,7 +238,7 @@ Both member and non-member `swap()` functions are available to perform the swapp
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
uuid empty;
|
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(empty.is_nil());
|
||||||
assert(!id.is_nil());
|
assert(!id.is_nil());
|
||||||
@ -232,25 +256,29 @@ assert(!id.is_nil());
|
|||||||
|
|
||||||
### String parsing
|
### 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
|
```cpp
|
||||||
auto id1 = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
|
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}");
|
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`.
|
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
|
### 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
|
```cpp
|
||||||
uuid id = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
|
auto id = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
|
||||||
assert(to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
assert(id.has_value());
|
||||||
assert(to_wstring(id) == L"47183823-2574-4bfd-b411-99ed177d3e43");
|
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"`.
|
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 +290,7 @@ A `std::hash<>` specialization for `uuid` is provided in order to enable the use
|
|||||||
```cpp
|
```cpp
|
||||||
std::unordered_set<uuid> ids{
|
std::unordered_set<uuid> ids{
|
||||||
uuid{},
|
uuid{},
|
||||||
uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43"),
|
uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value(),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert(ids.size() == 2);
|
assert(ids.size() == 2);
|
||||||
@ -275,37 +303,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:
|
Examples for generating new UUIDs with the `basic_uuid_random_generator` class:
|
||||||
```cpp
|
```cpp
|
||||||
{
|
{
|
||||||
basic_uuid_random_generator<std::mt19937> dgen;
|
std::random_device rd;
|
||||||
auto id1 = dgen();
|
auto seed_data = std::array<int, std::mt19937::state_size> {};
|
||||||
assert(!id1.is_nil());
|
std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd));
|
||||||
assert(id1.size() == 16);
|
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
|
||||||
assert(id1.version() == uuid_version::random_number_based);
|
std::mt19937 engine(seq);
|
||||||
assert(id1.variant() == uuid_variant::rfc);
|
|
||||||
}
|
basic_uuid_random_generator<std::mt19937> dgen{engine};
|
||||||
{
|
|
||||||
basic_uuid_random_generator<std::ranlux48_base> dgen;
|
|
||||||
auto id1 = dgen();
|
auto id1 = dgen();
|
||||||
assert(!id1.is_nil());
|
assert(!id1.is_nil());
|
||||||
assert(id1.size() == 16);
|
assert(id1.size() == 16);
|
||||||
assert(id1.version() == uuid_version::random_number_based);
|
assert(id1.version() == uuid_version::random_number_based);
|
||||||
assert(id1.variant() == uuid_variant::rfc);
|
assert(id1.variant() == uuid_variant::rfc);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::random_device rd;
|
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));
|
||||||
basic_uuid_random_generator<std::ranlux48_base> dgen(&generator);
|
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();
|
auto id1 = dgen();
|
||||||
assert(!id1.is_nil());
|
assert(!id1.is_nil());
|
||||||
assert(id1.size() == 16);
|
assert(id1.size() == 16);
|
||||||
assert(id1.version() == uuid_version::random_number_based);
|
assert(id1.version() == uuid_version::random_number_based);
|
||||||
assert(id1.variant() == uuid_variant::rfc);
|
assert(id1.variant() == uuid_variant::rfc);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::random_device rd;
|
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();
|
auto id1 = dgen();
|
||||||
assert(!id1.is_nil());
|
assert(!id1.is_nil());
|
||||||
assert(id1.size() == 16);
|
assert(id1.size() == 16);
|
||||||
@ -313,18 +347,26 @@ Examples for generating new UUIDs with the `basic_uuid_random_generator` class:
|
|||||||
assert(id1.variant() == uuid_variant::rfc);
|
assert(id1.variant() == uuid_variant::rfc);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Examples for generating new UUIDs with the `uuid_random_generator` type alias:
|
Examples for generating new UUIDs with the `uuid_random_generator` type alias:
|
||||||
```cpp
|
```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();
|
auto id1 = dgen();
|
||||||
assert(!id1.is_nil());
|
assert(!id1.is_nil());
|
||||||
assert(id1.size() == 16);
|
assert(id1.size() == 16);
|
||||||
assert(id1.version() == uuid_version::random_number_based);
|
assert(id1.version() == uuid_version::random_number_based);
|
||||||
assert(id1.variant() == uuid_variant::rfc);
|
assert(id1.variant() == uuid_variant::rfc);
|
||||||
```
|
```
|
||||||
|
|
||||||
Examples for genearting new UUIDs with the `uuid_name_generator` class:
|
Examples for genearting new UUIDs with the `uuid_name_generator` class:
|
||||||
```cpp
|
```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");
|
auto id1 = dgen("john");
|
||||||
assert(!id1.is_nil());
|
assert(!id1.is_nil());
|
||||||
assert(id1.size() == 16);
|
assert(id1.size() == 16);
|
||||||
@ -373,6 +415,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
|
### `uuid_version` enum
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
@ -389,17 +433,6 @@ 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
|
### `uuid` class
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
@ -407,7 +440,6 @@ namespace std {
|
|||||||
struct uuid
|
struct uuid
|
||||||
{
|
{
|
||||||
using value_type = uint8_t;
|
using value_type = uint8_t;
|
||||||
using const_iterator = /*implementation-defined*/;
|
|
||||||
|
|
||||||
constexpr uuid() noexcept = default;
|
constexpr uuid() noexcept = default;
|
||||||
|
|
||||||
@ -418,23 +450,29 @@ namespace std {
|
|||||||
|
|
||||||
constexpr uuid_variant variant() const noexcept;
|
constexpr uuid_variant variant() const noexcept;
|
||||||
constexpr uuid_version version() const noexcept;
|
constexpr uuid_version version() const noexcept;
|
||||||
constexpr std::size_t size() const noexcept;
|
|
||||||
constexpr bool is_nil() const noexcept;
|
constexpr bool is_nil() const noexcept;
|
||||||
|
|
||||||
constexpr void swap(uuid & other) 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::span<std::byte const, 16> as_bytes() const;
|
||||||
|
|
||||||
constexpr std::strong_ordering operator<=>(uuid const&) const noexcept = default;
|
constexpr std::strong_ordering operator<=>(uuid const&) const noexcept = default;
|
||||||
|
|
||||||
template <typename TChar>
|
template<class CharT = char>
|
||||||
static uuid from_string(TChar const * const str, size_t const size);
|
static bool is_valid_uuid(CharT const * str) noexcept;
|
||||||
static uuid from_string(std::string_view str);
|
|
||||||
static uuid from_string(std::wstring_view str);
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
static bool is_valid_uuid(std::basic_string<CharT, Traits, Allocator>& str) noexcept;
|
||||||
|
|
||||||
|
template<class CharT = char>
|
||||||
|
static uuid from_string(CharT const * str);
|
||||||
|
|
||||||
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
static uuid from_string(std::basic_string<CharT, Traits, Allocator>& str);
|
||||||
private:
|
private:
|
||||||
template <class Elem, class Traits>
|
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);
|
||||||
@ -451,8 +489,10 @@ namespace std {
|
|||||||
template <class Elem, class Traits>
|
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);
|
||||||
|
|
||||||
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
inline std::string to_string(uuid const & id);
|
inline std::string to_string(uuid const & id);
|
||||||
inline std::wstring to_wstring(uuid const & id);
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -464,11 +504,10 @@ namespace std {
|
|||||||
class basic_uuid_random_generator
|
class basic_uuid_random_generator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using result_type = uuid;
|
using engine_type = UniformRandomNumberGenerator;
|
||||||
|
|
||||||
basic_uuid_random_generator();
|
explicit basic_uuid_random_generator(engine_type& gen);
|
||||||
explicit basic_uuid_random_generator(UniformRandomNumberGenerator& gen);
|
explicit basic_uuid_random_generator(engine_type* gen);
|
||||||
explicit basic_uuid_random_generator(UniformRandomNumberGenerator* gen);
|
|
||||||
|
|
||||||
uuid operator()();
|
uuid operator()();
|
||||||
};
|
};
|
||||||
@ -480,14 +519,14 @@ namespace std {
|
|||||||
using uuid_random_generator = basic_uuid_random_generator<std::mt19937>;
|
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`.
|
`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`.
|
||||||
|
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.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
namespace std {
|
namespace std {
|
||||||
class uuid_name_generator
|
class uuid_name_generator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using result_type = uuid;
|
|
||||||
|
|
||||||
explicit uuid_name_generator(uuid const& namespace_uuid) noexcept;
|
explicit uuid_name_generator(uuid const& namespace_uuid) noexcept;
|
||||||
|
|
||||||
uuid operator()(std::string_view name);
|
uuid operator()(std::string_view name);
|
||||||
@ -496,6 +535,22 @@ namespace std {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`uuid_time_generator` is a function object that generates a time-based UUID as described in the RFC4122 document. 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 a 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.
|
||||||
|
```cpp
|
||||||
|
namespace std {
|
||||||
|
class uuid_time_generator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uuid_time_generator() noexcept;
|
||||||
|
|
||||||
|
uuid operator()();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Specialization
|
### Specialization
|
||||||
The template specializations of `std::hash` for the `uuid` class allow users to obtain hashes of UUIDs.
|
The template specializations of `std::hash` for the `uuid` class allow users to obtain hashes of UUIDs.
|
||||||
```cpp
|
```cpp
|
||||||
@ -534,7 +589,6 @@ namespace std {
|
|||||||
struct uuid
|
struct uuid
|
||||||
{
|
{
|
||||||
using value_type = uint8_t;
|
using value_type = uint8_t;
|
||||||
using const_iterator = /*implementation-defined*/;
|
|
||||||
|
|
||||||
constexpr uuid() noexcept = default;
|
constexpr uuid() noexcept = default;
|
||||||
|
|
||||||
@ -545,21 +599,27 @@ namespace std {
|
|||||||
|
|
||||||
constexpr uuid_variant variant() const noexcept;
|
constexpr uuid_variant variant() const noexcept;
|
||||||
constexpr uuid_version version() const noexcept;
|
constexpr uuid_version version() const noexcept;
|
||||||
constexpr std::size_t size() const noexcept;
|
|
||||||
constexpr bool is_nil() const noexcept;
|
constexpr bool is_nil() const noexcept;
|
||||||
|
|
||||||
constexpr void swap(uuid & other) 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::span<std::byte const, 16> as_bytes() const;
|
||||||
|
|
||||||
template <typename TChar>
|
template<class CharT = char>
|
||||||
static uuid from_string(TChar const * const str, size_t const size);
|
static bool is_valid_uuid(CharT const * str) noexcept;
|
||||||
static uuid from_string(std::string_view str);
|
|
||||||
static uuid from_string(std::wstring_view str);
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
static bool is_valid_uuid(std::basic_string<CharT, Traits, Allocator>& str) noexcept;
|
||||||
|
|
||||||
|
template<class CharT = char>
|
||||||
|
static uuid from_string(CharT const * str);
|
||||||
|
|
||||||
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
static uuid from_string(std::basic_string<CharT, Traits, Allocator>& str);
|
||||||
private:
|
private:
|
||||||
template <class Elem, class Traits>
|
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);
|
||||||
|
277
README.md
277
README.md
@ -18,16 +18,15 @@ 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` | 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_variant` | a strongly type enum representing the type of a UUID |
|
||||||
| `uuid_version` | a strongly type enum representing the version 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:
|
Generators:
|
||||||
|
|
||||||
| Name | Description |
|
| 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. |
|
| `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 Marsenne Twister engine (`basic_uuid_random_generator<std::mt19937>`) |
|
||||||
| `uuid_name_generator` | a function object that generates version 5, name-based UUIDs using SHA1 hashing. |
|
| `uuid_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. |
|
||||||
|
|
||||||
Utilities:
|
Utilities:
|
||||||
|
|
||||||
@ -43,194 +42,200 @@ Other:
|
|||||||
| `operator==` and `operator!=` | for UUIDs comparison for equality/inequality |
|
| `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<` | 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. |
|
| `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_string()` | creates a 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.
|
|
||||||
|
|
||||||
## Library history
|
## 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 commity 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
|
## Using the library
|
||||||
The following is a list of examples for using the library:
|
The following is a list of examples for using the library:
|
||||||
* Creating a nil UUID
|
* Creating a nil UUID
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
uuid empty;
|
uuid empty;
|
||||||
assert(empty.is_nil());
|
assert(empty.is_nil());
|
||||||
assert(empty.size() == 16);
|
```
|
||||||
```
|
|
||||||
|
|
||||||
* Creating a new UUID
|
* Creating a new UUID
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
uuid const id = uuids::uuid_system_generator{}();
|
uuid const id = uuids::uuid_system_generator{}();
|
||||||
assert(!id.is_nil());
|
assert(!id.is_nil());
|
||||||
assert(id.size() == 16);
|
assert(id.version() == uuids::uuid_version::random_number_based);
|
||||||
assert(id.version() == uuids::uuid_version::random_number_based);
|
assert(id.variant() == uuids::uuid_variant::rfc);
|
||||||
assert(id.variant() == uuids::uuid_variant::rfc);
|
```
|
||||||
```
|
|
||||||
|
|
||||||
* Creating a new UUID with a default random generator
|
* Creating a new UUID with a default random generator
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
uuids::uuid_random_generator gen;
|
std::random_device rd;
|
||||||
uuid const id = gen();
|
auto seed_data = std::array<int, std::mt19937::state_size> {};
|
||||||
assert(!id.is_nil());
|
std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd));
|
||||||
assert(id.size() == 16);
|
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
|
||||||
assert(id.version() == uuids::uuid_version::random_number_based);
|
std::mt19937 generator(seq);
|
||||||
assert(id.variant() == uuids::uuid_variant::rfc);
|
uuid const guid = uuids::uuid_random_generator{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);
|
||||||
|
```
|
||||||
|
|
||||||
* Creating a new UUID with a particular random generator
|
* Creating a new UUID with a particular random generator
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
std::random_device rd;
|
std::random_device rd;
|
||||||
std::ranlux48_base generator(rd());
|
auto seed_data = std::array<int, 6> {};
|
||||||
uuids::basic_uuid_random_generator<std::ranlux48_base> gen(&generator);
|
std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd));
|
||||||
uuid const id = gen();
|
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
|
||||||
assert(!id.is_nil());
|
std::ranlux48_base generator(seq);
|
||||||
assert(id.size() == 16);
|
|
||||||
assert(id.version() == uuids::uuid_version::random_number_based);
|
uuids::basic_uuid_random_generator<std::ranlux48_base> gen(&generator);
|
||||||
assert(id.variant() == uuids::uuid_variant::rfc);
|
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);
|
||||||
|
```
|
||||||
|
|
||||||
* Creating a new UUID with the name generator
|
* Creating a new UUID with the name generator
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
uuids::uuid_name_generator gen;
|
uuids::uuid_name_generator gen(uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value());
|
||||||
uuid const id = gen();
|
uuid const id = gen();
|
||||||
|
|
||||||
assert(!id.is_nil());
|
assert(!id.is_nil());
|
||||||
assert(id.size() == 16);
|
assert(id.version() == uuids::uuid_version::name_based_sha1);
|
||||||
assert(id.version() == uuids::uuid_version::name_based_sha1);
|
assert(id.variant() == uuids::uuid_variant::rfc);
|
||||||
assert(id.variant() == uuids::uuid_variant::rfc);
|
```
|
||||||
```
|
|
||||||
|
|
||||||
* Create a UUID from a string
|
* Create a UUID from a string
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
|
|
||||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||||
uuid id(uuids::uuid::from_string(str));
|
auto id = uuids::uuid::from_string(str);
|
||||||
assert(uuids::to_string(id) == str);
|
assert(id.has_value());
|
||||||
|
assert(uuids::to_string(id.value()) == str);
|
||||||
|
|
||||||
// or
|
// or
|
||||||
|
|
||||||
uuid id(uuids::uuid::from_string(L"{47183823-2574-4bfd-b411-99ed177d3e43}"s));
|
uuid id = uuids::uuid::from_string(L"{47183823-2574-4bfd-b411-99ed177d3e43}"s).value();
|
||||||
assert(id.wstring() == str);
|
assert(uuids::to_string<wchar_t>(id.value()) == str);
|
||||||
```
|
```
|
||||||
|
|
||||||
* Creating a UUID from sequence of 16 bytes
|
* Creating a UUID from a sequence of 16 bytes
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
std::array<uuids::uuid::value_type, 16> arr{{
|
std::array<uuids::uuid::value_type, 16> arr{{
|
||||||
0x47, 0x18, 0x38, 0x23,
|
0x47, 0x18, 0x38, 0x23,
|
||||||
0x25, 0x74,
|
0x25, 0x74,
|
||||||
0x4b, 0xfd,
|
0x4b, 0xfd,
|
||||||
0xb4, 0x11,
|
0xb4, 0x11,
|
||||||
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43}};
|
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43}};
|
||||||
uuid id(arr);
|
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] = {
|
uuids::uuid::value_type arr[16] = {
|
||||||
0x47, 0x18, 0x38, 0x23,
|
0x47, 0x18, 0x38, 0x23,
|
||||||
0x25, 0x74,
|
0x25, 0x74,
|
||||||
0x4b, 0xfd,
|
0x4b, 0xfd,
|
||||||
0xb4, 0x11,
|
0xb4, 0x11,
|
||||||
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 };
|
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 };
|
||||||
uuid id(std::begin(arr), std::end(arr));
|
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
|
* Comparing UUIDs
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
uuid empty;
|
uuid empty;
|
||||||
uuid id = uuids::uuid_system_generator{}();
|
uuid id = uuids::uuid_system_generator{}();
|
||||||
assert(empty == empty);
|
assert(empty == empty);
|
||||||
assert(id == id);
|
assert(id == id);
|
||||||
assert(empty != id);
|
assert(empty != id);
|
||||||
```
|
```
|
||||||
|
|
||||||
* Swapping UUIDs
|
* Swapping UUIDs
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
uuid empty;
|
uuid empty;
|
||||||
uuid id = uuids::uuid_system_generator{}();
|
uuid id = uuids::uuid_system_generator{}();
|
||||||
|
|
||||||
assert(empty.is_nil());
|
assert(empty.is_nil());
|
||||||
assert(!id.is_nil());
|
assert(!id.is_nil());
|
||||||
|
|
||||||
std::swap(empty, id);
|
std::swap(empty, id);
|
||||||
|
|
||||||
assert(!empty.is_nil());
|
assert(!empty.is_nil());
|
||||||
assert(id.is_nil());
|
assert(id.is_nil());
|
||||||
|
|
||||||
empty.swap(id);
|
empty.swap(id);
|
||||||
|
|
||||||
assert(empty.is_nil());
|
assert(empty.is_nil());
|
||||||
assert(!id.is_nil());
|
assert(!id.is_nil());
|
||||||
```
|
```
|
||||||
|
|
||||||
* Converting to string
|
* Converting to string
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
uuid empty;
|
uuid empty;
|
||||||
assert(uuids::to_string(empty) == "00000000-0000-0000-0000-000000000000");
|
assert(uuids::to_string(empty) == "00000000-0000-0000-0000-000000000000");
|
||||||
assert(uuids::to_wstring(empty) == L"00000000-0000-0000-0000-000000000000");
|
assert(uuids::to_string<wchar_t>(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);
|
|
||||||
```
|
|
||||||
|
|
||||||
* Using with an orderered associative container
|
* Using with an orderered associative container
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
uuids::uuid_random_generator gen;
|
std::random_device rd;
|
||||||
std::set<uuids::uuid> ids{uuid{}, gen(), gen(), gen(), gen()};
|
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.size() == 5);
|
||||||
assert(ids.find(uuid{}) != ids.end());
|
assert(ids.find(uuid{}) != ids.end());
|
||||||
```
|
```
|
||||||
|
|
||||||
* Using in an unordered associative container
|
* Using in an unordered associative container
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
uuids::uuid_random_generator gen;
|
std::random_device rd;
|
||||||
std::unordered_set<uuids::uuid> ids{uuid{}, gen(), gen(), gen(), gen()};
|
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);
|
std::unordered_set<uuids::uuid> ids{uuid{}, gen(), gen(), gen(), gen()};
|
||||||
assert(ids.find(uuid{}) != ids.end());
|
|
||||||
```
|
assert(ids.size() == 5);
|
||||||
|
assert(ids.find(uuid{}) != ids.end());
|
||||||
|
```
|
||||||
|
|
||||||
* Hashing UUIDs
|
* Hashing UUIDs
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||||
uuid id(uuids::uuid::from_string(str));
|
uuid id = uuids::uuid::from_string(str).value();
|
||||||
|
|
||||||
auto h1 = std::hash<std::string>{};
|
auto h1 = std::hash<std::string>{};
|
||||||
auto h2 = std::hash<uuid>{};
|
auto h2 = std::hash<uuid>{};
|
||||||
assert(h1(str) == h2(id));
|
assert(h1(str) == h2(id));
|
||||||
```
|
```
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
The library is supported on all major operating systems: Windows, Linux and Mac OS.
|
The library is supported on all major operating systems: Windows, Linux and Mac OS.
|
||||||
|
296
include/uuid.h
296
include/uuid.h
@ -11,6 +11,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <optional>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <gsl/span>
|
#include <gsl/span>
|
||||||
|
|
||||||
@ -283,19 +284,6 @@ namespace uuids
|
|||||||
reserved
|
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
|
enum class uuid_version
|
||||||
{
|
{
|
||||||
@ -309,151 +297,6 @@ namespace uuids
|
|||||||
|
|
||||||
struct uuid
|
struct 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));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using value_type = uint8_t;
|
using value_type = uint8_t;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -499,8 +342,6 @@ namespace uuids
|
|||||||
return uuid_version::none;
|
return uuid_version::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr std::size_t size() const noexcept { return 16; }
|
|
||||||
|
|
||||||
constexpr bool is_nil() const noexcept
|
constexpr bool is_nil() const noexcept
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < data.size(); ++i) if (data[i] != 0) return false;
|
for (size_t i = 0; i < data.size(); ++i) if (data[i] != 0) return false;
|
||||||
@ -512,38 +353,97 @@ namespace uuids
|
|||||||
data.swap(other.data);
|
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
|
inline gsl::span<std::byte const, 16> as_bytes() const
|
||||||
{
|
{
|
||||||
return gsl::span<std::byte const, 16>(reinterpret_cast<std::byte const*>(data.data()), 16);
|
return gsl::span<std::byte const, 16>(reinterpret_cast<std::byte const*>(data.data()), 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TChar>
|
template<class CharT = char>
|
||||||
static uuid from_string(TChar const * const str, size_t const size)
|
static bool is_valid_uuid(CharT const * str) noexcept
|
||||||
{
|
{
|
||||||
TChar digit = 0;
|
CharT digit = 0;
|
||||||
bool firstDigit = true;
|
bool firstDigit = true;
|
||||||
int hasBraces = 0;
|
int hasBraces = 0;
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
std::array<uint8_t, 16> data{ { 0 } };
|
size_t size = 0;
|
||||||
|
if constexpr(std::is_same_v<CharT, char>)
|
||||||
|
size = strlen(str);
|
||||||
|
else
|
||||||
|
size = wcslen(str);
|
||||||
|
|
||||||
if (str == nullptr || size == 0)
|
if (str == nullptr || size == 0)
|
||||||
throw uuid_error{ "Wrong uuid format" };
|
return false;
|
||||||
|
|
||||||
if (str[0] == static_cast<TChar>('{'))
|
if (str[0] == static_cast<CharT>('{'))
|
||||||
hasBraces = 1;
|
hasBraces = 1;
|
||||||
if (hasBraces && str[size - 1] != static_cast<TChar>('}'))
|
if (hasBraces && str[size - 1] != static_cast<CharT>('}'))
|
||||||
throw uuid_error{ "Wrong uuid format" };
|
return false;
|
||||||
|
|
||||||
for (size_t i = hasBraces; i < size - hasBraces; ++i)
|
for (size_t i = hasBraces; i < size - hasBraces; ++i)
|
||||||
{
|
{
|
||||||
if (str[i] == static_cast<TChar>('-')) continue;
|
if (str[i] == static_cast<CharT>('-')) continue;
|
||||||
|
|
||||||
if (index >= 16 || !detail::is_hex(str[i]))
|
if (index >= 16 || !detail::is_hex(str[i]))
|
||||||
{
|
{
|
||||||
throw uuid_error{ "Wrong uuid format" };
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstDigit)
|
||||||
|
{
|
||||||
|
firstDigit = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
firstDigit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < 16)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
static bool is_valid_uuid(std::basic_string<CharT, Traits, Allocator>& str) noexcept
|
||||||
|
{
|
||||||
|
return is_valid_uuid(str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class CharT = char>
|
||||||
|
static std::optional<uuid> from_string(CharT const * str) noexcept
|
||||||
|
{
|
||||||
|
CharT digit = 0;
|
||||||
|
bool firstDigit = true;
|
||||||
|
int hasBraces = 0;
|
||||||
|
size_t index = 0;
|
||||||
|
size_t size = 0;
|
||||||
|
if constexpr(std::is_same_v<CharT, char>)
|
||||||
|
size = strlen(str);
|
||||||
|
else
|
||||||
|
size = wcslen(str);
|
||||||
|
|
||||||
|
std::array<uint8_t, 16> data{ { 0 } };
|
||||||
|
|
||||||
|
if (str == nullptr || size == 0) return {};
|
||||||
|
|
||||||
|
if (str[0] == static_cast<CharT>('{'))
|
||||||
|
hasBraces = 1;
|
||||||
|
if (hasBraces && str[size - 1] != static_cast<CharT>('}'))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
for (size_t i = hasBraces; i < size - hasBraces; ++i)
|
||||||
|
{
|
||||||
|
if (str[i] == static_cast<CharT>('-')) continue;
|
||||||
|
|
||||||
|
if (index >= 16 || !detail::is_hex(str[i]))
|
||||||
|
{
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstDigit)
|
if (firstDigit)
|
||||||
@ -560,20 +460,18 @@ namespace uuids
|
|||||||
|
|
||||||
if (index < 16)
|
if (index < 16)
|
||||||
{
|
{
|
||||||
throw uuid_error{ "Wrong uuid format" };
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return uuid{ std::cbegin(data), std::cend(data) };
|
return uuid{ std::cbegin(data), std::cend(data) };
|
||||||
}
|
}
|
||||||
|
|
||||||
static uuid from_string(std::string_view str)
|
template<class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>,
|
||||||
|
class Allocator = std::allocator<CharT>>
|
||||||
|
static std::optional<uuid> from_string(std::basic_string<CharT, Traits, Allocator>& str) noexcept
|
||||||
{
|
{
|
||||||
return from_string(str.data(), str.size());
|
return from_string(str.c_str());
|
||||||
}
|
|
||||||
|
|
||||||
static uuid from_string(std::wstring_view str)
|
|
||||||
{
|
|
||||||
return from_string(str.data(), str.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -627,16 +525,12 @@ namespace uuids
|
|||||||
<< std::setw(2) << (int)id.data[15];
|
<< std::setw(2) << (int)id.data[15];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string to_string(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)
|
||||||
{
|
{
|
||||||
std::stringstream sstr;
|
std::basic_stringstream<CharT, Traits, Allocator> sstr;
|
||||||
sstr << id;
|
|
||||||
return sstr.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::wstring to_wstring(uuid const & id)
|
|
||||||
{
|
|
||||||
std::wstringstream sstr;
|
|
||||||
sstr << id;
|
sstr << id;
|
||||||
return sstr.str();
|
return sstr.str();
|
||||||
}
|
}
|
||||||
@ -745,18 +639,11 @@ namespace uuids
|
|||||||
class basic_uuid_random_generator
|
class basic_uuid_random_generator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using result_type = uuid;
|
using engine_type = UniformRandomNumberGenerator;
|
||||||
|
|
||||||
basic_uuid_random_generator()
|
explicit basic_uuid_random_generator(engine_type& gen) :
|
||||||
:generator(new UniformRandomNumberGenerator)
|
|
||||||
{
|
|
||||||
std::random_device rd;
|
|
||||||
generator->seed(rd());
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit basic_uuid_random_generator(UniformRandomNumberGenerator& gen) :
|
|
||||||
generator(&gen, [](auto) {}) {}
|
generator(&gen, [](auto) {}) {}
|
||||||
explicit basic_uuid_random_generator(UniformRandomNumberGenerator* gen) :
|
explicit basic_uuid_random_generator(engine_type* gen) :
|
||||||
generator(gen, [](auto) {}) {}
|
generator(gen, [](auto) {}) {}
|
||||||
|
|
||||||
uuid operator()()
|
uuid operator()()
|
||||||
@ -786,8 +673,6 @@ namespace uuids
|
|||||||
class uuid_name_generator
|
class uuid_name_generator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using result_type = uuid;
|
|
||||||
|
|
||||||
explicit uuid_name_generator(uuid const& namespace_uuid) noexcept
|
explicit uuid_name_generator(uuid const& namespace_uuid) noexcept
|
||||||
: nsuuid(namespace_uuid)
|
: nsuuid(namespace_uuid)
|
||||||
{}
|
{}
|
||||||
@ -810,8 +695,9 @@ namespace uuids
|
|||||||
void reset()
|
void reset()
|
||||||
{
|
{
|
||||||
hasher.reset();
|
hasher.reset();
|
||||||
uint8_t bytes[16];
|
std::byte bytes[16];
|
||||||
std::copy(std::begin(nsuuid), std::end(nsuuid), bytes);
|
auto nsbytes = nsuuid.as_bytes();
|
||||||
|
std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes);
|
||||||
hasher.process_bytes(bytes, 16);
|
hasher.process_bytes(bytes, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,31 +10,18 @@ using namespace uuids;
|
|||||||
|
|
||||||
TEST_CASE("Test default generator", "[gen][rand]")
|
TEST_CASE("Test default generator", "[gen][rand]")
|
||||||
{
|
{
|
||||||
uuid const guid = uuids::uuid_random_generator{}();
|
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.is_nil());
|
||||||
REQUIRE(guid.size() == 16);
|
|
||||||
REQUIRE(guid.version() == uuids::uuid_version::random_number_based);
|
REQUIRE(guid.version() == uuids::uuid_version::random_number_based);
|
||||||
REQUIRE(guid.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(guid.variant() == uuids::uuid_variant::rfc);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
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 random generator (conversion ctor w/ smart ptr)", "[gen][rand]")
|
TEST_CASE("Test random generator (conversion ctor w/ smart ptr)", "[gen][rand]")
|
||||||
{
|
{
|
||||||
std::random_device rd;
|
std::random_device rd;
|
||||||
@ -46,13 +33,11 @@ TEST_CASE("Test random generator (conversion ctor w/ smart ptr)", "[gen][rand]")
|
|||||||
uuids::uuid_random_generator dgen(&generator);
|
uuids::uuid_random_generator dgen(&generator);
|
||||||
auto id1 = dgen();
|
auto id1 = dgen();
|
||||||
REQUIRE(!id1.is_nil());
|
REQUIRE(!id1.is_nil());
|
||||||
REQUIRE(id1.size() == 16);
|
|
||||||
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
||||||
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
auto id2 = dgen();
|
auto id2 = dgen();
|
||||||
REQUIRE(!id2.is_nil());
|
REQUIRE(!id2.is_nil());
|
||||||
REQUIRE(id2.size() == 16);
|
|
||||||
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||||
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
@ -70,13 +55,11 @@ TEST_CASE("Test random generator (conversion ctor w/ ptr)", "[gen][rand]")
|
|||||||
uuids::uuid_random_generator dgen(generator.get());
|
uuids::uuid_random_generator dgen(generator.get());
|
||||||
auto id1 = dgen();
|
auto id1 = dgen();
|
||||||
REQUIRE(!id1.is_nil());
|
REQUIRE(!id1.is_nil());
|
||||||
REQUIRE(id1.size() == 16);
|
|
||||||
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
||||||
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
auto id2 = dgen();
|
auto id2 = dgen();
|
||||||
REQUIRE(!id1.is_nil());
|
REQUIRE(!id1.is_nil());
|
||||||
REQUIRE(id2.size() == 16);
|
|
||||||
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||||
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
@ -94,31 +77,11 @@ TEST_CASE("Test random generator (conversion ctor w/ ref)", "[gen][rand]")
|
|||||||
uuids::uuid_random_generator dgen(generator);
|
uuids::uuid_random_generator dgen(generator);
|
||||||
auto id1 = dgen();
|
auto id1 = dgen();
|
||||||
REQUIRE(!id1.is_nil());
|
REQUIRE(!id1.is_nil());
|
||||||
REQUIRE(id1.size() == 16);
|
|
||||||
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
||||||
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
auto id2 = dgen();
|
auto id2 = dgen();
|
||||||
REQUIRE(!id2.is_nil());
|
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.version() == uuids::uuid_version::random_number_based);
|
||||||
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
@ -128,18 +91,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]")
|
TEST_CASE("Test basic random generator (conversion ctor w/ ptr) w/ ranlux48_base", "[gen][rand]")
|
||||||
{
|
{
|
||||||
std::random_device rd;
|
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);
|
uuids::basic_uuid_random_generator<std::ranlux48_base> dgen(&generator);
|
||||||
auto id1 = dgen();
|
auto id1 = dgen();
|
||||||
REQUIRE(!id1.is_nil());
|
REQUIRE(!id1.is_nil());
|
||||||
REQUIRE(id1.size() == 16);
|
|
||||||
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
||||||
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
auto id2 = dgen();
|
auto id2 = dgen();
|
||||||
REQUIRE(!id2.is_nil());
|
REQUIRE(!id2.is_nil());
|
||||||
REQUIRE(id2.size() == 16);
|
|
||||||
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||||
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
@ -149,18 +113,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]")
|
TEST_CASE("Test basic random generator (conversion ctor w/ smart ptr) w/ ranlux48_base", "[gen][rand]")
|
||||||
{
|
{
|
||||||
std::random_device rd;
|
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());
|
uuids::basic_uuid_random_generator<std::ranlux48_base> dgen(generator.get());
|
||||||
auto id1 = dgen();
|
auto id1 = dgen();
|
||||||
REQUIRE(!id1.is_nil());
|
REQUIRE(!id1.is_nil());
|
||||||
REQUIRE(id1.size() == 16);
|
|
||||||
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
||||||
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
auto id2 = dgen();
|
auto id2 = dgen();
|
||||||
REQUIRE(!id2.is_nil());
|
REQUIRE(!id2.is_nil());
|
||||||
REQUIRE(id2.size() == 16);
|
|
||||||
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||||
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
@ -170,18 +135,19 @@ 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]")
|
TEST_CASE("Test basic random generator (conversion ctor w/ ref) w/ ranlux48_base", "[gen][rand]")
|
||||||
{
|
{
|
||||||
std::random_device rd;
|
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);
|
uuids::basic_uuid_random_generator<std::ranlux48_base> dgen(generator);
|
||||||
auto id1 = dgen();
|
auto id1 = dgen();
|
||||||
REQUIRE(!id1.is_nil());
|
REQUIRE(!id1.is_nil());
|
||||||
REQUIRE(id1.size() == 16);
|
|
||||||
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
REQUIRE(id1.version() == uuids::uuid_version::random_number_based);
|
||||||
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
auto id2 = dgen();
|
auto id2 = dgen();
|
||||||
REQUIRE(!id2.is_nil());
|
REQUIRE(!id2.is_nil());
|
||||||
REQUIRE(id2.size() == 16);
|
|
||||||
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
REQUIRE(id2.version() == uuids::uuid_version::random_number_based);
|
||||||
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
@ -190,28 +156,24 @@ TEST_CASE("Test basic random generator (conversion ctor w/ ref) w/ ranlux48_base
|
|||||||
|
|
||||||
TEST_CASE("Test name generator", "[gen][name]")
|
TEST_CASE("Test name generator", "[gen][name]")
|
||||||
{
|
{
|
||||||
uuids::uuid_name_generator dgen(uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43"));
|
uuids::uuid_name_generator dgen(uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value());
|
||||||
auto id1 = dgen("john");
|
auto id1 = dgen("john");
|
||||||
REQUIRE(!id1.is_nil());
|
REQUIRE(!id1.is_nil());
|
||||||
REQUIRE(id1.size() == 16);
|
|
||||||
REQUIRE(id1.version() == uuids::uuid_version::name_based_sha1);
|
REQUIRE(id1.version() == uuids::uuid_version::name_based_sha1);
|
||||||
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id1.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
auto id2 = dgen("jane");
|
auto id2 = dgen("jane");
|
||||||
REQUIRE(!id2.is_nil());
|
REQUIRE(!id2.is_nil());
|
||||||
REQUIRE(id2.size() == 16);
|
|
||||||
REQUIRE(id2.version() == uuids::uuid_version::name_based_sha1);
|
REQUIRE(id2.version() == uuids::uuid_version::name_based_sha1);
|
||||||
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id2.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
auto id3 = dgen("jane");
|
auto id3 = dgen("jane");
|
||||||
REQUIRE(!id3.is_nil());
|
REQUIRE(!id3.is_nil());
|
||||||
REQUIRE(id3.size() == 16);
|
|
||||||
REQUIRE(id3.version() == uuids::uuid_version::name_based_sha1);
|
REQUIRE(id3.version() == uuids::uuid_version::name_based_sha1);
|
||||||
REQUIRE(id3.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id3.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
auto id4 = dgen(L"jane");
|
auto id4 = dgen(L"jane");
|
||||||
REQUIRE(!id4.is_nil());
|
REQUIRE(!id4.is_nil());
|
||||||
REQUIRE(id4.size() == 16);
|
|
||||||
REQUIRE(id4.version() == uuids::uuid_version::name_based_sha1);
|
REQUIRE(id4.version() == uuids::uuid_version::name_based_sha1);
|
||||||
REQUIRE(id4.variant() == uuids::uuid_variant::rfc);
|
REQUIRE(id4.variant() == uuids::uuid_variant::rfc);
|
||||||
|
|
||||||
|
@ -9,82 +9,300 @@
|
|||||||
|
|
||||||
using namespace uuids;
|
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]")
|
TEST_CASE("Test default constructor", "[ctors]")
|
||||||
{
|
{
|
||||||
uuid empty;
|
uuid empty;
|
||||||
REQUIRE(empty.is_nil());
|
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;
|
using namespace std::string_literals;
|
||||||
|
|
||||||
{
|
{
|
||||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||||
auto guid = uuids::uuid::from_string(str);
|
REQUIRE(uuids::uuid::is_valid_uuid(str));
|
||||||
REQUIRE(uuids::to_string(guid) == str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43}"s;
|
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43}"s;
|
||||||
auto guid = uuids::uuid::from_string(str);
|
REQUIRE(uuids::uuid::is_valid_uuid(str));
|
||||||
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto guid = uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
|
auto str = L"47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||||
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
REQUIRE(uuids::uuid::is_valid_uuid(str));
|
||||||
REQUIRE(uuids::to_wstring(guid) == L"47183823-2574-4bfd-b411-99ed177d3e43");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto str = "4718382325744bfdb41199ed177d3e43"s;
|
auto str = L"{47183823-2574-4bfd-b411-99ed177d3e43}"s;
|
||||||
REQUIRE_NOTHROW(uuids::uuid::from_string(str));
|
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(char*) invalid format", "[parse]")
|
||||||
{
|
{
|
||||||
using namespace std::string_literals;
|
REQUIRE(!uuids::uuid::is_valid_uuid(""));
|
||||||
|
REQUIRE(!uuids::uuid::is_valid_uuid("{}"));
|
||||||
auto str = L"47183823-2574-4bfd-b411-99ed177d3e43"s;
|
REQUIRE(!uuids::uuid::is_valid_uuid("47183823-2574-4bfd-b411-99ed177d3e4"));
|
||||||
auto guid = uuids::uuid::from_string(str);
|
REQUIRE(!uuids::uuid::is_valid_uuid("47183823-2574-4bfd-b411-99ed177d3e430"));
|
||||||
REQUIRE(uuids::to_wstring(guid) == str);
|
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 from_string invalid format", "[parse]")
|
TEST_CASE("Test is_valid_uuid(basic_string) invalid format", "[parse]")
|
||||||
{
|
{
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
|
|
||||||
{
|
{
|
||||||
auto str = ""s;
|
auto str = ""s;
|
||||||
REQUIRE_THROWS_AS(uuids::uuid::from_string(str), uuids::uuid_error);
|
REQUIRE(!uuids::uuid::is_valid_uuid(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto str = "{}"s;
|
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;
|
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;
|
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;
|
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;
|
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 from_string(char*)", "[parse]")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e43";
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(uuids::to_string(guid) == str);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43}";
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto guid = uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value();
|
||||||
|
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||||
|
REQUIRE(uuids::to_string<wchar_t>(guid) == L"47183823-2574-4bfd-b411-99ed177d3e43");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"47183823-2574-4bfd-b411-99ed177d3e43";
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(uuids::to_string<wchar_t>(guid) == str);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "4718382325744bfdb41199ed177d3e43";
|
||||||
|
REQUIRE_NOTHROW(uuids::uuid::from_string(str));
|
||||||
|
REQUIRE(uuids::uuid::from_string(str).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "00000000-0000-0000-0000-000000000000";
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{00000000-0000-0000-0000-000000000000}";
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"00000000-0000-0000-0000-000000000000";
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"{00000000-0000-0000-0000-000000000000}";
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test from_string(basic_string)", "[parse]")
|
||||||
|
{
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(uuids::to_string(guid) == str);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43}"s;
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto guid = uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value();
|
||||||
|
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||||
|
REQUIRE(uuids::to_string<wchar_t>(guid) == L"47183823-2574-4bfd-b411-99ed177d3e43");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(uuids::to_string<wchar_t>(guid) == str);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "4718382325744bfdb41199ed177d3e43"s;
|
||||||
|
REQUIRE_NOTHROW(uuids::uuid::from_string(str));
|
||||||
|
REQUIRE(uuids::uuid::from_string(str).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "00000000-0000-0000-0000-000000000000"s;
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{00000000-0000-0000-0000-000000000000}"s;
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"00000000-0000-0000-0000-000000000000"s;
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = L"{00000000-0000-0000-0000-000000000000}"s;
|
||||||
|
auto guid = uuids::uuid::from_string(str).value();
|
||||||
|
REQUIRE(guid.is_nil());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test from_string(char*) invalid format", "[parse]")
|
||||||
|
{
|
||||||
|
REQUIRE(!uuids::uuid::from_string("").has_value());
|
||||||
|
REQUIRE(!uuids::uuid::from_string("{}").has_value());
|
||||||
|
REQUIRE(!uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e4").has_value());
|
||||||
|
REQUIRE(!uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e430").has_value());
|
||||||
|
REQUIRE(!uuids::uuid::from_string("{47183823-2574-4bfd-b411-99ed177d3e43").has_value());
|
||||||
|
REQUIRE(!uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43}").has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test from_string(basic_string) invalid format", "[parse]")
|
||||||
|
{
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = ""s;
|
||||||
|
REQUIRE(!uuids::uuid::from_string(str).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{}"s;
|
||||||
|
REQUIRE(!uuids::uuid::from_string(str).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e4"s;
|
||||||
|
REQUIRE(!uuids::uuid::from_string(str).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e430"s;
|
||||||
|
REQUIRE(!uuids::uuid::from_string(str).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||||
|
REQUIRE(!uuids::uuid::from_string(str).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto str = "47183823-2574-4bfd-b411-99ed177d3e43}"s;
|
||||||
|
REQUIRE(!uuids::uuid::from_string(str).has_value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +338,10 @@ TEST_CASE("Test iterators constructor", "[ctors]")
|
|||||||
TEST_CASE("Test equality", "[operators]")
|
TEST_CASE("Test equality", "[operators]")
|
||||||
{
|
{
|
||||||
uuid empty;
|
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(empty == empty);
|
||||||
REQUIRE(guid == guid);
|
REQUIRE(guid == guid);
|
||||||
@ -130,7 +351,11 @@ TEST_CASE("Test equality", "[operators]")
|
|||||||
TEST_CASE("Test comparison", "[operators]")
|
TEST_CASE("Test comparison", "[operators]")
|
||||||
{
|
{
|
||||||
auto empty = uuid{};
|
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();
|
auto id = gen();
|
||||||
|
|
||||||
REQUIRE(empty < id);
|
REQUIRE(empty < id);
|
||||||
@ -151,13 +376,15 @@ TEST_CASE("Test hashing", "[ops]")
|
|||||||
{
|
{
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
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 h1 = std::hash<std::string>{};
|
||||||
auto h2 = std::hash<uuid>{};
|
auto h2 = std::hash<uuid>{};
|
||||||
REQUIRE(h1(str) == h2(guid));
|
REQUIRE(h1(str) == h2(guid));
|
||||||
|
|
||||||
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{
|
std::unordered_set<uuids::uuid> ids{
|
||||||
uuid{},
|
uuid{},
|
||||||
@ -174,7 +401,10 @@ TEST_CASE("Test hashing", "[ops]")
|
|||||||
TEST_CASE("Test swap", "[ops]")
|
TEST_CASE("Test swap", "[ops]")
|
||||||
{
|
{
|
||||||
uuid empty;
|
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(empty.is_nil());
|
||||||
REQUIRE(!guid.is_nil());
|
REQUIRE(!guid.is_nil());
|
||||||
@ -190,52 +420,10 @@ TEST_CASE("Test swap", "[ops]")
|
|||||||
REQUIRE(!guid.is_nil());
|
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]")
|
TEST_CASE("Test constexpr", "[const]")
|
||||||
{
|
{
|
||||||
constexpr uuid empty;
|
constexpr uuid empty;
|
||||||
[[maybe_unused]] constexpr bool isnil = empty.is_nil();
|
[[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 uuids::uuid_variant variant = empty.variant();
|
||||||
[[maybe_unused]] constexpr uuid_version version = empty.version();
|
[[maybe_unused]] constexpr uuid_version version = empty.version();
|
||||||
}
|
}
|
||||||
@ -247,11 +435,11 @@ TEST_CASE("Test size", "[operators]")
|
|||||||
|
|
||||||
TEST_CASE("Test assignment", "[ops]")
|
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;
|
auto id2 = id1;
|
||||||
REQUIRE(id1 == id2);
|
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);
|
REQUIRE(id1 != id2);
|
||||||
|
|
||||||
auto id3 = std::move(id2);
|
auto id3 = std::move(id2);
|
||||||
|
Loading…
Reference in New Issue
Block a user