stduuid/P0959.md

651 lines
26 KiB
Markdown
Raw Normal View History

| ___ | ___ |
2018-02-12 07:40:40 +00:00
| --- | --- |
| Doc. No.: | P0959R1 |
| Date: | 2018-09-05 |
2018-02-12 07:40:40 +00:00
| Reply to: | Marius Bancila |
| Audience: | Library WG |
| Title: | A Proposal for a Universally Unique Identifier Library |
2017-12-18 13:17:45 +00:00
# A Proposal for a Universally Unique Identifier Library
## I. Revision History
### 1.1 P0959R0
Original UUID library paper with motivation, specification, and examples.
### 1.2 P0959R1
Revised with feedback from the LWG and the community.
2018-06-29 06:54:51 +00:00
* Removed string constructors and replaced with an overloaded static member function `from_string()`.
* Parsing strings to `uuid` throws exception `uuid_error` instead of creating a nil uuid when the operation fails.
2018-06-27 13:25:19 +00:00
* {} included in the supported format for string parsing, i.e. `"{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"`.
* Removed `state_size`.
* Rename member function `nil()` to `is_nil()`.
* The default constructor is defaulted.
2018-06-27 13:22:00 +00:00
* Added a conversion construct from `std::span<std::byte, 16>`.
2018-06-29 06:54:51 +00:00
* Added the member function `as_bytes()` to convert the `uuid` into a view of its underlying bytes.
* Constructing a `uuid` from a range with a size other than 16 is undefined behaviour.
* Replaced operators '==', '!=' and `<` with the three-way operator `<=>`
* Removed mutable iterators (but preserved the constant iterators).
* Removed typedefs and others container-like parts.
2018-06-27 13:22:00 +00:00
* Defined the correlation between the internal UUID bytes and the string representation.
* Added UUID layout and byte order specification from the RFC 4122 document.
2018-09-05 09:51:53 +00:00
* Added section on alternative ordering design
2018-06-29 07:33:08 +00:00
* Most functions are constexpr.
* Replaced typedefs with using statements.
## II. Motivation
2017-12-18 13:17:45 +00:00
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*.
2017-12-18 14:42:08 +00:00
UUIDs are 128-bit numbers that are for most practical purposes unique, without depending on a central registration authority for ensuring their uniqueness. Although the probability of UUID duplication exists, it is negligible. According to Wikipedia, "*for there to be a one in a billion chance of duplication, 103 trillion version 4 UUIDs must be generated.*" UUID is an Internet Engineering Task Force standard described by RFC 4122.
2017-12-18 13:17:45 +00:00
2018-02-12 07:20:37 +00:00
The library proposed on this paper is a light one: it enables developers to generate random and name-based UUIDs, serialize and deserialize UUIDs to and from strings, validate UUIDs and other common operations.
2017-12-18 13:17:45 +00:00
## III. Impact On the Standard
2017-12-18 13:17:45 +00:00
2018-02-12 07:20:37 +00:00
This proposal is a pure library extension. It does not require changes to any standard classes, functions or headers. It does not require any changes in the core language, and it has been implemented in standard C++ as per ISO/IEC 14882:2017. The implementation is available at https://github.com/mariusbancila/stduuid.
2017-12-18 13:17:45 +00:00
## IV. Design Decisions
2017-12-18 13:17:45 +00:00
2017-12-19 10:22:28 +00:00
The proposed library, that should be available in a new header called `<uuid>` in the namespace `std`, provides:
2017-12-18 14:12:48 +00:00
* 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
2018-01-31 07:30:39 +00:00
* function objects that generate UUIDs, called generators: `basic_uuid_random_generator<T>`, `uuid_random_generator`, `uuid_name_generator`
* conversion functions from strings `from_string()` and to strings `std::to_string()` \ `std::to_wstring()`, as well as an overloaded `operator<<` for `std::basic_ostream`
2018-01-31 07:30:39 +00:00
* `std::swap()` overload for `uuid`
2017-12-18 14:12:48 +00:00
* `std::hash<>` specialization for `uuid`
2017-12-18 13:17:45 +00:00
2017-12-18 14:12:48 +00:00
### Default constructor
Creates a nil UUID that has all the bits set to 0 (i.e. `00000000-0000-0000-0000-000000000000`).
2017-12-18 14:12:48 +00:00
2018-02-28 19:48:04 +00:00
```cpp
2017-12-18 14:12:48 +00:00
uuid empty;
auto empty = uuid{};
```
2017-12-19 10:22:28 +00:00
### Iterators constructors
2017-12-18 14:12:48 +00:00
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.
2017-12-18 14:12:48 +00:00
2018-02-28 19:48:04 +00:00
```cpp
std::array<uuid::value_type, 16> arr{{
0x47, 0x18, 0x38, 0x23,
0x25, 0x74,
0x4b, 0xfd,
0xb4, 0x11,
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43
}};
2018-01-31 07:04:26 +00:00
uuid id(std::begin(arr), std::end(arr));
2017-12-18 14:12:48 +00:00
```
2018-02-28 19:48:04 +00:00
```cpp
uuid::value_type arr[16] = {
0x47, 0x18, 0x38, 0x23,
0x25, 0x74,
0x4b, 0xfd,
0xb4, 0x11,
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 };
2018-01-31 07:04:26 +00:00
uuid id(std::begin(arr), std::end(arr));
2017-12-18 14:12:48 +00:00
```
2017-12-18 13:17:45 +00:00
### Span constructor
The conversion constructor that takes a `std::span` and constructs a `uuid` from a contiguous sequence of 16 bytes.
```cpp
std::array<uuid::value_type, 16> arr{ {
0x47, 0x18, 0x38, 0x23,
0x25, 0x74,
0x4b, 0xfd,
0xb4, 0x11,
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43
} };
std::span<uuid::value_type, 16> data(arr);
uuid id{ data };
assert(to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43");
```
2018-01-23 09:23:10 +00:00
### Size
2017-12-18 14:42:08 +00:00
Member function `size()` indicates the number of bytes in the UUID. Because this is a fixed size structure this function always returns 16.
2018-02-28 19:48:04 +00:00
```cpp
2018-01-23 09:23:10 +00:00
uuid id;
assert(id.size() == 16);
```
2017-12-18 14:42:08 +00:00
2018-01-23 09:23:10 +00:00
### Nil
2017-12-18 14:42:08 +00:00
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}`.
2018-02-28 19:48:04 +00:00
```cpp
2017-12-18 14:42:08 +00:00
uuid id;
2018-05-14 13:42:38 +00:00
assert(id.is_nil());
2018-06-29 06:54:51 +00:00
uuid id = uuid::from_string("00000000-0000-0000-0000-000000000000");
assert(id.is_nil());
2017-12-18 14:42:08 +00:00
```
2017-12-18 15:31:25 +00:00
### 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.
2017-12-18 15:31:25 +00:00
2018-02-28 19:48:04 +00:00
```cpp
std::array<uuid::value_type, 16> arr{{
0x47, 0x18, 0x38, 0x23,
0x25, 0x74,
0x4b, 0xfd,
0xb4, 0x11,
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43
}};
2017-12-18 15:31:25 +00:00
uuid id(std::begin(arr), std::end(arr));
assert(to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43");
2017-12-18 15:31:25 +00:00
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.
2017-12-18 15:31:25 +00:00
### `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`.
2017-12-18 15:31:25 +00:00
2018-02-28 19:48:04 +00:00
```cpp
2018-11-02 17:45:39 +00:00
uuid id = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
2017-12-19 10:22:28 +00:00
assert(id.version() == uuid_version::random_number_based);
assert(id.variant() == uuid_variant::rfc);
2017-12-18 15:31:25 +00:00
```
### Equality and ordering
Although it does not make sense to check whether a UUID is less (or less or equal) then another UUID, the overloading of this operator for `uuid` is necessary in order to be able to store `uuid` values in containers such as `std::set` that by default use `operator <` to compare keys. Because operators `==` and `!=` are needed for checking whether two UUIDs are the same (a basic operation for an identifier type) the three-way comparison operator `<=>` is defined so that all comparison operators are provided.
```cpp
std::array<uuid::value_type, 16> arr{ {
0x47, 0x18, 0x38, 0x23,
0x25, 0x74,
0x4b, 0xfd,
0xb4, 0x11,
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43
} };
uuid id1{ std::span<uuid::value_type, 16>{arr} };
2018-11-02 21:13:56 +00:00
uuid id2 = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
assert(id1 == id2);
std::set<std::uuid> ids{
uuid{},
2018-11-02 17:45:39 +00:00
uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43")
};
assert(ids.size() == 2);
assert(ids.find(uuid{}) != ids.end());
```
### Span view
Member function `as_bytes()` converts the `uuid` into a view of its underlying bytes.
```cpp
std::array<uuids::uuid::value_type, 16> arr{ {
0x47, 0x18, 0x38, 0x23,
0x25, 0x74,
0x4b, 0xfd,
0xb4, 0x11,
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43
} };
const uuid id{ arr };
assert(!id.is_nil());
auto view = id.as_bytes();
assert(memcmp(view.data(), arr.data(), arr.size()) == 0);
```
2017-12-18 15:31:25 +00:00
### Swapping
2018-01-31 07:26:03 +00:00
Both member and non-member `swap()` functions are available to perform the swapping of `uuid` values.
2017-12-18 15:31:25 +00:00
2018-02-28 19:48:04 +00:00
```cpp
2017-12-18 15:31:25 +00:00
uuid empty;
2018-11-02 17:45:39 +00:00
uuid id = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
2017-12-18 15:31:25 +00:00
2018-05-14 13:42:38 +00:00
assert(empty.is_nil());
assert(!id.is_nil());
2017-12-18 15:31:25 +00:00
std::swap(empty, id);
2018-05-14 13:42:38 +00:00
assert(!empty.is_nil());
assert(id.is_nil());
2017-12-18 15:31:25 +00:00
empty.swap(id);
2018-05-14 13:42:38 +00:00
assert(empty.is_nil());
assert(!id.is_nil());
2017-12-18 15:31:25 +00:00
```
### String parsing
2018-06-29 06:54:51 +00:00
Static overloaded member function `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.
```cpp
2018-06-29 06:54:51 +00:00
auto id1 = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
auto id2 = uuid::from_string(L"{47183823-2574-4bfd-b411-99ed177d3e43}");
```
The order of the bytes in the input string reflects directly into the internal representation of the UUID. That is, for an input string in the form `"aabbccdd-eeff-gghh-iijj-kkllmmnnoopp"` or `"{aabbccdd-eeff-gghh-iijj-kkllmmnnoopp}"` the internal byte order of the resulted UUID is `aa,bb,cc,dd,ee,ff,gg,hh,ii,jj,kk,ll,mm,nn,oo,pp`.
### String conversion
Non-member functions `to_string()` and `to_wstring()` return a string with the UUID formatted to the canonical textual representation `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`, where `x` is a lower case hexadecimal digit.
2018-02-28 19:48:04 +00:00
```cpp
2018-11-02 17:45:39 +00:00
uuid id = uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43");
2018-01-23 09:11:14 +00:00
assert(to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43");
assert(to_wstring(id) == 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"`.
2017-12-18 15:31:25 +00:00
### Hashing
A `std::hash<>` specialization for `uuid` is provided in order to enable the use of `uuid`s in associative unordered containers such as `std::unordered_set`.
2018-02-28 19:48:04 +00:00
```cpp
2017-12-19 10:22:28 +00:00
std::unordered_set<uuid> ids{
2017-12-18 15:31:25 +00:00
uuid{},
2018-11-02 17:45:39 +00:00
uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43"),
2017-12-18 15:31:25 +00:00
};
assert(ids.size() == 2);
2017-12-18 15:31:25 +00:00
assert(ids.find(uuid{}) != ids.end());
```
### Generating new uuids
2018-01-22 08:53:10 +00:00
Several function objects, called generators, are provided in order to create different versions of UUIDs.
2017-12-18 15:31:25 +00:00
2018-01-22 08:53:10 +00:00
Examples for generating new UUIDs with the `basic_uuid_random_generator` class:
2018-02-28 19:48:04 +00:00
```cpp
2018-01-22 08:53:10 +00:00
{
basic_uuid_random_generator<std::mt19937> dgen;
auto id1 = dgen();
2018-05-14 13:42:38 +00:00
assert(!id1.is_nil());
2018-01-22 08:53:10 +00:00
assert(id1.size() == 16);
assert(id1.version() == uuid_version::random_number_based);
assert(id1.variant() == uuid_variant::rfc);
}
{
basic_uuid_random_generator<std::ranlux48_base> dgen;
auto id1 = dgen();
2018-05-14 13:42:38 +00:00
assert(!id1.is_nil());
2018-01-22 08:53:10 +00:00
assert(id1.size() == 16);
assert(id1.version() == uuid_version::random_number_based);
assert(id1.variant() == uuid_variant::rfc);
}
{
std::random_device rd;
std::ranlux48_base generator(rd());
basic_uuid_random_generator<std::ranlux48_base> dgen(&generator);
auto id1 = dgen();
2018-05-14 13:42:38 +00:00
assert(!id1.is_nil());
2018-01-22 08:53:10 +00:00
assert(id1.size() == 16);
assert(id1.version() == uuid_version::random_number_based);
assert(id1.variant() == uuid_variant::rfc);
}
{
std::random_device rd;
auto generator = std::make_unique<std::mt19937>(rd());
basic_uuid_random_generator<std::mt19937> dgen(generator.get());
auto id1 = dgen();
2018-05-14 13:42:38 +00:00
assert(!id1.is_nil());
2018-01-22 08:53:10 +00:00
assert(id1.size() == 16);
assert(id1.version() == uuid_version::random_number_based);
assert(id1.variant() == uuid_variant::rfc);
}
```
Examples for generating new UUIDs with the `uuid_random_generator` type alias:
2018-02-28 19:48:04 +00:00
```cpp
2018-01-22 08:53:10 +00:00
uuid_random_generator dgen;
auto id1 = dgen();
2018-05-14 13:42:38 +00:00
assert(!id1.is_nil());
2018-01-22 08:53:10 +00:00
assert(id1.size() == 16);
assert(id1.version() == uuid_version::random_number_based);
assert(id1.variant() == uuid_variant::rfc);
```
Examples for genearting new UUIDs with the `uuid_name_generator` class:
2018-02-28 19:48:04 +00:00
```cpp
2018-11-02 21:13:56 +00:00
uuid_name_generator dgen(uuid::from_string("415ccc2b-f5cf-4ec1-b544-45132a518cc8"));
2018-01-22 08:53:10 +00:00
auto id1 = dgen("john");
2018-05-14 13:42:38 +00:00
assert(!id1.is_nil());
2018-01-22 08:53:10 +00:00
assert(id1.size() == 16);
assert(id1.version() == uuid_version::name_based_sha1);
assert(id1.variant() == uuid_variant::rfc);
auto id2 = dgen("jane");
2018-05-14 13:42:38 +00:00
assert(!id2.is_nil());
2018-01-22 08:53:10 +00:00
assert(id2.size() == 16);
assert(id2.version() == uuid_version::name_based_sha1);
assert(id2.variant() == uuid_variant::rfc);
auto id3 = dgen("jane");
2018-05-14 13:42:38 +00:00
assert(!id3.is_nil());
2018-01-22 08:53:10 +00:00
assert(id3.size() == 16);
assert(id3.version() == uuid_version::name_based_sha1);
assert(id3.variant() == uuid_variant::rfc);
auto id4 = dgen(L"jane");
2018-05-14 13:42:38 +00:00
assert(!id4.is_nil());
2018-01-22 08:53:10 +00:00
assert(id4.size() == 16);
assert(id4.version() == uuid_version::name_based_sha1);
assert(id4.variant() == uuid_variant::rfc);
assert(id1 != id2);
assert(id2 == id3);
assert(id3 != id4);
```
2017-12-18 15:31:25 +00:00
## V. Technical Specifications
2017-12-18 13:17:45 +00:00
2017-12-18 15:31:25 +00:00
### Header
Add a new header called `<uuid>`.
### `uuid_variant` enum
2018-02-28 19:48:04 +00:00
```cpp
2017-12-19 10:22:28 +00:00
namespace std {
2017-12-18 15:31:25 +00:00
enum class uuid_variant
{
ncs,
rfc,
microsoft,
future
};
}
```
### `uuid_version` enum
2018-02-28 19:48:04 +00:00
```cpp
2017-12-19 10:22:28 +00:00
namespace std {
2017-12-18 15:31:25 +00:00
enum class uuid_version
{
none = 0,
time_based = 1,
dce_security = 2,
name_based_md5 = 3,
random_number_based = 4,
name_based_sha1 = 5
};
}
```
### `uuid_error` class
2018-02-28 19:48:04 +00:00
```cpp
2017-12-19 10:22:28 +00:00
namespace std {
struct uuid_error : public std::runtime_error
{
explicit uuid_error(std::string_view message);
explicit uuid_error(char const * message);
};
}
```
2017-12-19 10:22:28 +00:00
### `uuid` class
2017-12-19 10:22:28 +00:00
```cpp
namespace std {
struct uuid
{
2018-06-29 06:54:51 +00:00
using value_type = uint8_t;
using const_iterator = /*implementation-defined*/;
constexpr uuid() noexcept = default;
2018-06-29 06:54:51 +00:00
constexpr explicit uuid(std::span<value_type, 16> bytes);
template<typename ForwardIterator>
2018-06-29 06:54:51 +00:00
constexpr explicit uuid(ForwardIterator first, ForwardIterator last);
constexpr uuid_variant variant() const noexcept;
constexpr uuid_version version() const noexcept;
constexpr std::size_t size() const noexcept;
constexpr bool is_nil() const noexcept;
2018-06-29 06:54:51 +00:00
constexpr void swap(uuid & other) noexcept;
2018-06-29 06:54:51 +00:00
constexpr const_iterator begin() const noexcept;
constexpr const_iterator end() const noexcept;
2018-06-29 06:54:51 +00:00
constexpr std::span<std::byte const, 16> as_bytes() const;
constexpr std::strong_equality operator<=>(uuid const&) const noexcept = default;
2018-06-29 06:54:51 +00:00
template <typename TChar>
static uuid from_string(TChar const * const str, size_t const size);
static uuid from_string(std::string_view str);
static uuid from_string(std::wstring_view str);
private:
template <class Elem, class Traits>
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
};
}
2017-12-18 15:31:25 +00:00
```
### non-member functions
2018-02-28 19:48:04 +00:00
```cpp
2017-12-19 10:22:28 +00:00
namespace std {
2018-06-29 06:54:51 +00:00
inline constexpr void swap(uuid & lhs, uuid & rhs);
2018-01-31 07:39:08 +00:00
2017-12-18 15:31:25 +00:00
template <class Elem, class Traits>
std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
inline std::string to_string(uuid const & id);
2018-06-29 06:54:51 +00:00
inline std::wstring to_wstring(uuid const & id);
2017-12-18 15:31:25 +00:00
}
```
2018-01-22 08:53:10 +00:00
### 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.
2018-02-28 19:48:04 +00:00
```cpp
namespace std {
template <typename UniformRandomNumberGenerator>
class basic_uuid_random_generator
{
public:
2018-06-29 07:33:08 +00:00
using result_type = uuid;
2018-01-22 08:53:10 +00:00
basic_uuid_random_generator();
explicit basic_uuid_random_generator(UniformRandomNumberGenerator& gen);
explicit basic_uuid_random_generator(UniformRandomNumberGenerator* gen);
2018-01-22 08:53:10 +00:00
uuid operator()();
};
}
2018-01-22 08:53:10 +00:00
```
2018-02-19 15:08:50 +00:00
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.
2018-02-28 19:48:04 +00:00
```cpp
namespace std {
using uuid_random_generator = basic_uuid_random_generator<std::mt19937>;
}
2018-01-22 08:53:10 +00:00
```
2018-01-22 08:58:04 +00:00
`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`.
2018-02-28 19:48:04 +00:00
```cpp
namespace std {
class uuid_name_generator
{
public:
2018-06-29 07:33:08 +00:00
using result_type = uuid;
2018-01-22 08:53:10 +00:00
explicit uuid_name_generator(uuid const& namespace_uuid) noexcept;
uuid operator()(std::string_view name);
uuid operator()(std::wstring_view name);
};
}
2018-01-22 08:53:10 +00:00
```
2017-12-18 15:31:25 +00:00
### Specialization
2018-01-31 07:26:03 +00:00
The template specializations of `std::hash` for the `uuid` class allow users to obtain hashes of UUIDs.
2018-02-28 19:48:04 +00:00
```cpp
2017-12-19 10:22:28 +00:00
namespace std {
2017-12-18 15:31:25 +00:00
template <>
2017-12-19 10:22:28 +00:00
struct hash<uuid>
2017-12-18 15:31:25 +00:00
{
2018-06-29 07:33:08 +00:00
using argument_type = uuid;
using result_type = std::size_t;
2017-12-18 15:31:25 +00:00
result_type operator()(argument_type const &uuid) const;
};
}
```
## VI. Alternative ordering design
The comparison of UUIDs is not an operation that makes logical sense but it is required for using UUIDs as keys for containers such as `std::set` or `std::map`. The technical specification of the `uuid` class given in the previous section features the three-way operator `<=>` as member of the class. The C++ community, however, is divided on this particular aspect (with long discussions happening in the [ISO C++ proposals forum](https://groups.google.com/a/isocpp.org/forum/#!forum/std-proposals)) between those that want convenience and those that want rigour. Although the RFC 4122 document, as quoted in the next section, does specify rules for lexical equivalence, not everybody is happy with the definition of comparison operator `<`.
The alternative put forward is to define non-member ordering functors. In this case, the library can define the following functors:
* `uuid_lexicographical_order` performs a lexicographic comparison (can provide compatibility with other systems)
* `uuid_fast_order` performs a memberwise comparison for efficiency.
These could be used as the comparison function for containers such as `std::set` or `std::map`:
```cpp
std::map<std::uuid, Value, std::uuid_fast_order> map;
```
```cpp
template<typename Value, typename Allocator = std::allocator<T>>
using uuid_map = std::map<std::uuid, Value, std::uuid_lexicographical_order, Allocator>;
```
In this case, the `uuid` class should be defined as follows:
```cpp
namespace std {
struct uuid
{
using value_type = uint8_t;
using const_iterator = /*implementation-defined*/;
constexpr uuid() noexcept = default;
constexpr explicit uuid(std::span<value_type, 16> bytes);
template<typename ForwardIterator>
constexpr explicit uuid(ForwardIterator first, ForwardIterator last);
constexpr uuid_variant variant() const noexcept;
constexpr uuid_version version() const noexcept;
constexpr std::size_t size() const noexcept;
constexpr bool is_nil() const noexcept;
constexpr void swap(uuid & other) noexcept;
constexpr const_iterator begin() const noexcept;
constexpr const_iterator end() const noexcept;
constexpr std::span<std::byte const, 16> as_bytes() const;
template <typename TChar>
static uuid from_string(TChar const * const str, size_t const size);
static uuid from_string(std::string_view str);
static uuid from_string(std::wstring_view str);
private:
template <class Elem, class Traits>
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
};
}
```
In addition, the following must be added to the `<uuid>` header:
```cpp
namespace std {
struct uuid_lexicographical_order {
constexpr bool operator()(uuid const&, uuid const&) const;
};
struct uuid_fast_order {
constexpr bool operator()(uuid const&, uuid const&) const;
};
}
```
Should users require other types of comparison they can provide their own implementation and use them instead of the standard ones.
## VII. UUID format specification
The content of this section is copied from the RFC 4122 document that describes the UUID standard.
The UUID format is 16 octets; some bits of the eight octet variant field determine the layout of the UUID. That is, the interpretation of all other bits in the UUID depends on the setting of the bits in the variant field. The variant field consists of a variable number of the most significant bits of octet 8 of the UUID. The following table lists the contents of the variant field, where the letter "x" indicates a "don't-care" value.
| Msb0 | Msb1 | Msb2 | Description |
| ---- | ---- | ---- | ----------- |
| 0 | x | x | Reserved, NCS backward compatibility. |
| 1 | 0 | x | The variant specified in this document. |
| 1 | 1 | 0 | Reserved, Microsoft Corporation backward compatibility. |
| 1 | 1 | 1 | Reserved for future definition. |
Only UUIDs of the variant with the bit pattern 10x are considered in this document. All the other references to UUIDs in this document refer to this variant. For simplicity, we will call this the RFC variant UUID.
The UUID record definition is defined only in terms of fields that are integral numbers of octets. The fields are presented with the most significant one first.
| Field | Data Type | Octet number | Note |
| ----- | --------- | ------------ | ---- |
| `time_low` | unsigned 32 bit integer | 0-3 | The low field of the timestamp |
| `time_mid` | unsigned 16 bit integer | 4-5 | The middle field of the timestamp |
| `time_hi_and_version` | unsigned 16 bit integer | 6-7 | The high field of the timestamp multiplexed with the version number |
| `clock_seq_hi_and_reserved` | unsigned 8 bit integer | 8 | The high field of the clock sequence multiplexed with the variant |
| `clock_seq_low` | unsigned 8 bit integer | 9 | The low field of the clock sequence |
| `node` | unsigned 48 bit integer | 10-15 | The spatially unique node identifier |
In the absence of explicit application or presentation protocol specification to the contrary, a UUID is encoded as a 128-bit object, as follows:
The fields are encoded as 16 octets, with the sizes and order of the fields defined above, and with each field encoded with the Most Significant Byte first (known as network byte order).
```
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_mid | time_hi_and_version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res | clk_seq_low | node (0-1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node (2-5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```
The version number is in the most significant 4 bits of the timestamp (bits 4 through 7 of the `time_hi_and_version` field). The following table lists the currently-defined versions for the RFC variant.
| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
| ---- | ---- | ---- | ---- | ------- | ----------- |
| 0 | 0 | 0 | 1 | 1 | The time-based version specified in this document. |
| 0 | 0 | 1 | 0 | 2 | DCE Security version, with embedded POSIX UIDs. |
| 0 | 0 | 1 | 1 | 3 | The name-based version specified in this document that uses MD5 hashing. |
| 0 | 1 | 0 | 0 | 4 | The randomly or pseudo-randomly generated version specified in this document. |
| 0 | 1 | 0 | 1 | 5 | The name-based version specified in this document that uses SHA-1 hashing. |
### Rules for Lexical Equivalence
Consider each field of the UUID to be an unsigned integer as shown in the table in the section above. Then, to compare a pair of UUIDs, arithmetically compare the corresponding fields from each UUID in order of significance and according to their data type. Two UUIDs are equal if and only if all the corresponding fields are equal.
As an implementation note, equality comparison can be performed on many systems by doing the appropriate byte-order canonicalization, and then treating the two UUIDs as 128-bit unsigned integers.
UUIDs, as defined in this document, can also be ordered lexicographically. For a pair of UUIDs, the first one follows the second if the most significant field in which the UUIDs differ is greater for the first UUID. The second precedes the first if the most significant field in which the UUIDs differ is greater for the second UUID.
## VIII. References
2017-12-18 13:17:45 +00:00
* [1] Universally unique identifier, https://en.wikipedia.org/wiki/Universally_unique_identifier
* [2] A Universally Unique IDentifier (UUID) URN Namespace, https://tools.ietf.org/html/rfc4122
* [3] Boost Uuid Library http://www.boost.org/doc/libs/1_65_1/libs/uuid/uuid.html
* [4] crossguid - Lightweight cross platform C++ GUID/UUID library, https://github.com/graeme-hill/crossguid