2
0
Эх сурвалжийг харах

Add version 6 UUID generation

Feoramund 1 жил өмнө
parent
commit
9866b54d59

+ 46 - 0
core/encoding/uuid/generation.odin

@@ -204,6 +204,52 @@ generate_v5 :: proc {
 	generate_v5_string,
 	generate_v5_string,
 }
 }
 
 
+/*
+Generate a version 6 UUID.
+
+Inputs:
+- clock_seq: The clock sequence from version 1, now made optional.
+  If unspecified, it will be replaced with random bits.
+- node: An optional 48-bit spatially unique identifier, specified to be the IEEE 802 address of the system.
+  If one is not provided or available, 48 bits of random state will take its place.
+
+Returns:
+- result: The generated UUID.
+*/
+generate_v6 :: proc(clock_seq: Maybe(u16) = nil, node: Maybe([6]u8) = nil) -> (result: Identifier) {
+	unix_time_in_hns_intervals := time.to_unix_nanoseconds(time.now()) / 100
+
+	timestamp := cast(u128be)(HNS_INTERVALS_BETWEEN_GREG_AND_UNIX + unix_time_in_hns_intervals)
+
+	result |= transmute(Identifier)(timestamp & 0x0FFFFFFF_FFFFF000 << 68)
+	result |= transmute(Identifier)(timestamp & 0x00000000_00000FFF << 64)
+
+	if realized_clock_seq, ok := clock_seq.?; ok {
+		assert(realized_clock_seq <= 0x3FFF, "The clock sequence can only hold 14 bits of data, therefore no number greater than 16,383.")
+		result[8] |= cast(u8)(realized_clock_seq & 0x3F00 >> 8)
+		result[9]  = cast(u8)realized_clock_seq
+	} else {
+		temporary: [2]u8
+		bytes_generated := rand.read(temporary[:])
+		assert(bytes_generated == 2, "RNG failed to generate 2 bytes for UUID v1.")
+		result[8] |= cast(u8)temporary[0] & 0x3F
+		result[9]  = cast(u8)temporary[1]
+	}
+
+	if realized_node, ok := node.?; ok {
+		mutable_node := realized_node
+		mem.copy_non_overlapping(&result[10], &mutable_node[0], 6)
+	} else {
+		bytes_generated := rand.read(result[10:])
+		assert(bytes_generated == 6, "RNG failed to generate 6 bytes for UUID v1.")
+	}
+
+	result[VERSION_BYTE_INDEX] |= 0x60
+	result[VARIANT_BYTE_INDEX] |= 0x80
+
+	return
+}
+
 /*
 /*
 Generate a version 7 UUID.
 Generate a version 7 UUID.
 
 

+ 19 - 1
core/encoding/uuid/reading.odin

@@ -99,7 +99,7 @@ variant :: proc "contextless" (id: Identifier) -> (variant: Variant_Type) #no_bo
 }
 }
 
 
 /*
 /*
-Get the clock sequence of a version 1 UUID.
+Get the clock sequence of a version 1 or version 6 UUID.
 
 
 Inputs:
 Inputs:
 - id: The identifier.
 - id: The identifier.
@@ -151,6 +151,24 @@ time_v1 :: proc "contextless" (id: Identifier) -> (timestamp: u64) {
 	return cast(u64)transmute(u64le)timestamp_octets
 	return cast(u64)transmute(u64le)timestamp_octets
 }
 }
 
 
+/*
+Get the timestamp of a version 6 UUID.
+
+Inputs:
+- id: The identifier.
+
+Returns:
+- timestamp: The timestamp, in 100-nanosecond intervals since 1582-10-15.
+*/
+time_v6 :: proc "contextless" (id: Identifier) -> (timestamp: u64) {
+	temporary := transmute(u128be)id
+
+	timestamp |= cast(u64)(temporary & 0xFFFFFFFF_FFFF0000_00000000_00000000 >> 68)
+	timestamp |= cast(u64)(temporary & 0x00000000_00000FFF_00000000_00000000 >> 64)
+
+	return timestamp
+}
+
 /*
 /*
 Get the timestamp of a version 7 UUID.
 Get the timestamp of a version 7 UUID.
 
 

+ 31 - 0
tests/core/encoding/uuid/test_core_uuid.odin

@@ -11,6 +11,7 @@ test_version_and_variant :: proc(t: ^testing.T) {
     v3 := uuid.generate_v3(uuid.Namespace_DNS, "")
     v3 := uuid.generate_v3(uuid.Namespace_DNS, "")
     v4 := uuid.generate_v4()
     v4 := uuid.generate_v4()
     v5 := uuid.generate_v5(uuid.Namespace_DNS, "")
     v5 := uuid.generate_v5(uuid.Namespace_DNS, "")
+    v6 := uuid.generate_v6()
     v7 := uuid.generate_v7()
     v7 := uuid.generate_v7()
 
 
     testing.expect_value(t, uuid.version(v1), 1)
     testing.expect_value(t, uuid.version(v1), 1)
@@ -21,6 +22,8 @@ test_version_and_variant :: proc(t: ^testing.T) {
     testing.expect_value(t, uuid.variant(v4), uuid.Variant_Type.RFC_4122)
     testing.expect_value(t, uuid.variant(v4), uuid.Variant_Type.RFC_4122)
     testing.expect_value(t, uuid.version(v5), 5)
     testing.expect_value(t, uuid.version(v5), 5)
     testing.expect_value(t, uuid.variant(v5), uuid.Variant_Type.RFC_4122)
     testing.expect_value(t, uuid.variant(v5), uuid.Variant_Type.RFC_4122)
+    testing.expect_value(t, uuid.version(v6), 6)
+    testing.expect_value(t, uuid.variant(v6), uuid.Variant_Type.RFC_4122)
     testing.expect_value(t, uuid.version(v7), 7)
     testing.expect_value(t, uuid.version(v7), 7)
     testing.expect_value(t, uuid.variant(v7), uuid.Variant_Type.RFC_4122)
     testing.expect_value(t, uuid.variant(v7), uuid.Variant_Type.RFC_4122)
 }
 }
@@ -84,6 +87,34 @@ test_v1 :: proc(t: ^testing.T) {
 	testing.expect(t, time_bits_c > time_bits_a, "The time bits on the later-generated v1 UUID are lesser than the earlier UUID.")
 	testing.expect(t, time_bits_c > time_bits_a, "The time bits on the later-generated v1 UUID are lesser than the earlier UUID.")
 }
 }
 
 
+@(test)
+test_v6 :: proc(t: ^testing.T) {
+	CLOCK :: 0x3A1A
+	v6_a := uuid.generate_v6(CLOCK)
+	time.sleep(10 * time.Millisecond)
+	v6_b := uuid.generate_v6(CLOCK)
+	time.sleep(10 * time.Millisecond)
+	v6_c := uuid.generate_v6(CLOCK)
+
+	testing.expect_value(t, uuid.clock_seq(v6_a), CLOCK)
+
+	time_bits_a := uuid.time_v6(v6_a)
+	time_bits_b := uuid.time_v6(v6_b)
+	time_bits_c := uuid.time_v6(v6_c)
+
+	time_a := time.Time { _nsec = cast(i64)((time_bits_a - uuid.HNS_INTERVALS_BETWEEN_GREG_AND_UNIX) * 100) }
+	time_b := time.Time { _nsec = cast(i64)((time_bits_b - uuid.HNS_INTERVALS_BETWEEN_GREG_AND_UNIX) * 100) }
+	time_c := time.Time { _nsec = cast(i64)((time_bits_c - uuid.HNS_INTERVALS_BETWEEN_GREG_AND_UNIX) * 100) }
+
+	log.debugf("A: %02x, %i, %v", v6_a, time_bits_a, time_a)
+	log.debugf("B: %02x, %i, %v", v6_b, time_bits_b, time_b)
+	log.debugf("C: %02x, %i, %v", v6_c, time_bits_c, time_c)
+
+	testing.expect(t, time_bits_b > time_bits_a, "The time bits on the later-generated v6 UUID are lesser than the earlier UUID.")
+	testing.expect(t, time_bits_c > time_bits_b, "The time bits on the later-generated v6 UUID are lesser than the earlier UUID.")
+	testing.expect(t, time_bits_c > time_bits_a, "The time bits on the later-generated v6 UUID are lesser than the earlier UUID.")
+}
+
 @(test)
 @(test)
 test_v7 :: proc(t: ^testing.T) {
 test_v7 :: proc(t: ^testing.T) {
 	v7_a := uuid.generate_v7()
 	v7_a := uuid.generate_v7()