File indexing completed on 2025-04-26 08:55:46
0001 #ifndef BOOST_UUID_TIME_GENERATOR_V7_HPP_INCLUDED
0002 #define BOOST_UUID_TIME_GENERATOR_V7_HPP_INCLUDED
0003
0004
0005
0006
0007
0008 #include <boost/uuid/uuid.hpp>
0009 #include <boost/uuid/detail/chacha20.hpp>
0010 #include <boost/uuid/detail/random_provider.hpp>
0011 #include <boost/uuid/detail/endian.hpp>
0012 #include <random>
0013 #include <cstdint>
0014 #include <cstring>
0015
0016 namespace boost {
0017 namespace uuids {
0018
0019
0020
0021 class time_generator_v7
0022 {
0023 private:
0024
0025
0026
0027
0028
0029
0030 using state_type = std::uint64_t;
0031
0032 state_type state_ = {};
0033
0034 detail::chacha20_12 rng_;
0035
0036 public:
0037
0038 using result_type = uuid;
0039
0040 time_generator_v7();
0041
0042 time_generator_v7( time_generator_v7 const& rhs );
0043 time_generator_v7( time_generator_v7&& rhs ) noexcept;
0044
0045 time_generator_v7& operator=( time_generator_v7 const& rhs ) noexcept;
0046 time_generator_v7& operator=( time_generator_v7&& rhs ) noexcept;
0047
0048 result_type operator()() noexcept;
0049
0050 private:
0051
0052 static state_type get_new_state( state_type const& oldst ) noexcept;
0053 };
0054
0055
0056
0057 inline time_generator_v7::time_generator_v7()
0058 {
0059 detail::random_provider seeder;
0060 rng_.seed( seeder );
0061 }
0062
0063 inline time_generator_v7::time_generator_v7( time_generator_v7 const& rhs ): state_( rhs.state_ )
0064 {
0065 detail::random_provider seeder;
0066 rng_.seed( seeder );
0067 }
0068
0069 inline time_generator_v7::time_generator_v7( time_generator_v7&& rhs ) noexcept: state_( std::move( rhs.state_ ) ), rng_( std::move( rhs.rng_ ) )
0070 {
0071 rhs.rng_.perturb();
0072 }
0073
0074
0075
0076 inline time_generator_v7& time_generator_v7::operator=( time_generator_v7 const& rhs ) noexcept
0077 {
0078 state_ = rhs.state_;
0079 return *this;
0080 }
0081
0082 inline time_generator_v7& time_generator_v7::operator=( time_generator_v7&& rhs ) noexcept
0083 {
0084 state_ = std::move( rhs.state_ );
0085 rng_ = std::move( rhs.rng_ );
0086
0087 rhs.rng_.perturb();
0088
0089 return *this;
0090 }
0091
0092
0093
0094 inline time_generator_v7::state_type time_generator_v7::get_new_state( state_type const& oldst ) noexcept
0095 {
0096
0097 std::uint64_t now_in_us = std::chrono::time_point_cast< std::chrono::microseconds >( std::chrono::system_clock::now() ).time_since_epoch().count();
0098
0099 std::uint64_t time_ms = now_in_us / 1000;
0100 std::uint64_t time_us = now_in_us % 1000;
0101
0102 std::uint64_t newst = ( time_ms << 16 ) | ( time_us << 6 );
0103
0104
0105 if( newst > oldst )
0106 {
0107 return newst;
0108 }
0109
0110
0111 if( time_ms < ( oldst >> 16 ) )
0112 {
0113 return newst;
0114 }
0115
0116
0117 return oldst + 1;
0118 }
0119
0120
0121
0122 inline time_generator_v7::result_type time_generator_v7::operator()() noexcept
0123 {
0124 uuid result;
0125
0126
0127
0128 std::uniform_int_distribution<std::uint32_t> dist;
0129
0130 detail::store_native_u32( result.data + 8, dist( rng_ ) );
0131 detail::store_native_u32( result.data + 12, dist( rng_ ) );
0132
0133
0134 state_ = get_new_state( state_ );
0135
0136 std::uint64_t time_ms = state_ >> 16;
0137 std::uint64_t time_us = ( state_ & 0xFFFF ) >> 6;
0138
0139 std::uint64_t timestamp = ( time_ms << 16 ) | 0x7000 | time_us;
0140
0141 detail::store_big_u64( result.data + 0, timestamp );
0142
0143
0144
0145 result.data[ 8 ] = static_cast< std::uint8_t >( 0x80 | ( state_ & 0x3F ) );
0146
0147 return result;
0148 }
0149
0150 }}
0151
0152 #endif