File indexing completed on 2025-04-26 08:55:46
0001 #ifndef BOOST_UUID_TIME_GENERATOR_V1_HPP_INCLUDED
0002 #define BOOST_UUID_TIME_GENERATOR_V1_HPP_INCLUDED
0003
0004
0005
0006
0007
0008 #include <boost/uuid/uuid.hpp>
0009 #include <boost/uuid/uuid_clock.hpp>
0010 #include <boost/uuid/detail/random_provider.hpp>
0011 #include <boost/uuid/detail/endian.hpp>
0012 #include <boost/config.hpp>
0013 #include <boost/config/workaround.hpp>
0014 #include <atomic>
0015 #include <cstdint>
0016 #include <cstring>
0017
0018 namespace boost {
0019 namespace uuids {
0020
0021
0022
0023 class time_generator_v1
0024 {
0025 public:
0026
0027 struct state_type
0028 {
0029 std::uint64_t timestamp;
0030 std::uint16_t clock_seq;
0031
0032
0033 #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION, >= 130000)
0034 # if BOOST_CXX_VERSION >= 201402L
0035
0036 std::uint16_t padding[ 3 ] = {};
0037
0038 # else
0039
0040 std::uint16_t padding[ 3 ];
0041
0042 # endif
0043 #endif
0044 };
0045
0046 private:
0047
0048 uuid::node_type node_ = {};
0049
0050 std::atomic<state_type>* ps_ = nullptr;
0051 state_type state_ = {};
0052
0053 public:
0054
0055 using result_type = uuid;
0056
0057 time_generator_v1();
0058 time_generator_v1( uuid::node_type const& node, state_type const& state ) noexcept;
0059 time_generator_v1( uuid::node_type const& node, std::atomic<state_type>& state ) noexcept;
0060
0061 result_type operator()() noexcept;
0062
0063 private:
0064
0065 static state_type get_new_state( state_type const& oldst ) noexcept;
0066 };
0067
0068
0069
0070 inline time_generator_v1::time_generator_v1()
0071 {
0072 detail::random_provider prov;
0073
0074
0075
0076 std::uint32_t tmp[ 3 ];
0077 prov.generate( tmp, tmp + 3 );
0078
0079 std::memcpy( node_.data(), tmp, node_.size() );
0080 node_[ 0 ] |= 0x01;
0081
0082
0083
0084 state_.clock_seq = static_cast<std::uint16_t>( tmp[ 2 ] & 0x3FFF );
0085 }
0086
0087 inline time_generator_v1::time_generator_v1( uuid::node_type const& node, state_type const& state ) noexcept: node_( node ), state_( state )
0088 {
0089 }
0090
0091 inline time_generator_v1::time_generator_v1( uuid::node_type const& node, std::atomic<state_type>& state ) noexcept: node_( node ), ps_( &state )
0092 {
0093 }
0094
0095
0096
0097 inline time_generator_v1::state_type time_generator_v1::get_new_state( state_type const& oldst ) noexcept
0098 {
0099 state_type newst( oldst );
0100
0101 std::uint64_t timestamp = uuid_clock::now().time_since_epoch().count();
0102
0103 if( timestamp <= newst.timestamp )
0104 {
0105 newst.clock_seq = ( newst.clock_seq + 1 ) & 0x3FFF;
0106 }
0107
0108 newst.timestamp = timestamp;
0109
0110 return newst;
0111 }
0112
0113
0114
0115 inline time_generator_v1::result_type time_generator_v1::operator()() noexcept
0116 {
0117 if( ps_ )
0118 {
0119 auto oldst = ps_->load( std::memory_order_relaxed );
0120
0121 for( ;; )
0122 {
0123 auto newst = get_new_state( oldst );
0124
0125 if( ps_->compare_exchange_strong( oldst, newst, std::memory_order_relaxed, std::memory_order_relaxed ) )
0126 {
0127 state_ = newst;
0128 break;
0129 }
0130 }
0131 }
0132 else
0133 {
0134 state_ = get_new_state( state_ );
0135 }
0136
0137 uuid result;
0138
0139 std::uint32_t time_low = static_cast< std::uint32_t >( state_.timestamp );
0140
0141 detail::store_big_u32( result.data + 0, time_low );
0142
0143 std::uint16_t time_mid = static_cast< std::uint16_t >( state_.timestamp >> 32 );
0144
0145 detail::store_big_u16( result.data + 4, time_mid );
0146
0147 std::uint16_t time_hi_and_version = static_cast< std::uint16_t >( state_.timestamp >> 48 ) | 0x1000;
0148
0149 detail::store_big_u16( result.data + 6, time_hi_and_version );
0150
0151 detail::store_big_u16( result.data + 8, state_.clock_seq | 0x8000 );
0152
0153 std::memcpy( result.data + 10, node_.data(), 6 );
0154
0155 return result;
0156 }
0157
0158 }}
0159
0160 #endif