revision 1 based on standard committe and community feedback
This commit is contained in:
parent
4e27a1e02a
commit
54b54bdab5
210
P0959.md
210
P0959.md
@ -25,8 +25,9 @@ This proposal is a pure library extension. It does not require changes to any st
|
||||
The proposed library, that should be available in a new header called `<uuid>` in the namespace `std`, provides:
|
||||
* a class called `uuid` that represents a universally unique identifier
|
||||
* strongly type enums `uuid_variant` and `uuid_version` to represent the possible variant and version types of a UUID
|
||||
* a class called `uuid_error` representing an exception type for `uuid` operations
|
||||
* function objects that generate UUIDs, called generators: `basic_uuid_random_generator<T>`, `uuid_random_generator`, `uuid_name_generator`
|
||||
* string conversion functions `std::to_string()`, `std::to_wstring()` 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`
|
||||
* comparison operators `==`, `!=`, `<`
|
||||
* `std::swap()` overload for `uuid`
|
||||
* `std::hash<>` specialization for `uuid`
|
||||
@ -40,22 +41,9 @@ uuid empty;
|
||||
auto empty = uuid{};
|
||||
```
|
||||
|
||||
### string_view constructors
|
||||
|
||||
Conversion constructors from `std::string_view` and `std::wstring_view` allow to create `uuid` instances from various strings.
|
||||
|
||||
The input argument must have the form `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` where `x` is a hexadecimal digit. Should the argument be of a different format a nil UUID would be created.
|
||||
|
||||
```cpp
|
||||
uuid id1("47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
|
||||
std::wstring str=L"47183823-2574-4bfd-b411-99ed177d3e43";
|
||||
uuid id2(str);
|
||||
```
|
||||
|
||||
### Iterators constructors
|
||||
|
||||
The conversion constructor that takes two forward iterators constructs an `uuid` with the content of the range \[first, last). It requires the range to have exactly 16 elements, otherwise the result is a nil `uuid`. This constructor follows the conventions of other containers in the standard library.
|
||||
The conversion constructor that takes two forward iterators constructs an `uuid` with the content of the range \[first, last). It requires the range to have exactly 16 elements, otherwise the behaviour is undefined. This constructor follows the conventions of other containers in the standard library.
|
||||
|
||||
```cpp
|
||||
std::array<uuid::value_type, 16> arr{{
|
||||
@ -78,6 +66,26 @@ uuid::value_type arr[16] = {
|
||||
uuid id(std::begin(arr), std::end(arr));
|
||||
```
|
||||
|
||||
### Span constructor
|
||||
|
||||
The conversion constructor that takes a `std::span` constructs a `uuid` from a contiguous sequence of 16 bytes.
|
||||
|
||||
```cpp
|
||||
std::array<uuid::value_type, 16> arr{ {
|
||||
0x47, 0x18, 0x38, 0x23,
|
||||
0x25, 0x74,
|
||||
0x4b, 0xfd,
|
||||
0xb4, 0x11,
|
||||
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43
|
||||
} };
|
||||
|
||||
std::span<uuid::value_type, 16> data(arr);
|
||||
|
||||
uuid id{ data };
|
||||
|
||||
assert(to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
```
|
||||
|
||||
### Size
|
||||
|
||||
Member function `size()` indicates the number of bytes in the UUID. Because this is a fixed size structure this function always returns 16.
|
||||
@ -88,15 +96,19 @@ assert(id.size() == 16);
|
||||
|
||||
### Nil
|
||||
|
||||
A nil UUID is a special UUID that has all the bits set to 0. Its canonical textual representation is `00000000-0000-0000-0000-000000000000`. Member function `is_nil()` indicates whether the `uuid` has all the bits set to 0. A nil uuid is created by the default constructor or by the string conversion constructors when failing to parse the input argument.
|
||||
A nil UUID is a special UUID that has all the bits set to 0. Its canonical textual representation is `00000000-0000-0000-0000-000000000000`. Member function `is_nil()` indicates whether the `uuid` has all the bits set to 0. A nil UUID is created by the default constructor or by parsing the strings `00000000-0000-0000-0000-000000000000` or `{00000000-0000-0000-0000-000000000000}`.
|
||||
|
||||
```cpp
|
||||
uuid id;
|
||||
assert(id.is_nil());
|
||||
|
||||
uuid id = from_string("00000000-0000-0000-0000-000000000000");
|
||||
assert(id.is_nil());
|
||||
```
|
||||
|
||||
### Iterators
|
||||
|
||||
Constant and mutable iterators allow direct access to the underlaying `uuid` data. This enables both direct reading and writing of the `uuid` bits. The `uuid` class has both const and non-const `begin()` and `end()` members to return constant and mutable iterators to the first and the one-past-last element of the UUID data.
|
||||
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{{
|
||||
@ -107,12 +119,8 @@ std::array<uuid::value_type, 16> arr{{
|
||||
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43
|
||||
}};
|
||||
|
||||
uuid id;
|
||||
assert(id.is_nil());
|
||||
|
||||
std::copy(std::cbegin(arr), std::cend(arr), std::begin(id));
|
||||
assert(!id.is_nil());
|
||||
assert(id.string() == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
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)
|
||||
@ -131,6 +139,24 @@ assert(id.version() == uuid_version::random_number_based);
|
||||
assert(id.variant() == uuid_variant::rfc);
|
||||
```
|
||||
|
||||
### Span view
|
||||
Member function `as_bytes()` converts the `uuid` into a view of its underlying bytes.
|
||||
```cpp
|
||||
std::array<uuids::uuid::value_type, 16> arr{ {
|
||||
0x47, 0x18, 0x38, 0x23,
|
||||
0x25, 0x74,
|
||||
0x4b, 0xfd,
|
||||
0xb4, 0x11,
|
||||
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43
|
||||
} };
|
||||
|
||||
const uuid id{ arr };
|
||||
assert(!id.is_nil());
|
||||
|
||||
auto view = id.as_bytes();
|
||||
assert(memcmp(view.data(), arr.data(), arr.size()) == 0);
|
||||
```
|
||||
|
||||
### Swapping
|
||||
|
||||
Both member and non-member `swap()` functions are available to perform the swapping of `uuid` values.
|
||||
@ -153,6 +179,17 @@ assert(empty.is_nil());
|
||||
assert(!id.is_nil());
|
||||
```
|
||||
|
||||
### string parsing
|
||||
|
||||
Non-member overloaded function `from_string()` allow 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.
|
||||
|
||||
```cpp
|
||||
auto id1 = from_string("47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
auto id2 = from_string(L"{47183823-2574-4bfd-b411-99ed177d3e43}");
|
||||
```
|
||||
|
||||
### 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.
|
||||
@ -324,52 +361,54 @@ namespace std {
|
||||
}
|
||||
```
|
||||
|
||||
### `uuid_error` class
|
||||
```cpp
|
||||
namespace std {
|
||||
struct uuid_error : public std::runtime_error
|
||||
{
|
||||
explicit uuid_error(std::string_view message);
|
||||
explicit uuid_error(char const * message);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### `uuid` class
|
||||
|
||||
```cpp
|
||||
namespace std {
|
||||
struct uuid
|
||||
{
|
||||
public:
|
||||
typedef uint8_t value_type;
|
||||
typedef uint8_t& reference;
|
||||
typedef uint8_t const& const_reference;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
struct uuid
|
||||
{
|
||||
typedef uint8_t value_type;
|
||||
typedef /*implementation-defined*/ const_iterator;
|
||||
|
||||
constexpr uuid() noexcept = default;
|
||||
|
||||
explicit uuid(std::span<value_type, 16> bytes);
|
||||
|
||||
typedef /*implementation-defined*/ iterator;
|
||||
typedef /*implementation-defined*/ const_iterator;
|
||||
|
||||
static constexpr size_t state_size = 16;
|
||||
template<typename ForwardIterator>
|
||||
explicit uuid(ForwardIterator first, ForwardIterator last);
|
||||
|
||||
public:
|
||||
constexpr uuid() noexcept;
|
||||
constexpr uuid_variant variant() const noexcept;
|
||||
constexpr uuid_version version() const noexcept;
|
||||
constexpr std::size_t size() const noexcept;
|
||||
constexpr bool is_nil() const noexcept;
|
||||
|
||||
template<typename ForwardIterator>
|
||||
explicit uuid(ForwardIterator first, ForwardIterator last);
|
||||
void swap(uuid & other) noexcept;
|
||||
|
||||
explicit uuid(std::string_view str);
|
||||
explicit uuid(std::wstring_view str);
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
|
||||
constexpr uuid_variant variant() const noexcept;
|
||||
constexpr uuid_version version() const noexcept;
|
||||
constexpr std::size_t size() const noexcept;
|
||||
constexpr bool is_nil() const noexcept;
|
||||
std::span<std::byte, 16> as_bytes();
|
||||
std::span<std::byte const, 16> as_bytes() const;
|
||||
|
||||
private:
|
||||
friend bool operator==(uuid const & lhs, uuid const & rhs) noexcept;
|
||||
friend bool operator<(uuid const & lhs, uuid const & rhs) noexcept;
|
||||
|
||||
void swap(uuid & other) noexcept;
|
||||
|
||||
iterator begin() noexcept;
|
||||
const_iterator begin() const noexcept;
|
||||
iterator end() noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
|
||||
private:
|
||||
friend bool operator==(uuid const & lhs, uuid const & rhs) noexcept;
|
||||
friend bool operator<(uuid const & lhs, uuid const & rhs) noexcept;
|
||||
|
||||
template <class Elem, class Traits>
|
||||
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
|
||||
};
|
||||
template <class Elem, class Traits>
|
||||
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### non-member functions
|
||||
@ -387,41 +426,54 @@ namespace std {
|
||||
|
||||
inline std::string to_string(uuid const & id);
|
||||
inline std::wstring to_wstring(uuid const & id);
|
||||
|
||||
template <typename TChar>
|
||||
inline uuid from_string(TChar const * const str, size_t const size);
|
||||
inline uuid from_string(std::string_view str);
|
||||
inline uuid from_string(std::wstring_view str);
|
||||
|
||||
inline std::span<uuid::value_type, 16> as_bytes(uuid id);
|
||||
}
|
||||
```
|
||||
|
||||
### Generators
|
||||
`basic_uuid_random_generator<T>` is a class template for generating random or pseudo-random UUIDs (version 4, i.e. `uuid_version::random_number_based`). The type template parameter represents a function object that implements both the [`RandomNumberEngine`](http://en.cppreference.com/w/cpp/concept/UniformRandomBitGenerator) and [`UniformRandomBitGenerator`](http://en.cppreference.com/w/cpp/concept/RandomNumberEngine) concepts. `basic_uuid_random_generator` can be either default constructed or constructed with a reference or pointer to a an objects that satisfies the `UniformRandomNumberGenerator` requirements.
|
||||
```cpp
|
||||
template <typename UniformRandomNumberGenerator>
|
||||
class basic_uuid_random_generator
|
||||
{
|
||||
public:
|
||||
typedef uuid result_type;
|
||||
namespace std {
|
||||
template <typename UniformRandomNumberGenerator>
|
||||
class basic_uuid_random_generator
|
||||
{
|
||||
public:
|
||||
typedef uuid result_type;
|
||||
|
||||
basic_uuid_random_generator();
|
||||
explicit basic_uuid_random_generator(UniformRandomNumberGenerator& gen);
|
||||
explicit basic_uuid_random_generator(UniformRandomNumberGenerator* gen);
|
||||
basic_uuid_random_generator();
|
||||
explicit basic_uuid_random_generator(UniformRandomNumberGenerator& gen);
|
||||
explicit basic_uuid_random_generator(UniformRandomNumberGenerator* gen);
|
||||
|
||||
uuid operator()();
|
||||
};
|
||||
uuid operator()();
|
||||
};
|
||||
}
|
||||
```
|
||||
A type alias `uuid_random_generator` is provided for convenience as `std::mt19937` is probably the preferred choice of a pseudo-random number generator engine in most cases.
|
||||
```cpp
|
||||
using uuid_random_generator = basic_uuid_random_generator<std::mt19937>;
|
||||
namespace std {
|
||||
using uuid_random_generator = basic_uuid_random_generator<std::mt19937>;
|
||||
}
|
||||
```
|
||||
`uuid_name_generator` is a function object that generates new UUIDs from a name. It has to be initialized with another UUID and has overloaded `operator()` for both `std::string_view` and `std::wstring_view`.
|
||||
```cpp
|
||||
class uuid_name_generator
|
||||
{
|
||||
public:
|
||||
typedef uuid result_type;
|
||||
namespace std {
|
||||
class uuid_name_generator
|
||||
{
|
||||
public:
|
||||
typedef uuid result_type;
|
||||
|
||||
explicit uuid_name_generator(uuid const& namespace_uuid) noexcept;
|
||||
|
||||
uuid operator()(std::string_view name);
|
||||
uuid operator()(std::wstring_view name);
|
||||
};
|
||||
explicit uuid_name_generator(uuid const& namespace_uuid) noexcept;
|
||||
|
||||
uuid operator()(std::string_view name);
|
||||
uuid operator()(std::wstring_view name);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Specialization
|
||||
|
161
README.md
161
README.md
@ -44,67 +44,96 @@ Other:
|
||||
|
||||
This project is currently under development and should be ignored until further notice.
|
||||
|
||||
## Library history
|
||||
This library is an implementation of the proposal P0959. As the proposal evolves based on the standard commity and the C++ community feedback, this library implementation will reflect those changes.
|
||||
|
||||
### Revision 1
|
||||
Changes from the first draft:
|
||||
* Removed string constructors and replaced with free overloaded function `from_string()`.
|
||||
* Parsing strings to `uuid` throws exception `uuid_error` instead of creating a nil uuid when the operation fails.
|
||||
* {} included in the supported format, i.e. `{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}`.
|
||||
* Removed `state_size`.
|
||||
* Rename member function `nil()` to `is_nil()`.
|
||||
* The default constructor is defaulted.
|
||||
* Added a conversion construct from `std::span<uint_8, 16>`.
|
||||
* Added the free 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.
|
||||
* Removed mutable iterators (but preserved the constant iterators).
|
||||
* Removed typedefs and others container-like parts.
|
||||
|
||||
## Using the library
|
||||
The following is a list of examples for using the library:
|
||||
* Creating a nil UUID
|
||||
|
||||
```cpp
|
||||
uuid empty;
|
||||
assert(empty.is_nil());
|
||||
assert(empty.size() == 16);
|
||||
```
|
||||
|
||||
* Creating a new UUID
|
||||
|
||||
```cpp
|
||||
uuid const guid = uuids::uuid_system_generator{}();
|
||||
assert(!guid.is_nil());
|
||||
assert(guid.size() == 16);
|
||||
assert(guid.version() == uuids::uuid_version::random_number_based);
|
||||
assert(guid.variant() == uuids::uuid_variant::rfc);
|
||||
uuid const id = uuids::uuid_system_generator{}();
|
||||
assert(!id.is_nil());
|
||||
assert(id.size() == 16);
|
||||
assert(id.version() == uuids::uuid_version::random_number_based);
|
||||
assert(id.variant() == uuids::uuid_variant::rfc);
|
||||
```
|
||||
|
||||
* Creating a new UUID with a default random generator
|
||||
|
||||
```cpp
|
||||
uuids::uuid_random_generator gen;
|
||||
uuid const guid = gen();
|
||||
assert(!guid.is_nil());
|
||||
assert(guid.size() == 16);
|
||||
assert(guid.version() == uuids::uuid_version::random_number_based);
|
||||
assert(guid.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 a particular random generator
|
||||
|
||||
```cpp
|
||||
std::random_device rd;
|
||||
std::ranlux48_base generator(rd());
|
||||
uuids::basic_uuid_random_generator<std::ranlux48_base> gen(&generator);
|
||||
|
||||
uuid const guid = gen();
|
||||
assert(!guid.is_nil());
|
||||
assert(guid.size() == 16);
|
||||
assert(guid.version() == uuids::uuid_version::random_number_based);
|
||||
assert(guid.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
|
||||
|
||||
```cpp
|
||||
uuids::uuid_name_generator gen;
|
||||
uuid const guid = gen();
|
||||
assert(!guid.is_nil());
|
||||
assert(guid.size() == 16);
|
||||
assert(guid.version() == uuids::uuid_version::name_based_sha1);
|
||||
assert(guid.variant() == uuids::uuid_variant::rfc);
|
||||
uuid const id = gen();
|
||||
|
||||
assert(!id.is_nil());
|
||||
assert(id.size() == 16);
|
||||
assert(id.version() == uuids::uuid_version::name_based_sha1);
|
||||
assert(id.variant() == uuids::uuid_variant::rfc);
|
||||
```
|
||||
|
||||
* Create a UUID from a string
|
||||
|
||||
```cpp
|
||||
using namespace std::string_literals;
|
||||
|
||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||
uuid guid(str);
|
||||
assert(guid.string() == str);
|
||||
uuid id(from_string(str));
|
||||
assert(uuids::to_string(id) == str);
|
||||
|
||||
// or
|
||||
|
||||
uuid id(from_string(L"{47183823-2574-4bfd-b411-99ed177d3e43}"s));
|
||||
assert(id.wstring() == str);
|
||||
```
|
||||
or
|
||||
```cpp
|
||||
auto str = L"47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||
uuid guid(str);
|
||||
assert(guid.wstring() == str);
|
||||
```
|
||||
* Creating a UUID from an array
|
||||
|
||||
* Creating a UUID from sequence of 16 bytes
|
||||
|
||||
```cpp
|
||||
std::array<uuids::uuid::value_type, 16> arr{{
|
||||
0x47, 0x18, 0x38, 0x23,
|
||||
@ -112,54 +141,60 @@ std::array<uuids::uuid::value_type, 16> arr{{
|
||||
0x4b, 0xfd,
|
||||
0xb4, 0x11,
|
||||
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43}};
|
||||
uuid guid(std::begin(arr), std::end(arr));
|
||||
assert(id.string() == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
```
|
||||
or
|
||||
```cpp
|
||||
uuid id(arr);
|
||||
|
||||
assert(uuids::to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
|
||||
// or
|
||||
|
||||
uuids::uuid::value_type arr[16] = {
|
||||
0x47, 0x18, 0x38, 0x23,
|
||||
0x25, 0x74,
|
||||
0x4b, 0xfd,
|
||||
0xb4, 0x11,
|
||||
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 };
|
||||
uuid guid(std::begin(arr), std::end(arr));
|
||||
assert(guid.string() == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
uuid id(std::begin(arr), std::end(arr));
|
||||
assert(uuids::to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
```
|
||||
* Comparing UUIDs
|
||||
```cpp
|
||||
uuid empty;
|
||||
uuid guid = uuids::uuid_system_generator{}();
|
||||
|
||||
assert(empty == empty);
|
||||
assert(guid == guid);
|
||||
assert(empty != guid);
|
||||
```
|
||||
* Swapping UUIDs
|
||||
```cpp
|
||||
uuid empty;
|
||||
uuid guid = uuids::uuid_system_generator{}();
|
||||
uuid id = uuids::uuid_system_generator{}();
|
||||
assert(empty == empty);
|
||||
assert(id == id);
|
||||
assert(empty != id);
|
||||
```
|
||||
|
||||
* Swapping UUIDs
|
||||
|
||||
```cpp
|
||||
uuid empty;
|
||||
uuid id = uuids::uuid_system_generator{}();
|
||||
|
||||
assert(empty.is_nil());
|
||||
assert(!guid.is_nil());
|
||||
assert(!id.is_nil());
|
||||
|
||||
std::swap(empty, guid);
|
||||
std::swap(empty, id);
|
||||
|
||||
assert(!empty.is_nil());
|
||||
assert(guid.is_nil());
|
||||
assert(id.is_nil());
|
||||
|
||||
empty.swap(guid);
|
||||
empty.swap(id);
|
||||
|
||||
assert(empty.is_nil());
|
||||
assert(!guid.is_nil());
|
||||
assert(!id.is_nil());
|
||||
```
|
||||
* Converting to string
|
||||
|
||||
```cpp
|
||||
uuid empty;
|
||||
assert(uuids::to_string(empty) == "00000000-0000-0000-0000-000000000000");
|
||||
assert(uuids::to_wstring(empty) == L"00000000-0000-0000-0000-000000000000");
|
||||
```
|
||||
|
||||
* Iterating through the UUID data
|
||||
|
||||
```cpp
|
||||
std::array<uuids::uuid::value_type, 16> arr{{
|
||||
0x47, 0x18, 0x38, 0x23,
|
||||
@ -168,18 +203,15 @@ std::array<uuids::uuid::value_type, 16> arr{{
|
||||
0xb4, 0x11,
|
||||
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43}};
|
||||
|
||||
uuid guid;
|
||||
assert(guid.is_nil());
|
||||
|
||||
std::copy(std::cbegin(arr), std::cend(arr), std::begin(guid));
|
||||
assert(!guid.is_nil());
|
||||
assert(guid.string() == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
uuid id(arr);
|
||||
|
||||
size_t i = 0;
|
||||
for (auto const & b : guid)
|
||||
for (auto const & b : id)
|
||||
assert(arr[i++] == b);
|
||||
```
|
||||
|
||||
* Using with an orderered associative container
|
||||
|
||||
```cpp
|
||||
uuids::uuid_random_generator gen;
|
||||
std::set<uuids::uuid> ids{uuid{}, gen(), gen(), gen(), gen()};
|
||||
@ -187,7 +219,9 @@ std::set<uuids::uuid> ids{uuid{}, gen(), gen(), gen(), gen()};
|
||||
assert(ids.size() == 5);
|
||||
assert(ids.find(uuid{}) != ids.end());
|
||||
```
|
||||
|
||||
* Using in an unordered associative container
|
||||
|
||||
```cpp
|
||||
uuids::uuid_random_generator gen;
|
||||
std::unordered_set<uuids::uuid> ids{uuid{}, gen(), gen(), gen(), gen()};
|
||||
@ -195,16 +229,25 @@ std::unordered_set<uuids::uuid> ids{uuid{}, gen(), gen(), gen(), gen()};
|
||||
assert(ids.size() == 5);
|
||||
assert(ids.find(uuid{}) != ids.end());
|
||||
```
|
||||
|
||||
* Hashing UUIDs
|
||||
|
||||
```cpp
|
||||
using namespace std::string_literals;
|
||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||
uuid id(from_string(str));
|
||||
|
||||
auto h1 = std::hash<std::string>{};
|
||||
auto h2 = std::hash<uuid>{};
|
||||
assert(h1(str) == h2(guid));
|
||||
assert(h1(str) == h2(id));
|
||||
```
|
||||
|
||||
## Support
|
||||
The library is supported on all major operating systems: Windows, Linux and Mac OS.
|
||||
|
||||
## Dependencies
|
||||
Because no major compiler supports `std::span` yet the [Microsoft Guidelines Support Library](https://github.com/Microsoft/GSL) (aka GSL) is used for its span implementation (from which the standard version was defined).
|
||||
|
||||
## Testing
|
||||
A testing project is available in the sources. To build and execute the tests do the following:
|
||||
* Clone or download this repository
|
||||
|
318
include/uuid.h
318
include/uuid.h
@ -11,6 +11,7 @@
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <assert.h>
|
||||
#include <gsl/span>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <objbase.h>
|
||||
@ -324,7 +325,7 @@ namespace uuids
|
||||
|
||||
self_type & operator++ ()
|
||||
{
|
||||
if (index >= uuid::state_size)
|
||||
if (index >= 16)
|
||||
throw std::out_of_range("Iterator cannot be incremented past the end of the data.");
|
||||
++index;
|
||||
return *this;
|
||||
@ -420,8 +421,8 @@ namespace uuids
|
||||
|
||||
self_type & operator+=(difference_type const offset)
|
||||
{
|
||||
if (static_cast<difference_type>(index) + offset < 0 ||
|
||||
static_cast<difference_type>(index) + offset > uuid::state_size)
|
||||
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;
|
||||
@ -439,187 +440,23 @@ namespace uuids
|
||||
}
|
||||
};
|
||||
|
||||
struct uuid_iterator : public uuid_const_iterator
|
||||
typedef uint8_t value_type;
|
||||
|
||||
public:
|
||||
constexpr uuid() noexcept = default;
|
||||
|
||||
explicit uuid(gsl::span<value_type, 16> bytes)
|
||||
{
|
||||
typedef uuid_iterator self_type;
|
||||
typedef uint8_t value_type;
|
||||
typedef uint8_t& reference;
|
||||
typedef uint8_t* pointer;
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
protected:
|
||||
pointer ptr = nullptr;
|
||||
size_t index = 0;
|
||||
|
||||
bool compatible(self_type const & other) const noexcept
|
||||
{
|
||||
return ptr == other.ptr;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit uuid_iterator(pointer ptr, size_t const index) :
|
||||
ptr(ptr), index(index)
|
||||
{
|
||||
}
|
||||
|
||||
uuid_iterator(uuid_iterator const & o) = default;
|
||||
uuid_iterator& operator=(uuid_iterator const & o) = default;
|
||||
~uuid_iterator() = default;
|
||||
|
||||
self_type & operator++ ()
|
||||
{
|
||||
if (index >= uuid::state_size)
|
||||
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_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 > uuid::state_size)
|
||||
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 & operator[](difference_type const offset)
|
||||
{
|
||||
return (*(*this + offset));
|
||||
}
|
||||
|
||||
value_type const & operator[](difference_type const offset) const
|
||||
{
|
||||
return (*(*this + offset));
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
typedef uint8_t value_type;
|
||||
typedef uint8_t& reference;
|
||||
typedef uint8_t const& const_reference;
|
||||
typedef uuid_iterator iterator;
|
||||
typedef uuid_const_iterator const_iterator;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
static constexpr size_t state_size = 16;
|
||||
|
||||
public:
|
||||
constexpr uuid() noexcept {}
|
||||
|
||||
std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data));
|
||||
}
|
||||
|
||||
template<typename ForwardIterator>
|
||||
explicit uuid(ForwardIterator first, ForwardIterator last)
|
||||
{
|
||||
if (std::distance(first, last) == 16)
|
||||
std::copy(first, last, std::begin(data));
|
||||
}
|
||||
|
||||
explicit uuid(std::string_view str)
|
||||
{
|
||||
create(str.data(), str.size());
|
||||
}
|
||||
|
||||
explicit uuid(std::wstring_view str)
|
||||
{
|
||||
create(str.data(), str.size());
|
||||
}
|
||||
|
||||
|
||||
constexpr uuid_variant variant() const noexcept
|
||||
{
|
||||
if ((data[8] & 0x80) == 0x00)
|
||||
@ -648,7 +485,7 @@ namespace uuids
|
||||
return uuid_version::none;
|
||||
}
|
||||
|
||||
constexpr std::size_t size() const noexcept { return state_size; }
|
||||
constexpr std::size_t size() const noexcept { return 16; }
|
||||
|
||||
constexpr bool is_nil() const noexcept
|
||||
{
|
||||
@ -661,53 +498,40 @@ namespace uuids
|
||||
data.swap(other.data);
|
||||
}
|
||||
|
||||
iterator begin() noexcept { return uuid_iterator(&data[0], 0); }
|
||||
const_iterator begin() const noexcept { return uuid_const_iterator(&data[0], 0); }
|
||||
iterator end() noexcept { return uuid_iterator(&data[0], state_size); }
|
||||
const_iterator end() const noexcept { return uuid_const_iterator(&data[0], state_size); }
|
||||
uuid_const_iterator begin() const noexcept { return uuid_const_iterator(&data[0], 0); }
|
||||
uuid_const_iterator end() const noexcept { return uuid_const_iterator(&data[0], 16); }
|
||||
|
||||
inline gsl::span<std::byte, 16> as_bytes()
|
||||
{
|
||||
return gsl::span<std::byte, 16>(reinterpret_cast<std::byte*>(data.data()), 16);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
private:
|
||||
std::array<uint8_t, 16> data{ { 0 } };
|
||||
std::array<value_type, 16> data{ { 0 } };
|
||||
|
||||
friend bool operator==(uuid const & lhs, uuid const & rhs) noexcept;
|
||||
friend bool operator<(uuid const & lhs, uuid const & rhs) noexcept;
|
||||
|
||||
template <class Elem, class Traits>
|
||||
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
|
||||
|
||||
template <typename TChar>
|
||||
void create(TChar const * const str, size_t const size)
|
||||
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
|
||||
|
||||
//friend gsl::span<std::byte, 16> as_bytes(uuid id);
|
||||
};
|
||||
|
||||
struct uuid_error : public std::runtime_error
|
||||
{
|
||||
explicit uuid_error(std::string_view message)
|
||||
: std::runtime_error(message.data())
|
||||
{
|
||||
TChar digit = 0;
|
||||
bool firstdigit = true;
|
||||
size_t index = 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
if (str[i] == static_cast<TChar>('-')) continue;
|
||||
|
||||
if (index >= 16 || !detail::is_hex(str[i]))
|
||||
{
|
||||
std::fill(std::begin(data), std::end(data), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstdigit)
|
||||
{
|
||||
digit = str[i];
|
||||
firstdigit = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
data[index++] = detail::hexpair2char(digit, str[i]);
|
||||
firstdigit = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 16)
|
||||
{
|
||||
std::fill(std::begin(data), std::end(data), 0);
|
||||
}
|
||||
explicit uuid_error(char const * message)
|
||||
: std::runtime_error(message)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@ -752,6 +576,62 @@ namespace uuids
|
||||
<< std::setw(2) << (int)id.data[15];
|
||||
}
|
||||
|
||||
template <typename TChar>
|
||||
inline uuid from_string(TChar const * const str, size_t const size)
|
||||
{
|
||||
TChar digit = 0;
|
||||
bool firstDigit = true;
|
||||
int hasBraces = 0;
|
||||
size_t index = 0;
|
||||
std::array<uint8_t, 16> data{ { 0 } };
|
||||
|
||||
if(str == nullptr || size == 0)
|
||||
throw uuid_error{ "Wrong uuid format" };
|
||||
|
||||
if (str[0] == static_cast<TChar>('{'))
|
||||
hasBraces = 1;
|
||||
if(hasBraces && str[size-1] != static_cast<TChar>('}'))
|
||||
throw uuid_error{ "Wrong uuid format" };
|
||||
|
||||
for (size_t i = hasBraces; i < size - hasBraces; ++i)
|
||||
{
|
||||
if (str[i] == static_cast<TChar>('-')) continue;
|
||||
|
||||
if (index >= 16 || !detail::is_hex(str[i]))
|
||||
{
|
||||
throw uuid_error{"Wrong uuid format"};
|
||||
}
|
||||
|
||||
if (firstDigit)
|
||||
{
|
||||
digit = str[i];
|
||||
firstDigit = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
data[index++] = detail::hexpair2char(digit, str[i]);
|
||||
firstDigit = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 16)
|
||||
{
|
||||
throw uuid_error{"Wrong uuid format"};
|
||||
}
|
||||
|
||||
return uuid{std::cbegin(data), std::cend(data)};
|
||||
}
|
||||
|
||||
inline uuid from_string(std::string_view str)
|
||||
{
|
||||
return from_string(str.data(), str.size());
|
||||
}
|
||||
|
||||
inline uuid from_string(std::wstring_view str)
|
||||
{
|
||||
return from_string(str.data(), str.size());
|
||||
}
|
||||
|
||||
inline std::string to_string(uuid const & id)
|
||||
{
|
||||
std::stringstream sstr;
|
||||
@ -935,9 +815,9 @@ namespace uuids
|
||||
void reset()
|
||||
{
|
||||
hasher.reset();
|
||||
uint8_t bytes[uuid::state_size];
|
||||
uint8_t bytes[16];
|
||||
std::copy(std::begin(nsuuid), std::end(nsuuid), bytes);
|
||||
hasher.process_bytes(bytes, uuid::state_size);
|
||||
hasher.process_bytes(bytes, 16);
|
||||
}
|
||||
|
||||
template <typename char_type,
|
||||
@ -972,7 +852,7 @@ namespace uuids
|
||||
digest[6] &= 0x5F;
|
||||
digest[6] |= 0x50;
|
||||
|
||||
return uuid{ digest, digest + uuid::state_size };
|
||||
return uuid{ digest, digest + 16 };
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -190,7 +190,7 @@ TEST_CASE("Test basic random generator (conversion ctor w/ ref) w/ ranlux48_base
|
||||
|
||||
TEST_CASE("Test name generator", "[gen][name]")
|
||||
{
|
||||
uuids::uuid_name_generator dgen(uuids::uuid{ "47183823-2574-4bfd-b411-99ed177d3e43" });
|
||||
uuids::uuid_name_generator dgen(uuids::from_string("47183823-2574-4bfd-b411-99ed177d3e43"));
|
||||
auto id1 = dgen("john");
|
||||
REQUIRE(!id1.is_nil());
|
||||
REQUIRE(id1.size() == 16);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
using namespace uuids;
|
||||
|
||||
@ -14,32 +15,78 @@ TEST_CASE("Test default constructor", "[ctors]")
|
||||
REQUIRE(empty.size() == 16);
|
||||
}
|
||||
|
||||
TEST_CASE("Test string_view constructor", "[ctors]")
|
||||
TEST_CASE("Test from_string(string_view)", "[parse]")
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
|
||||
{
|
||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||
uuid guid(str);
|
||||
auto guid = uuids::from_string(str);
|
||||
REQUIRE(uuids::to_string(guid) == str);
|
||||
}
|
||||
|
||||
{
|
||||
uuid guid("47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43}"s;
|
||||
auto guid = uuids::from_string(str);
|
||||
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
}
|
||||
|
||||
{
|
||||
auto guid = uuids::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
REQUIRE(uuids::to_wstring(guid) == L"47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "4718382325744bfdb41199ed177d3e43"s;
|
||||
REQUIRE_NOTHROW(uuids::from_string(str));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Test wstring_view constructor", "[ctors]")
|
||||
TEST_CASE("Test from_string(wstring_view)", "[parse]")
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
|
||||
auto str = L"47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||
uuid guid(str);
|
||||
auto guid = uuids::from_string(str);
|
||||
REQUIRE(uuids::to_wstring(guid) == str);
|
||||
}
|
||||
|
||||
TEST_CASE("Test from_string invalid format", "[parse]")
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
|
||||
{
|
||||
auto str = ""s;
|
||||
REQUIRE_THROWS_AS(uuids::from_string(str), uuids::uuid_error);
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "{}"s;
|
||||
REQUIRE_THROWS_AS(uuids::from_string(str), uuids::uuid_error);
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e4"s;
|
||||
REQUIRE_THROWS_AS(uuids::from_string(str), uuids::uuid_error);
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e430"s;
|
||||
REQUIRE_THROWS_AS(uuids::from_string(str), uuids::uuid_error);
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "{47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||
REQUIRE_THROWS_AS(uuids::from_string(str), uuids::uuid_error);
|
||||
}
|
||||
|
||||
{
|
||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e43}"s;
|
||||
REQUIRE_THROWS_AS(uuids::from_string(str), uuids::uuid_error);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Test iterators constructor", "[ctors]")
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
@ -103,7 +150,7 @@ TEST_CASE("Test hashing", "[ops]")
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s;
|
||||
auto guid = uuid{ str };
|
||||
auto guid = uuids::from_string(str);
|
||||
|
||||
auto h1 = std::hash<std::string>{};
|
||||
auto h2 = std::hash<uuid>{};
|
||||
@ -160,11 +207,7 @@ TEST_CASE("Test iterators", "[iter]")
|
||||
} };
|
||||
|
||||
{
|
||||
uuid guid;
|
||||
REQUIRE(guid.is_nil());
|
||||
|
||||
std::copy(std::cbegin(arr), std::cend(arr), std::begin(guid));
|
||||
REQUIRE(!guid.is_nil());
|
||||
uuid guid(arr);
|
||||
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
|
||||
size_t i = 0;
|
||||
@ -175,7 +218,7 @@ TEST_CASE("Test iterators", "[iter]")
|
||||
}
|
||||
|
||||
{
|
||||
const uuid guid("47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
const uuid guid = uuids::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
REQUIRE(!guid.is_nil());
|
||||
REQUIRE(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
|
||||
@ -194,4 +237,55 @@ TEST_CASE("Test constexpr", "[const]")
|
||||
constexpr size_t size = empty.size();
|
||||
constexpr uuid_variant variant = empty.variant();
|
||||
constexpr uuid_version version = empty.version();
|
||||
}
|
||||
|
||||
TEST_CASE("Test size", "[operators]")
|
||||
{
|
||||
REQUIRE(sizeof(uuid) == 16);
|
||||
}
|
||||
|
||||
TEST_CASE("Test assignment", "[ops]")
|
||||
{
|
||||
auto id1 = uuids::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
auto id2 = id1;
|
||||
REQUIRE(id1 == id2);
|
||||
|
||||
id1 = uuids::from_string("{fea43102-064f-4444-adc2-02cec42623f8}");
|
||||
REQUIRE(id1 != id2);
|
||||
|
||||
auto id3 = std::move(id2);
|
||||
REQUIRE(uuids::to_string(id3) == "47183823-2574-4bfd-b411-99ed177d3e43");
|
||||
}
|
||||
|
||||
TEST_CASE("Test trivial", "[trivial]")
|
||||
{
|
||||
REQUIRE(std::is_trivially_copyable_v<uuids::uuid>);
|
||||
}
|
||||
|
||||
TEST_CASE("Test as_bytes", "[ops]")
|
||||
{
|
||||
std::array<uuids::uuid::value_type, 16> arr{ {
|
||||
0x47, 0x18, 0x38, 0x23,
|
||||
0x25, 0x74,
|
||||
0x4b, 0xfd,
|
||||
0xb4, 0x11,
|
||||
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43
|
||||
} };
|
||||
|
||||
{
|
||||
uuids::uuid id{ arr };
|
||||
REQUIRE(!id.is_nil());
|
||||
|
||||
auto view = id.as_bytes();
|
||||
REQUIRE(memcmp(view.data(), arr.data(), arr.size()) == 0);
|
||||
}
|
||||
|
||||
{
|
||||
const uuids::uuid id{ arr };
|
||||
REQUIRE(!id.is_nil());
|
||||
|
||||
auto view = id.as_bytes();
|
||||
REQUIRE(memcmp(view.data(), arr.data(), arr.size()) == 0);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user