Back to home page

EIC code displayed by LXR

 
 

    


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 // Copyright 2024 Peter Dimov
0005 // Distributed under the Boost Software License, Version 1.0.
0006 // https://www.boost.org/LICENSE_1_0.txt
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 // time_generator_v1
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 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114865
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 // constructors
0069 
0070 inline time_generator_v1::time_generator_v1()
0071 {
0072     detail::random_provider prov;
0073 
0074     // generate a pseudorandom node identifier
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; // mark as multicast
0081 
0082     // generate a pseudorandom 14 bit clock sequence
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 // get_new_state
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 // operator()
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 }} // namespace boost::uuids
0159 
0160 #endif // BOOST_UUID_TIME_GENERATOR_V1_HPP_INCLUDED