A C++17 cross-platform single-header library implementation for universally unique identifiers, simply know as either UUID or GUID (mostly on Windows). A UUID is a 128-bit number used to uniquely identify information in computer systems, such as database table keys, COM interfaces, classes and type libraries, and many others.
For information about UUID/GUIDs see:
Although the specification puts the uuid library in the std
namespace, this implementation uses the namespace uuids
for this purpose, in order to make the library usable without violating the restrictions imposed on the std
namespace. The following types and utilities are available:
Basic types:
Name | Description |
---|---|
uuid |
a class representing a UUID; this can be default constructed (a nil UUID), constructed from a range (defined by a pair of iterators), or from a span . |
uuid_variant |
a strongly type enum representing the type of a UUID |
uuid_version |
a strongly type enum representing the version of a UUID |
Generators:
Name | Description |
---|---|
basic_uuid_random_generator |
a function object that generates version 4 UUIDs using a pseudo-random number generator engine. |
uuid_random_generator |
a basic_uuid_random_generator using the Marsenne Twister engine (basic_uuid_random_generator<std::mt19937> ) |
uuid_name_generator |
a function object that generates version 5, name-based UUIDs using SHA1 hashing. |
uuid_system_generator |
a function object that generates new UUIDs using operating system resources (CoCreateGuid on Windows, uuid_generate on Linux, CFUUIDCreate on Mac) Note: This is not part of the standard proposal. |
Utilities:
Name | Description |
---|---|
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 |
---|---|
operator== and operator!= |
for UUIDs comparison for equality/inequality |
operator< |
for comparing whether one UUIDs is less than another. Although this operation does not make much logical sense, it is necessary in order to store UUIDs in a std::set. |
operator<< |
to write a UUID to an output stream using the canonical textual representation. |
to_string() |
creates a string with the canonical textual representation of a UUID. |
This library is an implementation of the proposal P0959.
As the proposal evolves based on the standard committee and the C++ community feedback, this library implementation will reflect those changes.
See the revision history of the proposal for history of changes.
The following is a list of examples for using the library:
-
Creating a nil UUID
uuid empty; assert(empty.is_nil());
-
Creating a new UUID
uuid const id = uuids::uuid_system_generator{}(); assert(!id.is_nil()); assert(id.version() == uuids::uuid_version::random_number_based); assert(id.variant() == uuids::uuid_variant::rfc);
-
Creating a new UUID with a default random generator
std::random_device rd; auto seed_data = std::array<int, std::mt19937::state_size> {}; std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); std::mt19937 generator(seq); uuid const guid = uuids::uuid_random_generator{generator}(); 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
std::random_device rd; auto seed_data = std::array<int, 6> {}; std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); std::ranlux48_base generator(seq); uuids::basic_uuid_random_generator<std::ranlux48_base> gen(&generator); uuid const id = gen(); assert(!id.is_nil()); assert(id.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
uuids::uuid_name_generator gen(uuids::uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value()); uuid const id = gen(); assert(!id.is_nil()); assert(id.version() == uuids::uuid_version::name_based_sha1); assert(id.variant() == uuids::uuid_variant::rfc);
-
Create a UUID from a string
using namespace std::string_literals; auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s; auto id = uuids::uuid::from_string(str); assert(id.has_value()); assert(uuids::to_string(id.value()) == str); // or uuid id = uuids::uuid::from_string(L"{47183823-2574-4bfd-b411-99ed177d3e43}"s).value(); assert(uuids::to_string<wchar_t>(id.value()) == str);
-
Creating a UUID from a sequence of 16 bytes
std::array<uuids::uuid::value_type, 16> arr{{ 0x47, 0x18, 0x38, 0x23, 0x25, 0x74, 0x4b, 0xfd, 0xb4, 0x11, 0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43}}; uuid id(arr); assert(uuids::to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43"); // or uuids::uuid::value_type arr[16] = { 0x47, 0x18, 0x38, 0x23, 0x25, 0x74, 0x4b, 0xfd, 0xb4, 0x11, 0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 }; uuid id(std::begin(arr), std::end(arr)); assert(uuids::to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43"); // or uuids::uuid id{{ 0x47, 0x18, 0x38, 0x23, 0x25, 0x74, 0x4b, 0xfd, 0xb4, 0x11, 0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43}}; assert(uuids::to_string(id) == "47183823-2574-4bfd-b411-99ed177d3e43");
-
Comparing UUIDs
uuid empty; uuid id = uuids::uuid_system_generator{}(); assert(empty == empty); assert(id == id); assert(empty != id);
-
Swapping UUIDs
uuid empty; uuid id = uuids::uuid_system_generator{}(); assert(empty.is_nil()); assert(!id.is_nil()); std::swap(empty, id); assert(!empty.is_nil()); assert(id.is_nil()); empty.swap(id); assert(empty.is_nil()); assert(!id.is_nil());
-
Converting to string
uuid empty; assert(uuids::to_string(empty) == "00000000-0000-0000-0000-000000000000"); assert(uuids::to_string<wchar_t>(empty) == L"00000000-0000-0000-0000-000000000000");
-
Using with an orderered associative container
std::random_device rd; auto seed_data = std::array<int, std::mt19937::state_size> {}; std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); std::mt19937 engine(seq); uuids::uuid_random_generator gen(&engine); std::set<uuids::uuid> ids{uuid{}, gen(), gen(), gen(), gen()}; assert(ids.size() == 5); assert(ids.find(uuid{}) != ids.end());
-
Using in an unordered associative container
std::random_device rd; auto seed_data = std::array<int, std::mt19937::state_size> {}; std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); std::mt19937 engine(seq); uuids::uuid_random_generator gen(&engine); std::unordered_set<uuids::uuid> ids{uuid{}, gen(), gen(), gen(), gen()}; assert(ids.size() == 5); assert(ids.find(uuid{}) != ids.end());
-
Hashing UUIDs
using namespace std::string_literals; auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s; uuid id = uuids::uuid::from_string(str).value(); auto h1 = std::hash<std::string>{}; auto h2 = std::hash<uuid>{}; assert(h1(str) == h2(id));
The library is supported on all major operating systems: Windows, Linux and Mac OS.
Because no major compiler supports std::span
yet the Microsoft Guidelines Support Library (aka GSL) is used for its span implementation (from which the standard version was defined).
A testing project is available in the sources. To build and execute the tests do the following:
- Clone or download this repository
- Create a
build
directory in the root directory of the sources - Run the command
cmake ..
from thebuild
directory; if you do not have CMake you must install it first. - Build the project created in the previous step
- Run the executable.
The SHA1 implementation is based on the TinySHA1 library.