mirror of
				https://github.com/pocoproject/poco.git
				synced 2025-10-27 11:06:50 +01:00 
			
		
		
		
	feat(Foundation): Poco::UUID/UUIDGenerator: add support for Version 6 and 7 UUIDs (#4580)
This commit is contained in:
		| @@ -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(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Günter Obiltschnig
					Günter Obiltschnig