Skip to content

Commit

Permalink
Update documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
pdimov committed May 3, 2024
1 parent c915af9 commit b20a0ba
Show file tree
Hide file tree
Showing 7 changed files with 336 additions and 2 deletions.
2 changes: 1 addition & 1 deletion doc/uuid/namespaces.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ uuid url() noexcept;
uuid oid() noexcept;
uuid x500dn() noexcept;
}}} //namespace boost::uuids::ns
}}} // namespace boost::uuids::ns
----

=== Namespaces
Expand Down
7 changes: 6 additions & 1 deletion doc/uuid/reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

include::uuid_all.adoc[]
include::uuid.adoc[]
include::uuid_io.adoc[]
include::uuid_generators.adoc[]
include::nil_generator.adoc[]
include::string_generator.adoc[]
Expand All @@ -12,4 +13,8 @@ include::name_generator_md5.adoc[]
include::name_generator.adoc[]
include::basic_random_generator.adoc[]
include::random_generator.adoc[]
include::uuid_io.adoc[]
include::uuid_clock.adoc[]
include::time_generator_v1.adoc[]
include::time_generator_v6.adoc[]
include::time_generator_v7.adoc[]
include::time_generator.adoc[]
15 changes: 15 additions & 0 deletions doc/uuid/time_generator.adoc
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.
96 changes: 96 additions & 0 deletions doc/uuid/time_generator_v1.adoc
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.
46 changes: 46 additions & 0 deletions doc/uuid/time_generator_v6.adoc
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.
62 changes: 62 additions & 0 deletions doc/uuid/time_generator_v7.adoc
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.)
110 changes: 110 additions & 0 deletions doc/uuid/uuid_clock.adoc
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() ) );
```

0 comments on commit b20a0ba

Please sign in to comment.