-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
336 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[#time_generator] | ||
== <boost/uuid/time_generator.hpp> | ||
|
||
:idprefix: time_generator_ | ||
|
||
=== Synopsis | ||
|
||
[source,c++] | ||
---- | ||
#include <boost/uuid/time_generator_v1.hpp> | ||
#include <boost/uuid/time_generator_v6.hpp> | ||
#include <boost/uuid/time_generator_v7.hpp> | ||
---- | ||
|
||
This convenience header makes the three time-based generators `time_generator_v1`, `time_generator_v6`, and `time_generator_v7`, available. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
[#time_generator_v1] | ||
== <boost/uuid/{zwsp}time_generator_v1.hpp> | ||
|
||
:idprefix: time_generator_v1_ | ||
|
||
=== Synopsis | ||
|
||
[source,c++] | ||
---- | ||
namespace boost { | ||
namespace uuids { | ||
class time_generator_v1 | ||
{ | ||
public: | ||
struct state_type | ||
{ | ||
std::uint64_t timestamp; | ||
std::uint16_t clock_seq; | ||
}; | ||
private: // exposition only | ||
uuid::node_type node_ = {}; | ||
std::atomic<state_type>* ps_ = nullptr; | ||
state_type state_ = {}; | ||
public: | ||
using result_type = uuid; | ||
time_generator_v1(); | ||
time_generator_v1( uuid::node_type const& node, state_type const& state ) noexcept; | ||
time_generator_v1( uuid::node_type const& node, std::atomic<state_type>& state ) noexcept; | ||
result_type operator()() noexcept; | ||
}; | ||
}} // namespace boost::uuids | ||
---- | ||
|
||
The class `time_generator_v1` generates time-based version 1 UUIDs. | ||
It supports three modes of operation. | ||
|
||
The default and recommended one is by using its default constructor. | ||
This instructs the generator to use a pseudorandom node identifier and initial clock sequence. | ||
|
||
If more control over the node identifier (or the clock sequence) is desired, | ||
for example, | ||
if the generated UUIDs must use a specific node identifier that persists for the lifetime of the program or even across different program runs, | ||
a constructor that takes a node identifier and a `state_type` is provided. | ||
(The `timestamp` field of the provided `state_type` should generally be zero.) | ||
|
||
Finally, if the program has several `time_generator_v1` instances (for example, one per thread) that need to use the same node identifier, | ||
the third constructor takes a node identifier and a reference to `std::atomic<state_type>`. | ||
The atomic state is used by the generators to ensure that no duplicate UUIDs are produced. | ||
|
||
=== Constructors | ||
|
||
``` | ||
time_generator_v1(); | ||
``` | ||
|
||
Effects: :: Using entropy from `std::random_device`, generates a pseudorandom 48 bit node identifier in `node_` and a pseudorandom 14 bit clock sequence in `state_.clock_seq`. Initalizes `state_.timestamp` to zero. | ||
|
||
Remarks: :: The multicast bit of `node_` is set to denote a local node identifier, as recommended in https://www.rfc-editor.org/rfc/rfc4122.html#section-4.5[RFC 4122 Section 4.5]. | ||
|
||
``` | ||
time_generator_v1( uuid::node_type const& node, state_type const& state ) noexcept; | ||
``` | ||
|
||
Effects: :: Initializes `node_` to `node` and `state_` to `state`. | ||
|
||
``` | ||
time_generator_v1( uuid::node_type const& node, std::atomic<state_type>& state ) noexcept; | ||
``` | ||
|
||
Effects: :: Initializes `node_` to `node` and `ps_` to `&state`. | ||
|
||
=== operator() | ||
|
||
``` | ||
result_type operator()() noexcept; | ||
``` | ||
|
||
Effects: :: | ||
+ | ||
Using the state in `state_`, if `ps_` is `nullptr`, or the state in `*ps_`, if `ps_` is not `nullptr`, | ||
atomically computes and sets a new state by retrieving the system time as if by `uuid_clock::now()`, | ||
converting it to a timestamp as if by `uuid_clock::to_timestamp`, | ||
storing the result in `state.timestamp`, | ||
and incrementing `state.clock_seq` modulo 0x4000 if the new timestamp is lower than or equal to the previous timestamp. | ||
+ | ||
Creates a version 1 UUID using the node identifier from `node_` and the new timestamp and clock sequence and returns it. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
[#time_generator_v6] | ||
== <boost/uuid/{zwsp}time_generator_v6.hpp> | ||
|
||
:idprefix: time_generator_v6_ | ||
|
||
=== Synopsis | ||
|
||
[source,c++] | ||
---- | ||
namespace boost { | ||
namespace uuids { | ||
class time_generator_v6 | ||
{ | ||
public: | ||
struct state_type | ||
{ | ||
std::uint64_t timestamp; | ||
std::uint16_t clock_seq; | ||
}; | ||
private: // exposition only | ||
uuid::node_type node_ = {}; | ||
std::atomic<state_type>* ps_ = nullptr; | ||
state_type state_ = {}; | ||
public: | ||
using result_type = uuid; | ||
time_generator_v6(); | ||
time_generator_v6( uuid::node_type const& node, state_type const& state ) noexcept; | ||
time_generator_v6( uuid::node_type const& node, std::atomic<state_type>& state ) noexcept; | ||
result_type operator()() noexcept; | ||
}; | ||
}} // namespace boost::uuids | ||
---- | ||
|
||
The class `time_generator_v6` generates time-based version 6 UUIDs, as described in https://datatracker.ietf.org/doc/draft-ietf-uuidrev-rfc4122bis/[rfc4122bis] section 5.6. | ||
|
||
It operates in the exact same manner as `time_generator_v1`, with the only difference being that it produces version 6 UUIDs rather than version 1 ones. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
[#time_generator_v7] | ||
== <boost/uuid/{zwsp}time_generator_v7.hpp> | ||
|
||
:idprefix: time_generator_v7_ | ||
|
||
=== Synopsis | ||
|
||
[source,c++] | ||
[subs=+quotes] | ||
---- | ||
namespace boost { | ||
namespace uuids { | ||
class time_generator_v7 | ||
{ | ||
private: | ||
// exposition only | ||
_unspecified-csprng-type_ rng_; | ||
public: | ||
using result_type = uuid; | ||
time_generator_v7(); | ||
result_type operator()() noexcept; | ||
}; | ||
}} // namespace boost::uuids | ||
---- | ||
|
||
The class `time_generator_v7` generates time-based version 7 UUIDs, as described in https://datatracker.ietf.org/doc/draft-ietf-uuidrev-rfc4122bis/[rfc4122bis] section 5.7. | ||
|
||
=== Constructor | ||
|
||
``` | ||
time_generator_v7(); | ||
``` | ||
|
||
Effects: :: Initializes the internal cryptographically strong pseudorandom number generator (CSPRNG) `rng_` using entropy from `std::random_device`. | ||
|
||
=== operator() | ||
|
||
``` | ||
result_type operator()() noexcept; | ||
``` | ||
|
||
Effects: :: | ||
+ | ||
. Obtains a new timestamp as if by getting the system time from `std::chrono::system_clock::now()` and converting it to a number of microseconds from the Unix epoch. | ||
. Creates a new version 7 UUID and initializes its `unix_ts_ms` field with the number of milliseconds in the timestamp. | ||
. Initializes the `rand_a` field with the residual number of microseconds from the timestamp. | ||
. Initializes the 6 bits of the `rand_b` field following the variant to a conflict resolution counter, such that if more than one UUID is generated using the same timestamp, monotonicity is still ensured. | ||
. Initializes the rest of the `rand_b` field to random values obtained from the internal CSPRNG `rng_`. | ||
. Returns the UUID. | ||
|
||
Remarks: :: `operator()` generates a monotonically increasing sequence of UUIDs, if the following requirements are met: | ||
+ | ||
* The system clock never goes backwards; | ||
* The system clock has at least millisecond resolution; | ||
* No more than 64 UUIDs are generated per microsecond (no more than one every 16 nanoseconds.) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
[#uuid_clock] | ||
== <boost/uuid/uuid_clock.hpp> | ||
|
||
:idprefix: uuid_clock_ | ||
|
||
=== Synopsis | ||
|
||
[source,c++] | ||
---- | ||
namespace boost { | ||
namespace uuids { | ||
class uuid_clock | ||
{ | ||
public: | ||
using rep = std::int64_t; | ||
using period = std::ratio<1, 10000000>; // 100ns | ||
using duration = std::chrono::duration<rep, period>; | ||
using time_point = std::chrono::time_point<uuid_clock, duration>; | ||
static constexpr bool is_steady = false; | ||
static time_point now() noexcept; | ||
static time_point from_sys( std::chrono::system_clock::time_point const& tp ) noexcept; | ||
static std::chrono::system_clock::time_point to_sys( time_point const& tp ) noexcept; | ||
static time_point from_timestamp( std::uint64_t timestamp ) noexcept; | ||
static std::uint64_t to_timestamp( time_point const& tp ) noexcept; | ||
}; | ||
}} // namespace boost::uuids | ||
---- | ||
|
||
The class `uuid_clock` is a `<chrono>`-compatible clock with an epoch of 00:00:00.00, 15 October 1582, and a resolution of 100 ns. | ||
These values are specified in https://www.rfc-editor.org/rfc/rfc4122.html#section-4.1.4[RFC 4122 Section 4.1.4]. | ||
|
||
=== now | ||
|
||
``` | ||
static time_point now() noexcept; | ||
``` | ||
|
||
Returns: :: The current system time (`std::chrono::system_clock::now()`, converted to `uuid_clock::time_point`.) | ||
|
||
=== from_sys | ||
|
||
``` | ||
static time_point from_sys( std::chrono::system_clock::time_point const& tp ) noexcept; | ||
``` | ||
|
||
Returns: :: The `uuid_clock::time_point` corresponding to `tp`. | ||
|
||
=== to_sys | ||
|
||
``` | ||
static std::chrono::system_clock::time_point to_sys( time_point const& tp ) noexcept; | ||
``` | ||
|
||
Returns: :: The `std::chrono::system_clock::time_point` corresponding to `tp`. | ||
|
||
Example: :: | ||
+ | ||
``` | ||
#include <boost/uuid/time_generator_v1.hpp> | ||
#include <boost/uuid/uuid.hpp> | ||
#include <boost/uuid/uuid_clock.hpp> | ||
#include <chrono> | ||
|
||
using namespace boost::uuids; | ||
|
||
int main() | ||
{ | ||
time_generator_v1 gen; | ||
|
||
uuid u = gen(); // generates a version 1 time-based UUID | ||
|
||
// note that stream output of std::chrono::system_clock::time_point requires C++20 | ||
|
||
std::cout << uuid_clock::to_sys( u.time_point_v1() ) << std::endl; | ||
} | ||
``` | ||
|
||
=== from_timestamp | ||
|
||
``` | ||
static time_point from_timestamp( std::uint64_t timestamp ) noexcept; | ||
``` | ||
|
||
Returns: :: The `uuid_clock::time_point` corresponding to `timestamp` 100 nanosecond intervals since the `uuid_clock` epoch. | ||
|
||
=== to_timestamp | ||
|
||
``` | ||
static std::uint64_t to_timestamp( time_point const& tp ) noexcept; | ||
``` | ||
|
||
Returns: :: The number of 100 nanosecond intervals since the `uuid_clock` epoch corresponding to `tp`. | ||
|
||
Example: :: | ||
+ | ||
``` | ||
using namespace boost::uuids; | ||
|
||
uuid u = time_generator_v1()(); | ||
|
||
assert( u.timestamp_v1() == uuid_clock::to_timestamp( u.time_point_v1() ) ); | ||
``` |