This commit is contained in:
Marius Bancila 2017-12-19 12:56:35 +02:00
commit 883f2547b6
2 changed files with 106 additions and 105 deletions

View File

@ -52,25 +52,26 @@ assert(guid.wstring() == str);
``` ```
* Creating a UUID from an array * Creating a UUID from an array
``` ```
std::array<uint8_t, 16> arr{{ std::array<std::byte, 16> arr{{
0x47, 0x18, 0x38, 0x23, std::byte{ 0x47 }, std::byte{ 0x18 }, std::byte{ 0x38 }, std::byte{ 0x23 },
0x25, 0x74, std::byte{ 0x25 }, std::byte{ 0x74 },
0x4b, 0xfd, std::byte{ 0x4b }, std::byte{ 0xfd },
0xb4, 0x11, std::byte{ 0xb4 }, std::byte{ 0x11 },
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43}}; std::byte{ 0x99 }, std::byte{ 0xed }, std::byte{ 0x17 }, std::byte{ 0x7d }, std::byte{ 0x3e }, std::byte{ 0x43 }
uuid guid(arr); }};
uuid guid(std::begin(arr), std::end(arr));
assert(id.string() == "47183823-2574-4bfd-b411-99ed177d3e43"); assert(id.string() == "47183823-2574-4bfd-b411-99ed177d3e43");
``` ```
or or
``` ```
uint8_t arr[16] = { std::byte arr[16] = {
0x47, 0x18, 0x38, 0x23, std::byte{ 0x47 }, std::byte{ 0x18 }, std::byte{ 0x38 }, std::byte{ 0x23 },
0x25, 0x74, std::byte{ 0x25 }, std::byte{ 0x74 },
0x4b, 0xfd, std::byte{ 0x4b }, std::byte{ 0xfd },
0xb4, 0x11, std::byte{ 0xb4 }, std::byte{ 0x11 },
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43}; std::byte{ 0x99 }, std::byte{ 0xed }, std::byte{ 0x17 }, std::byte{ 0x7d }, std::byte{ 0x3e }, std::byte{ 0x43 } };
uuid guid(arr); uuid guid(std::begin(arr), std::end(arr));
assert(id.string() == "47183823-2574-4bfd-b411-99ed177d3e43"); assert(guid.string() == "47183823-2574-4bfd-b411-99ed177d3e43");
``` ```
* Comparing UUIDS * Comparing UUIDS
``` ```
@ -107,12 +108,13 @@ assert(empty.wstring() == L"00000000-0000-0000-0000-000000000000");
``` ```
* Iterating through the UUID data * Iterating through the UUID data
``` ```
std::array<uint8_t, 16> arr{{ std::array<std::byte, 16> arr{{
0x47, 0x18, 0x38, 0x23, std::byte{ 0x47 }, std::byte{ 0x18 }, std::byte{ 0x38 }, std::byte{ 0x23 },
0x25, 0x74, std::byte{ 0x25 }, std::byte{ 0x74 },
0x4b, 0xfd, std::byte{ 0x4b }, std::byte{ 0xfd },
0xb4, 0x11, std::byte{ 0xb4 }, std::byte{ 0x11 },
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43}}; std::byte{ 0x99 }, std::byte{ 0xed }, std::byte{ 0x17 }, std::byte{ 0x7d }, std::byte{ 0x3e }, std::byte{ 0x43 }
}};
uuid guid; uuid guid;
assert(guid.nil()); assert(guid.nil());

167
paper.md
View File

@ -6,7 +6,7 @@ Universally unique identifiers (*uuid*), also known as Globally Unique Identifie
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. 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 lite one: it enables developers to generate UUIDs based on the operation system facilities, serialize and deserialize UUIDs to and frmo strings, validate UUIDs and other common ensuing operations. The library proposed on this paper is a light one: it enables developers to generate UUIDs based on the operation system facilities, serialize and deserialize UUIDs to and from strings, validate UUIDs and other common ensuing operations.
## II. Impact On the Standard ## II. Impact On the Standard
@ -14,7 +14,7 @@ This proposal is a pure library extension. It does not require changes to any st
## III. Design Decisions ## III. Design Decisions
The proposed library, that should be available in a new header called `<uuid>` in the namespace `std::uuids`, provides: 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 * 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 * strongly type enums `uuid_variant` and `uuid_version` to represent the possible variant and version types of a UUID
* a `make_uuid` function to generate a new UUID * a `make_uuid` function to generate a new UUID
@ -31,9 +31,9 @@ uuid empty;
auto empty = uuid{}; auto empty = uuid{};
``` ```
### String constructors ### string_view constructors
Conversion constructors from `std::string` and `std::wstring` allow to create `uuid` instances from a string. 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. 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.
@ -44,28 +44,27 @@ std::wstring str=L"47183823-2574-4bfd-b411-99ed177d3e43";
uuid id2(str); uuid id2(str);
``` ```
### Array constructors ### Iterators constructors
The conversion constructor from `std::array<uint8_t, 16>` enables the construction of a `uuid` from an array of bytes. 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.
``` ```
std::array<uint8_t, 16> arr{{ std::array<std::byte, 16> arr{{
0x47, 0x18, 0x38, 0x23, std::byte{ 0x47 }, std::byte{ 0x18 }, std::byte{ 0x38 }, std::byte{ 0x23 },
0x25, 0x74, std::byte{ 0x25 }, std::byte{ 0x74 },
0x4b, 0xfd, std::byte{ 0x4b }, std::byte{ 0xfd },
0xb4, 0x11, std::byte{ 0xb4 }, std::byte{ 0x11 },
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43}}; std::byte{ 0x99 }, std::byte{ 0xed }, std::byte{ 0x17 }, std::byte{ 0x7d }, std::byte{ 0x3e }, std::byte{ 0x43 } }};
uuid id(arr); uuid id(arr);
``` ```
A conversion constructor from `uint8_t*` also exists to construct `uuid`s from C-like arrays. This requires the input buffer to have at least 16 bytes. The behavior when the buffer does not have 16 bytes is undefined.
``` ```
uint8_t arr[16] = { std::byte arr[16] = {
0x47, 0x18, 0x38, 0x23, std::byte{ 0x47 }, std::byte{ 0x18 }, std::byte{ 0x38 }, std::byte{ 0x23 },
0x25, 0x74, std::byte{ 0x25 }, std::byte{ 0x74 },
0x4b, 0xfd, std::byte{ 0x4b }, std::byte{ 0xfd },
0xb4, 0x11, std::byte{ 0xb4 }, std::byte{ 0x11 },
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43}; std::byte{ 0x99 }, std::byte{ 0xed }, std::byte{ 0x17 }, std::byte{ 0x7d }, std::byte{ 0x3e }, std::byte{ 0x43 }};
uuid id(arr); uuid id(arr);
``` ```
@ -96,12 +95,12 @@ assert(id.wstring() == L"47183823-2574-4bfd-b411-99ed177d3e43");
Constant and mutable iterators allow direct access to the underlaying `uuid` data. This enables both direct reading and writing of the `uuid` bits. Constant and mutable iterators allow direct access to the underlaying `uuid` data. This enables both direct reading and writing of the `uuid` bits.
``` ```
std::array<uint8_t, 16> arr{{ std::array<std::byte, 16> arr{{
0x47, 0x18, 0x38, 0x23, std::byte{ 0x47 }, std::byte{ 0x18 }, std::byte{ 0x38 }, std::byte{ 0x23 },
0x25, 0x74, std::byte{ 0x25 }, std::byte{ 0x74 },
0x4b, 0xfd, std::byte{ 0x4b }, std::byte{ 0xfd },
0xb4, 0x11, std::byte{ 0xb4 }, std::byte{ 0x11 },
0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43}}; std::byte{ 0x99 }, std::byte{ 0xed }, std::byte{ 0x17 }, std::byte{ 0x7d }, std::byte{ 0x3e }, std::byte{ 0x43 } }};
uuid id; uuid id;
assert(id.nil()); assert(id.nil());
@ -121,8 +120,8 @@ Member functions `variant()` and `version()` allows to check the variant type of
``` ```
uuid id("47183823-2574-4bfd-b411-99ed177d3e43"); uuid id("47183823-2574-4bfd-b411-99ed177d3e43");
assert(id.version() == uuids::uuid_version::random_number_based); assert(id.version() == uuid_version::random_number_based);
assert(id.variant() == uuids::uuid_variant::rfc); assert(id.variant() == uuid_variant::rfc);
``` ```
### Swapping ### Swapping
@ -165,10 +164,10 @@ assert(empty != id);
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 some containers such as `std::set` that by default use the operator to compare keys. 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 some containers such as `std::set` that by default use the operator to compare keys.
``` ```
std::set<uuids::uuid> ids{ std::set<std::uuid> ids{
uuid{}, uuid{},
uuids::uuid("47183823-2574-4bfd-b411-99ed177d3e43"), uuid("47183823-2574-4bfd-b411-99ed177d3e43"),
uuids::make_uuid() make_uuid()
}; };
assert(ids.size() == 3); assert(ids.size() == 3);
@ -180,10 +179,10 @@ assert(ids.find(uuid{}) != ids.end());
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`. 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`.
``` ```
std::unordered_set<uuids::uuid> ids{ std::unordered_set<uuid> ids{
uuid{}, uuid{},
uuids::uuid("47183823-2574-4bfd-b411-99ed177d3e43"), uuid("47183823-2574-4bfd-b411-99ed177d3e43"),
uuids::make_uuid() make_uuid()
}; };
assert(ids.size() == 3); assert(ids.size() == 3);
@ -197,8 +196,8 @@ Non-member `make_uuid` function creates a new uuid by relying on the operating s
``` ```
auto id = make_uuid(); auto id = make_uuid();
assert(!id.nil()); assert(!id.nil());
assert(id.version() == uuids::uuid_version::random_number_based); assert(id.version() == uuid_version::random_number_based);
assert(id.variant() == uuids::uuid_variant::rfc); assert(id.variant() == uuid_variant::rfc);
``` ```
## IV. Technical Specifications ## IV. Technical Specifications
@ -209,7 +208,7 @@ Add a new header called `<uuid>`.
### `uuid_variant` enum ### `uuid_variant` enum
``` ```
namespace std::uuid { namespace std {
enum class uuid_variant enum class uuid_variant
{ {
ncs, ncs,
@ -223,7 +222,7 @@ namespace std::uuid {
### `uuid_version` enum ### `uuid_version` enum
``` ```
namespace std::uuid { namespace std {
enum class uuid_version enum class uuid_version
{ {
none = 0, none = 0,
@ -239,59 +238,60 @@ namespace std::uuid {
### `uuid` class ### `uuid` class
``` ```
namespace std::uuid { namespace std {
struct uuid struct uuid
{ {
public: public:
typedef uint8_t value_type; typedef std::byte value_type;
typedef uint8_t& reference; typedef std::byte& reference;
typedef uint8_t const& const_reference; typedef std::byte const& const_reference;
typedef uint8_t* iterator; typedef std::byte* iterator;
typedef uint8_t const* const_iterator; typedef std::byte const* const_iterator;
typedef std::size_t size_type; typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type; typedef std::ptrdiff_t difference_type;
public: public:
constexpr explicit uuid(); constexpr uuid() noexcept;
constexpr explicit uuid(std::array<uint8_t, 16> const & bytes);
explicit uuid(uint8_t const * const bytes);
explicit uuid(std::string const & str);
explicit uuid(std::wstring const & str);
constexpr uuid_variant variant() const noexcept; template<typename ForwardIterator>
constexpr uuid_version version() const noexcept; explicit uuid(ForwardIterator first, ForwardIterator last);
constexpr std::size_t size() const noexcept;
constexpr bool nil() const noexcept;
void swap(uuid & other) noexcept; explicit uuid(std::string_view str);
friend void swap(uuid& lhs, uuid& rhs) noexcept; explicit uuid(std::wstring_view str);
iterator begin() noexcept;
const_iterator begin() const noexcept;
iterator end() noexcept;
const_iterator end() const noexcept;
template<class CharT, constexpr uuid_variant variant() const noexcept;
class Traits = std::char_traits<CharT>, constexpr uuid_version version() const noexcept;
class Alloc = std::allocator<CharT>> constexpr std::size_t size() const noexcept;
std::basic_string<CharT, Traits, Alloc> string(Alloc const & a = Alloc()) const; constexpr bool nil() const noexcept;
std::string string() const;
std::wstring wstring() const;
private: void swap(uuid & other) noexcept;
friend bool operator==(uuid const & lhs, uuid const & rhs) noexcept; friend void swap(uuid& lhs, uuid& rhs) noexcept;
friend bool operator<(uuid const & lhs, uuid const & rhs) noexcept;
iterator begin() noexcept;
template <class Elem, class Traits> const_iterator begin() const noexcept;
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id); iterator end() noexcept;
}; const_iterator end() const noexcept;
}
template<class CharT,
class Traits = std::char_traits<CharT>,
class Alloc = std::allocator<CharT>>
std::basic_string<CharT, Traits, Alloc> string(Alloc const & a = Alloc()) const;
std::string string() const;
std::wstring wstring() const;
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);
};
``` ```
### non-member functions ### non-member functions
``` ```
namespace std::uuid { namespace std {
inline bool operator== (uuid const& lhs, uuid const& rhs) noexcept; inline bool operator== (uuid const& lhs, uuid const& rhs) noexcept;
inline bool operator!= (uuid const& lhs, uuid const& rhs) noexcept; inline bool operator!= (uuid const& lhs, uuid const& rhs) noexcept;
inline bool operator< (uuid const& lhs, uuid const& rhs) noexcept; inline bool operator< (uuid const& lhs, uuid const& rhs) noexcept;
@ -306,15 +306,14 @@ namespace std::uuid {
### Specialization ### Specialization
``` ```
namespace std namespace std {
{
template <> template <>
void swap(uuids::uuid & lhs, uuids::uuid & rhs); void swap(uuid & lhs, uuid & rhs);
template <> template <>
struct hash<uuids::uuid> struct hash<uuid>
{ {
typedef uuids::uuid argument_type; typedef uuid argument_type;
typedef std::size_t result_type; typedef std::size_t result_type;
result_type operator()(argument_type const &uuid) const; result_type operator()(argument_type const &uuid) const;