I have recently submitted a proposal for a new standard library for universally unique identifiers. The library is called uuid and the paper, P0959R0 – A Proposal for a Universally Unique Identifier Library, is available on Github. The design of the library is inspired by the Boost Uuid Library and the Crossuuid library. I got lots of great feedback that shaped the formed of the proposal from people on the ISO C++ Standard – Future Proposals forum.
I have made an implementation of the library, which is called stduuid, and again, it available on github. This implementation is supported on all major operating systems: Windows, Linux and Mac OS.
Motivation
Universally unique identifiers (uuid), also known as Globally Unique Identifiers (guids), 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.
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.
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.
Using the library
The following is a list of examples for using the library:
-
Creating a nil UUID
uuid empty; assert(empty.nil()); assert(empty.size() == 16);
-
Creating a new UUID
uuid const guid = uuids::uuid_system_generator{}(); assert(!guid.nil()); assert(guid.size() == 16); assert(guid.version() == uuids::uuid_version::random_number_based); assert(guid.variant() == uuids::uuid_variant::rfc);
-
Creating a new UUID with a default random generator
uuids::uuid_random_generator gen; uuid const guid = gen(); assert(!guid.nil()); assert(guid.size() == 16); assert(guid.version() == uuids::uuid_version::random_number_based); assert(guid.variant() == uuids::uuid_variant::rfc);
-
Creating a new UUID with a particular random generator
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.nil()); assert(guid.size() == 16); assert(guid.version() == uuids::uuid_version::random_number_based); assert(guid.variant() == uuids::uuid_variant::rfc);
-
Creating a new UUID with the name generator
uuids::uuid_name_generator gen; uuid const guid = gen(); assert(!guid.nil()); assert(guid.size() == 16); assert(guid.version() == uuids::uuid_version::name_based_sha1); assert(guid.variant() == uuids::uuid_variant::rfc);
Create a UUID from a string
using namespace std::string_literals; auto str = "47183823-2574-4bfd-b411-99ed177d3e43"s; uuid guid(str); assert(guid.string() == str);
or
auto str = L"47183823-2574-4bfd-b411-99ed177d3e43"s; uuid guid(str); assert(guid.wstring() == str);
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(std::begin(arr), std::end(arr)); assert(id.string() == "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 empty; uuid guid = uuids::uuid_system_generator{}(); assert(empty == empty); assert(guid == guid); assert(empty != guid);
uuid empty; uuid guid = uuids::uuid_system_generator{}(); assert(empty.nil()); assert(!guid.nil()); std::swap(empty, guid); assert(!empty.nil()); assert(guid.nil()); empty.swap(guid); assert(empty.nil()); assert(!guid.nil());
uuid empty; assert(uuids::to_string(empty) == "00000000-0000-0000-0000-000000000000"); assert(uuids::to_wstring(empty) == L"00000000-0000-0000-0000-000000000000");
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; assert(guid.nil()); std::copy(std::cbegin(arr), std::cend(arr), std::begin(guid)); assert(!guid.nil()); assert(guid.string() == "47183823-2574-4bfd-b411-99ed177d3e43"); size_t i = 0; for (auto const & b : guid) assert(arr[i++] == b);
uuids::uuid_random_generator gen; std::set<uuids::uuid> ids{uuid{}, gen(), gen(), gen(), gen()}; assert(ids.size() == 5); assert(ids.find(uuid{}) != ids.end());
uuids::uuid_random_generator gen; std::unordered_set<uuids::uuid> ids{uuid{}, gen(), gen(), gen(), gen()}; assert(ids.size() == 5); assert(ids.find(uuid{}) != ids.end());
auto h1 = std::hash<std::string>{}; auto h2 = std::hash<uuid>{}; assert(h1(str) == h2(guid));
You can read more about the library, including the proposed paper, on Github. I encourage you to try the library and provide feedback, whether here or on github, on the issues or the suggestions that you might have.