- updates after Kona

- new constructors
- namespace constants for name-based uuids
This commit is contained in:
Marius Bancila 2019-05-17 12:33:35 +03:00
parent f7a15f1e72
commit b74a5eb7e9
5 changed files with 308 additions and 69 deletions

260
P0959.md
View File

@ -1,7 +1,7 @@
| ___ | ___ |
| --- | --- |
| Doc. No.: | P0959R2 |
| Date: | 2019-01-08 |
| Doc. No.: | P0959R3 |
| Date: | 2019-05-20 |
| Reply to: | Marius Bancila, Tony van Eerd |
| Audience: | Library WG |
| Title: | A Proposal for a Universally Unique Identifier Library |
@ -91,6 +91,26 @@ Based on this feedback the following changes have been done in this version:
* removed the class `uuid_error`
* footnote on the use of the name Microsoft
### 1.4 P0959R3
P0959R2 was discussed by LEWGI in Kona with the following feedback:
* The random number generator is not random enough; may want to consult W23 - or not provide a default.
* Why `string` and `char*` instead of `string_view`?
* Some methods that can be `constexpr`/`noexcept` are not.
* Need more explanations about the choices of ordering and how the RFC works in that regard.
* Need to specify which algorithm the name generator uses.
* The uuid should be a `class` not a `struct`.
* The three-way comparison operator cannot be defaulted if the class doesn't have at least exposition only members.
Based on this feedback and further considerations, the following changes have been done in this version:
* Added detailed explanation of the algorithms for generating uuids.
* `from_string()` and non-member `swap()` declared with `noexcept`.
* The `uuid` type is now defined as a class.
* Added an exposition-only member to hint and the possible internal representation of the uuid data.
* Added `uuid` constructors from arrays.
* Added implementation-specific constant uuids that can be used for generating name-based uuids.
* Added a new section (Open discussion) in this document to address questions/concerns from the committee.
## II. Motivation
Universally unique identifiers (*uuid*), also known as Globally Unique Identifiers (*guid*s), are commonly used in many types of applications to uniquely identify data. A standard uuid library would benefit developers that currently have to either use operating system specific APIs for creating new uuids or resort to 3rd party libraries, such as *boost::uuid*.
@ -147,6 +167,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.
@ -438,45 +482,49 @@ namespace std {
```cpp
namespace std {
struct uuid
class uuid
{
using value_type = uint8_t;
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 bool is_nil() const noexcept;
constexpr void swap(uuid & other) noexcept;
constexpr std::span<std::byte const, 16> as_bytes() const;
constexpr std::strong_ordering operator<=>(uuid const&) const noexcept = default;
template<class CharT = char>
static bool is_valid_uuid(CharT const * str) noexcept;
template<class CharT = char>
static bool is_valid_uuid(CharT const * str) noexcept;
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
static bool is_valid_uuid(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
static bool is_valid_uuid(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
template<class CharT = char>
static uuid from_string(CharT const * str) noexcept;
template<class CharT = char>
static uuid from_string(CharT const * str) noexcept;
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
static uuid from_string(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
static uuid from_string(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
private:
template <class Elem, class Traits>
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
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
};
}
```
@ -497,7 +545,19 @@ namespace std {
}
```
### Constants
The following implementation-specific constant uuid values can be used for generating name-based uuids.
```cpp
namespace std {
constexpr uuid uuid_namespace_dns = /* implementation-specific */;
constexpr uuid uuid_namespace_url = /* implementation-specific */;
constexpr uuid uuid_namespace_oid = /* implementation-specific */;
constexpr uuid uuid_namespace_x500 = /* implementation-specific */;
}
```
### Generators
#### Random uuid generators
`basic_uuid_random_generator<T>` is a class template for generating random or pseudo-random UUIDs (version 4, i.e. `uuid_version::random_number_based`).
The type template parameter represents a function object that implements both the [`RandomNumberEngine`](http://en.cppreference.com/w/cpp/concept/UniformRandomBitGenerator) and [`UniformRandomBitGenerator`](http://en.cppreference.com/w/cpp/concept/RandomNumberEngine) concepts.
`basic_uuid_random_generator` can be constructed with a reference or pointer to a an objects that satisfies the `UniformRandomNumberGenerator` requirements.
@ -522,9 +582,14 @@ 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 and has to be initialized with another UUID.
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 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
@ -542,11 +607,25 @@ namespace std {
};
}
```
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.
`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 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 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
@ -559,6 +638,25 @@ namespace std {
}
```
The generated uuid's parts are as follows:
* the timestamp is a 60-bit value, representing the number of 100 nanosecond intervals since 15 October 1582 00:00:000000000.
* the clock sequence is a 14-bit value, that is initially a high-quality pseudo-random value; when the previous value is known, it is simply incremented by one.
* the node identifier is an IEEE 802 MAC address (when multiple are available any could be used); if no such address is available, a pseudo-randomly generated value may be used, in which case the multicast bit (least significant bit of the first byte) is set to 1, this to avoid clashes with legitimate IEEE 802 addresses.
The algorithm for generating time-based uuids is as follows:
* Consider the timestamp to be a 60-bit unsigned integer and the clock sequence to be a 14-bit unsigned integer. Sequentially number the bits in a field, starting with zero for the least significant bit.
* Determine the values for the UTC-based timestamp and clock sequence to be used in the UUID as a 60-bit count of 100-nanosecond intervals since 00:00:00.00, 15 October 1582.
* Copy the bits of the timestamp to the uuid bits as follows, using the same order of significance:
* bits 0 through 31 to the `time_low` field
* bits 32 through 47 to the `time_mid` field
* bits 48 through 59 to the 12 least significant bits (bits 0 through 11) of the `time_hi_and_version` field
* Copy the bits of the clock sequence to the uuid bits as follows, using the same order of significance:
* bits 0 through 7 to the `clock_seq_low` field
* bits 8 through 13 to the 6 least significant bits (bits 0 through 5) of the `clock_seq_hi_and_reserved` field
* Set the four most significant bits (bits 12 through 15) of the `time_hi_and_version` field to the binary value 0001 (representing version 1 as defined in the section _VII. UUID format specification_).
* Set the two most significant bits (bits 6 and 7) of the `clock_seq_hi_and_reserved` to zero and one, respectively.
* Set the `node` field to the 48-bit IEEE address in the same order of significance as the address.
### Specialization
The template specializations of `std::hash` for the `uuid` class allow users to obtain hashes of UUIDs.
```cpp
@ -594,43 +692,47 @@ 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;
public:
using value_type = uint8_t;
constexpr uuid() noexcept = default;
constexpr explicit uuid(std::span<value_type, 16> bytes);
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);
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 uuid_variant variant() const noexcept;
constexpr uuid_version version() const noexcept;
constexpr bool is_nil() const noexcept;
constexpr void swap(uuid & other) noexcept;
constexpr void swap(uuid & other) noexcept;
constexpr std::span<std::byte const, 16> as_bytes() const;
constexpr std::span<std::byte const, 16> as_bytes() const;
template<class CharT = char>
static bool is_valid_uuid(CharT const * str) noexcept;
template<class CharT = char>
static bool is_valid_uuid(CharT const * str) noexcept;
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
static bool is_valid_uuid(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
static bool is_valid_uuid(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
template<class CharT = char>
static uuid from_string(CharT const * str) noexcept;
template<class CharT = char>
static uuid from_string(CharT const * str) noexcept;
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
static uuid from_string(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
static uuid from_string(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
private:
template <class Elem, class Traits>
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
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
};
}
```
@ -710,7 +812,31 @@ 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 there is no implicit conversion from `std::basic_string` to `std::basic_string_view`, [2] would not work. Instead, it should be:
```cpp
auto id2 = uuid::from_string(std::string_view {str});
```
#### 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

View File

@ -35,6 +35,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 |
@ -153,6 +162,17 @@ The following is a list of examples for using the library:
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 };
uuid id(std::begin(arr), std::end(arr));
assert(uuids::to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43");
// or
uuids::uuid id{{
0x47, 0x18, 0x38, 0x23,
0x25, 0x74,
0x4b, 0xfd,
0xb4, 0x11,
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43}};
assert(uuids::to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43");
```
* Comparing UUIDs

View File

@ -244,7 +244,11 @@ namespace uuids
};
}
// --------------------------------------------------------------------------------------------------------------------------
// 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.
@ -266,6 +270,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
{
@ -293,7 +301,7 @@ namespace uuids
reserved
};
// 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
@ -304,6 +312,9 @@ namespace uuids
name_based_sha1 = 5 // The name-based version specified in RFS 4122 with SHA1 hashing
};
// --------------------------------------------------------------------------------------------------------------------------
// uuid class
// --------------------------------------------------------------------------------------------------------------------------
class uuid
{
public:
@ -311,6 +322,16 @@ namespace uuids
constexpr uuid() noexcept : data({}) {};
uuid(value_type(&arr)[16]) noexcept
{
std::copy(std::cbegin(arr), std::cend(arr), std::begin(data));
}
uuid(std::array<value_type, 16> const & arr) noexcept
{
std::copy(std::cbegin(arr), std::cend(arr), std::begin(data));
}
explicit uuid(gsl::span<value_type, 16> bytes)
{
std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data));
@ -493,6 +514,10 @@ namespace uuids
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
};
// --------------------------------------------------------------------------------------------------------------------------
// operators and non-member functions
// --------------------------------------------------------------------------------------------------------------------------
inline bool operator== (uuid const& lhs, uuid const& rhs) noexcept
{
return lhs.data == rhs.data;
@ -546,9 +571,29 @@ namespace uuids
inline void swap(uuids::uuid & lhs, uuids::uuid & rhs) noexcept
{
lhs.swap(rhs);
lhs.swap(rhs);
}
// --------------------------------------------------------------------------------------------------------------------------
// namespace IDs that could be used for generating name-based uuids
// --------------------------------------------------------------------------------------------------------------------------
// Name string is a fully-qualified domain name
static uuid uuid_namespace_dns{ {0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
// Name string is a URL
static uuid uuid_namespace_url{ {0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
// Name string is an ISO OID (See https://oidref.com/, https://en.wikipedia.org/wiki/Object_identifier)
static uuid uuid_namespace_oid{ {0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
// Name string is an X.500 DN, in DER or a text output format (See https://en.wikipedia.org/wiki/X.500, https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One)
static uuid uuid_namespace_x500{ {0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
// --------------------------------------------------------------------------------------------------------------------------
// uuid generators
// --------------------------------------------------------------------------------------------------------------------------
class uuid_system_generator
{
public:

View File

@ -154,6 +154,14 @@ TEST_CASE("Test basic random generator (conversion ctor w/ ref) w/ ranlux48_base
REQUIRE(id1 != id2);
}
TEST_CASE("Test namespaces", "[gen][name]")
{
REQUIRE(uuid_namespace_dns == uuids::uuid::from_string("6ba7b810-9dad-11d1-80b4-00c04fd430c8"));
REQUIRE(uuid_namespace_url == uuids::uuid::from_string("6ba7b811-9dad-11d1-80b4-00c04fd430c8"));
REQUIRE(uuid_namespace_oid == uuids::uuid::from_string("6ba7b812-9dad-11d1-80b4-00c04fd430c8"));
REQUIRE(uuid_namespace_x500 == uuids::uuid::from_string("6ba7b814-9dad-11d1-80b4-00c04fd430c8"));
}
TEST_CASE("Test name generator (char*)", "[gen][name]")
{
uuids::uuid_name_generator dgen(uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value());

View File

@ -335,6 +335,46 @@ 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;