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_V7_HPP_INCLUDED
0002 #define BOOST_UUID_TIME_GENERATOR_V7_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/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 // time_generator_v7
0020 
0021 class time_generator_v7
0022 {
0023 private:
0024 
0025     // Bit layout from high to low:
0026     // 48 bits: millisecond part of Unix epoch timestamp
0027     // 10 bits: microsecond part of Unix epoch timestamp
0028     //  6 bits: conflict resolution counter
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 // constructors
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 // assignment
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 // get_new_state
0093 
0094 inline time_generator_v7::state_type time_generator_v7::get_new_state( state_type const& oldst ) noexcept
0095 {
0096     // `now()` in microseconds
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; // timestamp, ms part
0100     std::uint64_t time_us = now_in_us % 1000; // timestamp, us part
0101 
0102     std::uint64_t newst = ( time_ms << 16 ) | ( time_us << 6 );
0103 
0104     // if the time has advanced, reset counter to zero
0105     if( newst > oldst )
0106     {
0107         return newst;
0108     }
0109 
0110     // if time_in_ms has gone backwards, we can't be monotonic
0111     if( time_ms < ( oldst >> 16 ) )
0112     {
0113         return newst;
0114     }
0115 
0116     // otherwise, use the old value and increment the counter
0117     return oldst + 1;
0118 }
0119 
0120 // operator()
0121 
0122 inline time_generator_v7::result_type time_generator_v7::operator()() noexcept
0123 {
0124     uuid result;
0125 
0126     // set lower 64 bits to random values
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     // get new timestamp
0134     state_ = get_new_state( state_ );
0135 
0136     std::uint64_t time_ms = state_ >> 16; // timestamp, ms part
0137     std::uint64_t time_us = ( state_ & 0xFFFF ) >> 6; // timestamp, us part
0138 
0139     std::uint64_t timestamp = ( time_ms << 16 ) | 0x7000 | time_us;
0140 
0141     detail::store_big_u64( result.data + 0, timestamp );
0142 
0143     // set variant and counter
0144 
0145     result.data[ 8 ] = static_cast< std::uint8_t >( 0x80 | ( state_ & 0x3F ) );
0146 
0147     return result;
0148 }
0149 
0150 }} // namespace boost::uuids
0151 
0152 #endif // BOOST_UUID_TIME_GENERATOR_V7_HPP_INCLUDED