mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-12 10:13:51 +01:00
feat(Foundation): Poco::UUID/UUIDGenerator: add support for Version 6 and 7 UUIDs (#4580)
This commit is contained in:
parent
db1cc9507b
commit
072e980e1d
@ -40,6 +40,8 @@ class Foundation_API UUID
|
||||
/// draft by Leach/Salz from February, 1998
|
||||
/// (http://www.ics.uci.edu/~ejw/authoring/uuid-guid/draft-leach-uuids-guids-01.txt)
|
||||
/// and also http://tools.ietf.org/html/draft-mealling-uuid-urn-05
|
||||
///
|
||||
/// Version 6 and 7 UUIDs are based on RFC 9562.
|
||||
{
|
||||
public:
|
||||
enum Version
|
||||
@ -48,8 +50,9 @@ public:
|
||||
UUID_DCE_UID = 0x02,
|
||||
UUID_NAME_BASED = 0x03,
|
||||
UUID_RANDOM = 0x04,
|
||||
UUID_NAME_BASED_SHA1 = 0x05
|
||||
|
||||
UUID_NAME_BASED_SHA1 = 0x05,
|
||||
UUID_TIME_BASED_V6 = 0x06,
|
||||
UUID_TIME_BASED_V7 = 0x07
|
||||
};
|
||||
|
||||
UUID();
|
||||
|
@ -39,6 +39,8 @@ class Foundation_API UUIDGenerator
|
||||
/// RFC 2518 (WebDAV), section 6.4.1 and the UUIDs and GUIDs internet
|
||||
/// draft by Leach/Salz from February, 1998
|
||||
/// (http://ftp.ics.uci.edu/pub/ietf/webdav/uuid-guid/draft-leach-uuids-guids-01.txt)
|
||||
///
|
||||
/// Version 6 and 7 UUIDs are based on RFC 9562.
|
||||
{
|
||||
public:
|
||||
UUIDGenerator();
|
||||
@ -78,6 +80,13 @@ public:
|
||||
/// The UUID::version() method can be used to determine the actual kind of
|
||||
/// the UUID generated.
|
||||
|
||||
UUID createV6();
|
||||
/// Creates a time-based version 6 UUID (according to RFC 9562) with a MAC address.
|
||||
/// If no MAC address is available, a random MAC address will be generated.
|
||||
|
||||
UUID createV7();
|
||||
/// Creates a time-based version 7 UUID (according to RFC 9652).
|
||||
|
||||
void seed(UInt32 n);
|
||||
/// Seeds the internal pseudo random generator for time-based UUIDs with the given seed.
|
||||
|
||||
@ -97,6 +106,7 @@ private:
|
||||
Random _random;
|
||||
Timestamp _lastTime;
|
||||
int _ticks;
|
||||
Poco::UInt16 _counter;
|
||||
Environment::NodeId _node;
|
||||
bool _haveNode;
|
||||
|
||||
|
@ -33,6 +33,10 @@ int main(int argc, char** argv)
|
||||
{
|
||||
if (arg == "-random")
|
||||
uuid = UUIDGenerator::defaultGenerator().createRandom();
|
||||
else if (arg == "-v6")
|
||||
uuid = UUIDGenerator::defaultGenerator().createV6();
|
||||
else if (arg == "-v7")
|
||||
uuid = UUIDGenerator::defaultGenerator().createV7();
|
||||
else if (arg.empty())
|
||||
uuid = UUIDGenerator::defaultGenerator().create();
|
||||
else
|
||||
|
@ -24,8 +24,12 @@
|
||||
namespace Poco {
|
||||
|
||||
|
||||
UUIDGenerator::UUIDGenerator(): _ticks(0), _haveNode(false)
|
||||
UUIDGenerator::UUIDGenerator():
|
||||
_ticks(0),
|
||||
_counter(0),
|
||||
_haveNode(false)
|
||||
{
|
||||
seed();
|
||||
}
|
||||
|
||||
|
||||
@ -38,6 +42,18 @@ UUID UUIDGenerator::create()
|
||||
{
|
||||
FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | time_low |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | time_mid | ver | time_high |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |var| clock_seq | node |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | node |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
if (!_haveNode)
|
||||
{
|
||||
Environment::nodeId(_node);
|
||||
@ -99,6 +115,88 @@ UUID UUIDGenerator::createRandom()
|
||||
}
|
||||
|
||||
|
||||
UUID UUIDGenerator::createOne()
|
||||
{
|
||||
try
|
||||
{
|
||||
return create();
|
||||
}
|
||||
catch (Exception&)
|
||||
{
|
||||
return createRandom();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UUID UUIDGenerator::createV6()
|
||||
{
|
||||
FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | time_high |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | time_mid | ver | time_low |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |var| clock_seq | node |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | node |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
if (!_haveNode)
|
||||
{
|
||||
try
|
||||
{
|
||||
Environment::nodeId(_node);
|
||||
_haveNode = true;
|
||||
}
|
||||
catch (Poco::Exception&)
|
||||
{
|
||||
RandomInputStream ris;
|
||||
ris.read(reinterpret_cast<char*>(_node), sizeof(_node));
|
||||
}
|
||||
}
|
||||
Timestamp::UtcTimeVal tv = timeStamp();
|
||||
UInt32 timeHigh = UInt32((tv >> 28) & 0xFFFFFFFF);
|
||||
UInt16 timeMid = UInt16((tv >> 12) & 0xFFFF);
|
||||
UInt16 timeLoAndVersion = UInt16(tv & 0x0FFF) + (UUID::UUID_TIME_BASED_V6 << 12);
|
||||
UInt16 clockSeq = (UInt16(_random.next() >> 4) & 0x3FFF) | 0x8000;
|
||||
return UUID(timeHigh, timeMid, timeLoAndVersion, clockSeq, _node);
|
||||
}
|
||||
|
||||
|
||||
UUID UUIDGenerator::createV7()
|
||||
{
|
||||
FastMutex::ScopedLock lock(_mutex);
|
||||
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | unix_ts_ms |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | unix_ts_ms | ver | rand_a |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |var| rand_b |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | rand_b |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
|
||||
if (_counter == 0) _counter = static_cast<Poco::UInt16>(_random.next(4096));
|
||||
|
||||
Timestamp::TimeVal tv = Poco::Timestamp().epochMicroseconds()/1000;
|
||||
UInt32 timeHigh = UInt32((tv >> 16) & 0xFFFFFFFF);
|
||||
UInt16 timeMid = UInt16(tv & 0xFFFF);
|
||||
UInt16 randAVersion = (_counter++ & 0x0FFF) + (UUID::UUID_TIME_BASED_V7 << 12);
|
||||
UInt16 randBHiVar = (UInt16(_random.next() >> 4) & 0x3FFF) | 0x8000;
|
||||
Poco::UInt8 randBLow[6];
|
||||
RandomInputStream ris;
|
||||
ris.read(reinterpret_cast<char*>(randBLow), sizeof(randBLow));
|
||||
return UUID(timeHigh, timeMid, randAVersion, randBHiVar, randBLow);
|
||||
}
|
||||
|
||||
|
||||
Timestamp::UtcTimeVal UUIDGenerator::timeStamp()
|
||||
{
|
||||
Timestamp now;
|
||||
@ -122,19 +220,6 @@ Timestamp::UtcTimeVal UUIDGenerator::timeStamp()
|
||||
}
|
||||
|
||||
|
||||
UUID UUIDGenerator::createOne()
|
||||
{
|
||||
try
|
||||
{
|
||||
return create();
|
||||
}
|
||||
catch (Exception&)
|
||||
{
|
||||
return createRandom();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UUIDGenerator::seed()
|
||||
{
|
||||
Poco::FastMutex::ScopedLock lock(_mutex);
|
||||
|
@ -91,6 +91,58 @@ void UUIDGeneratorTest::testNameBased()
|
||||
}
|
||||
|
||||
|
||||
void UUIDGeneratorTest::testV6()
|
||||
{
|
||||
UUIDGenerator& gen = UUIDGenerator::defaultGenerator();
|
||||
|
||||
Poco::UUID uuid1 = gen.createV6();
|
||||
assertTrue (uuid1.version() == Poco::UUID::UUID_TIME_BASED_V6);
|
||||
assertTrue (uuid1.variant() == 2);
|
||||
}
|
||||
|
||||
|
||||
void UUIDGeneratorTest::testV7()
|
||||
{
|
||||
UUIDGenerator& gen = UUIDGenerator::defaultGenerator();
|
||||
|
||||
Poco::UUID uuid1 = gen.createV7();
|
||||
assertTrue (uuid1.version() == Poco::UUID::UUID_TIME_BASED_V7);
|
||||
assertTrue (uuid1.variant() == 2);
|
||||
}
|
||||
|
||||
|
||||
void UUIDGeneratorTest::testV6Uniqueness()
|
||||
{
|
||||
UUIDGenerator& gen = UUIDGenerator::defaultGenerator();
|
||||
|
||||
const int ROUNDS = 1000;
|
||||
|
||||
std::set<Poco::UUID> uuids;
|
||||
for (int i = 0; i < ROUNDS; i++)
|
||||
{
|
||||
uuids.insert(gen.createV6());
|
||||
}
|
||||
|
||||
assertTrue (uuids.size() == ROUNDS);
|
||||
}
|
||||
|
||||
|
||||
void UUIDGeneratorTest::testV7Uniqueness()
|
||||
{
|
||||
UUIDGenerator& gen = UUIDGenerator::defaultGenerator();
|
||||
|
||||
const int ROUNDS = 1000;
|
||||
|
||||
std::set<Poco::UUID> uuids;
|
||||
for (int i = 0; i < ROUNDS; i++)
|
||||
{
|
||||
uuids.insert(gen.createV7());
|
||||
}
|
||||
|
||||
assertTrue (uuids.size() == ROUNDS);
|
||||
}
|
||||
|
||||
|
||||
void UUIDGeneratorTest::setUp()
|
||||
{
|
||||
}
|
||||
@ -108,6 +160,10 @@ CppUnit::Test* UUIDGeneratorTest::suite()
|
||||
CppUnit_addTest(pSuite, UUIDGeneratorTest, testTimeBased);
|
||||
CppUnit_addTest(pSuite, UUIDGeneratorTest, testRandom);
|
||||
CppUnit_addTest(pSuite, UUIDGeneratorTest, testNameBased);
|
||||
CppUnit_addTest(pSuite, UUIDGeneratorTest, testV6);
|
||||
CppUnit_addTest(pSuite, UUIDGeneratorTest, testV7);
|
||||
CppUnit_addTest(pSuite, UUIDGeneratorTest, testV6Uniqueness);
|
||||
CppUnit_addTest(pSuite, UUIDGeneratorTest, testV7Uniqueness);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -27,6 +27,10 @@ public:
|
||||
void testTimeBased();
|
||||
void testRandom();
|
||||
void testNameBased();
|
||||
void testV6();
|
||||
void testV7();
|
||||
void testV6Uniqueness();
|
||||
void testV7Uniqueness();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
@ -204,6 +204,7 @@ void UUIDTest::testSwap()
|
||||
assertTrue (uuid2.toString() == "db4fa7e9-9e62-4597-99e0-b1ec0b59800e");
|
||||
}
|
||||
|
||||
|
||||
void UUIDTest::testTryParse()
|
||||
{
|
||||
Poco::UUID uuid;
|
||||
@ -215,6 +216,27 @@ void UUIDTest::testTryParse()
|
||||
assertTrue (notUuid.isNull());
|
||||
}
|
||||
|
||||
|
||||
void UUIDTest::testV6()
|
||||
{
|
||||
Poco::UUID uuid("1EC9414C-232A-6B00-B3C8-9F6BDECED846");
|
||||
int ver = uuid.version();
|
||||
assertTrue (ver == 6);
|
||||
int var = uuid.variant();
|
||||
assertTrue (var == 2);
|
||||
}
|
||||
|
||||
|
||||
void UUIDTest::testV7()
|
||||
{
|
||||
Poco::UUID uuid("017F22E2-79B0-7CC3-98C4-DC0C0C07398F");
|
||||
int ver = uuid.version();
|
||||
assertTrue (ver == 7);
|
||||
int var = uuid.variant();
|
||||
assertTrue (var == 2);
|
||||
}
|
||||
|
||||
|
||||
void UUIDTest::setUp()
|
||||
{
|
||||
}
|
||||
@ -236,6 +258,8 @@ CppUnit::Test* UUIDTest::suite()
|
||||
CppUnit_addTest(pSuite, UUIDTest, testVariant);
|
||||
CppUnit_addTest(pSuite, UUIDTest, testSwap);
|
||||
CppUnit_addTest(pSuite, UUIDTest, testTryParse);
|
||||
CppUnit_addTest(pSuite, UUIDTest, testV6);
|
||||
CppUnit_addTest(pSuite, UUIDTest, testV7);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -31,6 +31,8 @@ public:
|
||||
void testVariant();
|
||||
void testSwap();
|
||||
void testTryParse();
|
||||
void testV6();
|
||||
void testV7();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
Loading…
Reference in New Issue
Block a user