Daily bump.
[gcc.git] / libphobos / src / std / uuid.d
blob09ce2f73f380c1da4da4714210d8d47b9c25c900
1 /**
2 * A $(LINK2 http://en.wikipedia.org/wiki/Universally_unique_identifier, UUID), or
3 * $(LINK2 http://en.wikipedia.org/wiki/Universally_unique_identifier, Universally unique identifier),
4 * is intended to uniquely identify information in a distributed environment
5 * without significant central coordination. It can be
6 * used to tag objects with very short lifetimes, or to reliably identify very
7 * persistent objects across a network.
9 $(SCRIPT inhibitQuickIndex = 1;)
11 $(DIVC quickindex,
12 $(BOOKTABLE ,
13 $(TR $(TH Category) $(TH Functions)
15 $(TR $(TDNW Parsing UUIDs)
16 $(TD $(MYREF parseUUID)
17 $(MYREF UUID)
18 $(MYREF UUIDParsingException)
19 $(MYREF uuidRegex)
22 $(TR $(TDNW Generating UUIDs)
23 $(TD $(MYREF sha1UUID)
24 $(MYREF randomUUID)
25 $(MYREF md5UUID)
28 $(TR $(TDNW Using UUIDs)
29 $(TD $(MYREF2 UUID.uuidVersion, uuidVersion)
30 $(MYREF2 UUID.variant, variant)
31 $(MYREF2 UUID.toString, toString)
32 $(MYREF2 UUID.data, data)
33 $(MYREF2 UUID.swap, swap)
34 $(MYREF2 UUID.opEquals, opEquals)
35 $(MYREF2 UUID.opCmp, opCmp)
36 $(MYREF2 UUID.toHash, toHash)
39 $(TR $(TDNW UUID namespaces)
40 $(TD $(MYREF dnsNamespace)
41 $(MYREF urlNamespace)
42 $(MYREF oidNamespace)
43 $(MYREF x500Namespace)
49 * UUIDs have many applications. Some examples follow: Databases may use UUIDs to identify
50 * rows or records in order to ensure that they are unique across different
51 * databases, or for publication/subscription services. Network messages may be
52 * identified with a UUID to ensure that different parts of a message are put back together
53 * again. Distributed computing may use UUIDs to identify a remote procedure call.
54 * Transactions and classes involved in serialization may be identified by UUIDs.
55 * Microsoft's component object model (COM) uses UUIDs to distinguish different software
56 * component interfaces. UUIDs are inserted into documents from Microsoft Office programs.
57 * UUIDs identify audio or video streams in the Advanced Systems Format (ASF). UUIDs are
58 * also a basis for OIDs (object identifiers), and URNs (uniform resource name).
60 * An attractive feature of UUIDs when compared to alternatives is their relative small size,
61 * of 128 bits, or 16 bytes. Another is that the creation of UUIDs does not require
62 * a centralized authority.
64 * When UUIDs are generated by one of the defined mechanisms, they are either guaranteed
65 * to be unique, different from all other generated UUIDs (that is, it has never been
66 * generated before and it will never be generated again), or it is extremely likely
67 * to be unique (depending on the mechanism).
69 * For efficiency, UUID is implemented as a struct. UUIDs are therefore empty if not explicitly
70 * initialized. An UUID is empty if $(MYREF3 UUID.empty, empty) is true. Empty UUIDs are equal to
71 * `UUID.init`, which is a UUID with all 16 bytes set to 0.
72 * Use UUID's constructors or the UUID generator functions to get an initialized UUID.
74 * This is a port of $(LINK2 http://www.boost.org/doc/libs/1_42_0/libs/uuid/uuid.html,
75 * boost.uuid) from the Boost project with some minor additions and API
76 * changes for a more D-like API.
78 * Standards:
79 * $(LINK2 http://www.ietf.org/rfc/rfc4122.txt, RFC 4122)
81 * See_Also:
82 * $(LINK http://en.wikipedia.org/wiki/Universally_unique_identifier)
84 * Copyright: Copyright Johannes Pfau 2011 - .
85 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
86 * Authors: Johannes Pfau
87 * Source: $(PHOBOSSRC std/uuid.d)
89 * Macros:
90 * MYREF2 = <a href="#$2">$(TT $1)</a>&nbsp;
91 * MYREF3 = <a href="#$2">`$1`</a>
93 /* Copyright Johannes Pfau 2011 - 2012.
94 * Distributed under the Boost Software License, Version 1.0.
95 * (See accompanying file LICENSE_1_0.txt or copy at
96 * http://www.boost.org/LICENSE_1_0.txt)
98 module std.uuid;
101 @safe unittest
103 import std.uuid;
105 UUID[] ids;
106 ids ~= randomUUID();
107 ids ~= md5UUID("test.name.123");
108 ids ~= sha1UUID("test.name.123");
110 foreach (entry; ids)
112 assert(entry.variant == UUID.Variant.rfc4122);
114 assert(ids[0].uuidVersion == UUID.Version.randomNumberBased);
115 assert(ids[1].toString() == "22390768-cced-325f-8f0f-cfeaa19d0ccd");
116 assert(ids[1].data == [34, 57, 7, 104, 204, 237, 50, 95, 143, 15, 207,
117 234, 161, 157, 12, 205]);
118 UUID id;
119 assert(id.empty);
122 import std.range.primitives;
123 import std.traits;
128 public struct UUID
130 import std.meta : AliasSeq, allSatisfy;
132 private:
133 alias skipSeq = AliasSeq!(8, 13, 18, 23);
134 alias byteSeq = AliasSeq!(0,2,4,6,9,11,14,16,19,21,24,26,28,30,32,34);
136 @safe pure nothrow @nogc Char toChar(Char)(size_t i) const
138 if (i <= 9)
139 return cast(Char)('0' + i);
140 else
141 return cast(Char)('a' + (i-10));
144 @safe pure nothrow unittest
146 assert(UUID(cast(ubyte[16])[138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45,
147 179, 189, 251, 70]).toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
150 // Reinterpret the UUID as an array of some other primitive.
151 @trusted ref T[16 / T.sizeof] asArrayOf(T)() return
152 if (isIntegral!T)
154 return *cast(typeof(return)*)&data;
157 public:
159 * RFC 4122 defines different internal data layouts for UUIDs. These are
160 * the UUID formats supported by this module. It's
161 * possible to read, compare and use all these Variants, but
162 * UUIDs generated by this module will always be in rfc4122 format.
164 * Note: Do not confuse this with $(REF _Variant, std,_variant).
166 enum Variant
168 ncs, /// NCS backward compatibility
169 rfc4122, /// Defined in RFC 4122 document
170 microsoft, /// Microsoft Corporation backward compatibility
171 future ///Reserved for future use
175 * RFC 4122 defines different UUID versions. The version shows
176 * how a UUID was generated, e.g. a version 4 UUID was generated
177 * from a random number, a version 3 UUID from an MD5 hash of a name.
179 * Note:
180 * All of these UUID versions can be read and processed by
181 * `std.uuid`, but only version 3, 4 and 5 UUIDs can be generated.
183 enum Version
185 ///Unknown version
186 unknown = -1,
187 ///Version 1
188 timeBased = 1,
189 ///Version 2
190 dceSecurity = 2,
191 ///Version 3 (Name based + MD5)
192 nameBasedMD5 = 3,
193 ///Version 4 (Random)
194 randomNumberBased = 4,
195 ///Version 5 (Name based + SHA-1)
196 nameBasedSHA1 = 5
199 union
202 * It is sometimes useful to get or set the 16 bytes of a UUID
203 * directly.
205 * Note:
206 * UUID uses a 16-ubyte representation for the UUID data.
207 * RFC 4122 defines a UUID as a special structure in big-endian
208 * format. These 16-ubytes always equal the big-endian structure
209 * defined in RFC 4122.
211 * Example:
212 * -----------------------------------------------
213 * auto rawData = uuid.data; //get data
214 * rawData[0] = 1; //modify
215 * uuid.data = rawData; //set data
216 * uuid.data[1] = 2; //modify directly
217 * -----------------------------------------------
219 ubyte[16] data;
220 private ulong[2] ulongs;
221 static if (size_t.sizeof == 4)
222 private uint[4] uints;
226 * We could use a union here to also provide access to the
227 * fields specified in RFC 4122, but as we never have to access
228 * those (only necessary for version 1 (and maybe 2) UUIDs),
229 * that is not needed right now.
232 @safe pure unittest
234 UUID tmp;
235 tmp.data = cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,12,
236 13,14,15];
237 assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,
238 12,13,14,15]);
239 tmp.data[2] = 3;
240 assert(tmp.data == cast(ubyte[16])[0,1,3,3,4,5,6,7,8,9,10,11,
241 12,13,14,15]);
243 auto tmp2 = cast(immutable UUID) tmp;
244 assert(tmp2.data == cast(ubyte[16])[0,1,3,3,4,5,6,7,8,9,10,11,
245 12,13,14,15]);
249 * Construct a UUID struct from the 16 byte representation
250 * of a UUID.
252 @safe pure nothrow @nogc this(ref const scope ubyte[16] uuidData)
254 data = uuidData;
256 /// ditto
257 @safe pure nothrow @nogc this(const ubyte[16] uuidData)
259 data = uuidData;
263 @safe pure unittest
265 enum ubyte[16] data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
266 auto uuid = UUID(data);
267 enum ctfe = UUID(data);
268 assert(uuid.data == data);
269 assert(ctfe.data == data);
273 * Construct a UUID struct from the 16 byte representation
274 * of a UUID. Variadic constructor to allow a simpler syntax, see examples.
275 * You need to pass exactly 16 ubytes.
277 @safe pure this(T...)(T uuidData)
278 if (uuidData.length == 16 && allSatisfy!(isIntegral, T))
280 import std.conv : to;
282 foreach (idx, it; uuidData)
284 this.data[idx] = to!ubyte(it);
289 @safe unittest
291 auto tmp = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
292 assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,
293 12,13,14,15]);
296 @safe unittest
298 UUID tmp = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
299 assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,
300 12,13,14,15]);
302 enum UUID ctfeID = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
303 assert(ctfeID == tmp);
305 //Too few arguments
306 assert(!__traits(compiles, typeof(UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14))));
308 //Too many arguments
309 assert(!__traits(compiles, typeof(UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1))));
313 * <a name="UUID(string)"></a>
314 * Parse a UUID from its canonical string form. An UUID in its
315 * canonical form looks like this: 8ab3060e-2cba-4f23-b74c-b52db3bdfb46
317 * Throws:
318 * $(LREF UUIDParsingException) if the input is invalid
320 * CTFE:
321 * This function is supported in CTFE code. Note that error messages
322 * caused by a malformed UUID parsed at compile time can be cryptic,
323 * but errors are detected and reported at
324 * compile time.
326 * Note:
327 * This is a strict parser. It only accepts the pattern above.
328 * It doesn't support any leading or trailing characters. It only
329 * accepts characters used for hex numbers and the string must have
330 * hyphens exactly like above.
332 * For a less strict parser, see $(LREF parseUUID)
334 this(T)(in T[] uuid)
335 if (isSomeChar!T)
337 import std.conv : to, parse;
338 if (uuid.length < 36)
340 throw new UUIDParsingException(to!string(uuid), 0,
341 UUIDParsingException.Reason.tooLittle, "Insufficient Input");
343 if (uuid.length > 36)
345 throw new UUIDParsingException(to!string(uuid), 35, UUIDParsingException.Reason.tooMuch,
346 "Input is too long, need exactly 36 characters");
348 static immutable skipInd = [skipSeq];
349 foreach (pos; skipInd)
350 if (uuid[pos] != '-')
351 throw new UUIDParsingException(to!string(uuid), pos,
352 UUIDParsingException.Reason.invalidChar, "Expected '-'");
354 ubyte[16] data2; //ctfe bug
355 uint pos = void;
357 foreach (i, p; byteSeq)
359 enum uint s = 'a'-10-'0';
360 uint h = uuid[p];
361 uint l = uuid[p+1];
362 pos = p;
363 if (h < '0') goto Lerr;
364 if (l < '0') goto Lerr;
365 if (h > '9')
367 h |= 0x20; //poorman's tolower
368 if (h < 'a') goto Lerr;
369 if (h > 'f') goto Lerr;
370 h -= s;
372 if (l > '9')
374 l |= 0x20; //poorman's tolower
375 if (l < 'a') goto Lerr;
376 if (l > 'f') goto Lerr;
377 l -= s;
379 h -= '0';
380 l -= '0';
382 data2[i] = cast(ubyte)((h << 4) ^ l);
384 this.data = data2;
385 return;
387 Lerr: throw new UUIDParsingException(to!string(uuid), pos,
388 UUIDParsingException.Reason.invalidChar, "Couldn't parse ubyte");
392 @safe pure unittest
394 auto id = UUID("8AB3060E-2cba-4f23-b74c-b52db3bdfb46");
395 assert(id.data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76,
396 181, 45, 179, 189, 251, 70]);
397 assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
399 //Can also be used in CTFE, for example as UUID literals:
400 enum ctfeID = UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
401 //here parsing is done at compile time, no runtime overhead!
404 @safe pure unittest
406 import std.conv : to;
407 import std.exception;
408 import std.meta : AliasSeq;
410 static foreach (S; AliasSeq!(char[], const(char)[], immutable(char)[],
411 wchar[], const(wchar)[], immutable(wchar)[],
412 dchar[], const(dchar)[], immutable(dchar)[],
413 immutable(char[]), immutable(wchar[]), immutable(dchar[])))
415 //Test valid, working cases
416 assert(UUID(to!S("00000000-0000-0000-0000-000000000000")).empty);
418 auto id = UUID(to!S("8AB3060E-2cba-4f23-b74c-b52db3bdfb46"));
419 assert(id.data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76,
420 181, 45, 179, 189, 251, 70]);
421 assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
423 enum UUID ctfe = UUID(to!S("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
424 assert(ctfe == id);
426 assert(UUID(to!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a")).data
427 == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);
429 //Test too short UUIDS
430 auto except = collectException!UUIDParsingException(
431 UUID(to!S("5668122d-9df0-49a4-ad0b-b9b0a57f886")));
432 assert(except && except.reason == UUIDParsingException.Reason.tooLittle);
434 //Test too long UUIDS
435 except = collectException!UUIDParsingException(
436 UUID(to!S("5668122d-9df0-49a4-ad0b-b9b0a57f886aa")));
437 assert(except && except.reason == UUIDParsingException.Reason.tooMuch);
439 //Test dashes
440 except = collectException!UUIDParsingException(
441 UUID(to!S("8ab3060e2cba-4f23-b74c-b52db3bdfb-46")));
442 assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
444 //Test dashes 2
445 except = collectException!UUIDParsingException(
446 UUID(to!S("8ab3-060e2cba-4f23-b74c-b52db3bdfb46")));
447 assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
449 //Test invalid characters
450 //make sure 36 characters in total or we'll get a 'tooMuch' reason
451 except = collectException!UUIDParsingException(
452 UUID(to!S("{8ab3060e-2cba-4f23-b74c-b52db3bdf6}")));
453 assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
455 //Boost test
456 assert(UUID(to!S("01234567-89ab-cdef-0123-456789ABCDEF"))
457 == UUID(cast(ubyte[16])[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0x01,
458 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]));
463 * Returns true if and only if the UUID is equal
464 * to {00000000-0000-0000-0000-000000000000}
466 @trusted pure nothrow @nogc @property bool empty() const
468 if (__ctfe)
469 return data == (ubyte[16]).init;
471 auto p = cast(const(size_t*))data.ptr;
472 static if (size_t.sizeof == 4)
473 return p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0;
474 else static if (size_t.sizeof == 8)
475 return p[0] == 0 && p[1] == 0;
476 else
477 static assert(false, "nonsense, it's not 32 or 64 bit");
481 @safe pure unittest
483 UUID id;
484 assert(id.empty);
485 id = UUID("00000000-0000-0000-0000-000000000001");
486 assert(!id.empty);
489 @safe pure unittest
491 ubyte[16] getData(size_t i)
493 ubyte[16] data;
494 data[i] = 1;
495 return data;
498 for (size_t i = 0; i < 16; i++)
500 assert(!UUID(getData(i)).empty);
503 enum ctfeEmpty = UUID.init.empty;
504 assert(ctfeEmpty);
506 bool ctfeTest()
508 for (size_t i = 0; i < 16; i++)
510 auto ctfeEmpty2 = UUID(getData(i)).empty;
511 assert(!ctfeEmpty2);
513 return true;
515 enum res = ctfeTest();
519 * RFC 4122 defines different internal data layouts for UUIDs.
520 * Returns the format used by this UUID.
522 * Note: Do not confuse this with $(REF _Variant, std,_variant).
523 * The type of this property is $(MYREF3 std.uuid.UUID.Variant, _Variant).
525 * See_Also:
526 * $(MYREF3 UUID.Variant, Variant)
528 @safe pure nothrow @nogc @property Variant variant() const
530 //variant is stored in octet 7
531 //which is index 8, since indexes count backwards
532 immutable octet7 = data[8]; //octet 7 is array index 8
534 if ((octet7 & 0x80) == 0x00) //0b0xxxxxxx
535 return Variant.ncs;
536 else if ((octet7 & 0xC0) == 0x80) //0b10xxxxxx
537 return Variant.rfc4122;
538 else if ((octet7 & 0xE0) == 0xC0) //0b110xxxxx
539 return Variant.microsoft;
540 else
542 //assert((octet7 & 0xE0) == 0xE0, "Unknown UUID variant!") //0b111xxxx
543 return Variant.future;
548 @safe pure unittest
550 assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").variant
551 == UUID.Variant.rfc4122);
553 @system pure unittest
555 // @system due to Variant
556 Variant[ubyte] tests = cast(Variant[ubyte])[0x00 : Variant.ncs,
557 0x10 : Variant.ncs,
558 0x20 : Variant.ncs,
559 0x30 : Variant.ncs,
560 0x40 : Variant.ncs,
561 0x50 : Variant.ncs,
562 0x60 : Variant.ncs,
563 0x70 : Variant.ncs,
564 0x80 : Variant.rfc4122,
565 0x90 : Variant.rfc4122,
566 0xa0 : Variant.rfc4122,
567 0xb0 : Variant.rfc4122,
568 0xc0 : Variant.microsoft,
569 0xd0 : Variant.microsoft,
570 0xe0 : Variant.future,
571 0xf0 : Variant.future];
572 foreach (key, value; tests)
574 UUID u;
575 u.data[8] = key;
576 assert(u.variant == value);
581 * RFC 4122 defines different UUID versions. The version shows
582 * how a UUID was generated, e.g. a version 4 UUID was generated
583 * from a random number, a version 3 UUID from an MD5 hash of a name.
584 * Returns the version used by this UUID.
586 * See_Also:
587 * $(MYREF3 UUID.Version, Version)
589 @safe pure nothrow @nogc @property Version uuidVersion() const
591 //version is stored in octet 9
592 //which is index 6, since indexes count backwards
593 immutable octet9 = data[6];
594 if ((octet9 & 0xF0) == 0x10)
595 return Version.timeBased;
596 else if ((octet9 & 0xF0) == 0x20)
597 return Version.dceSecurity;
598 else if ((octet9 & 0xF0) == 0x30)
599 return Version.nameBasedMD5;
600 else if ((octet9 & 0xF0) == 0x40)
601 return Version.randomNumberBased;
602 else if ((octet9 & 0xF0) == 0x50)
603 return Version.nameBasedSHA1;
604 else
605 return Version.unknown;
609 @safe unittest
611 assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").uuidVersion
612 == UUID.Version.randomNumberBased);
614 @system unittest
616 // @system due to cast
617 Version[ubyte] tests = cast(Version[ubyte]) [
618 0x00 : UUID.Version.unknown,
619 0x10 : UUID.Version.timeBased,
620 0x20 : UUID.Version.dceSecurity,
621 0x30 : UUID.Version.nameBasedMD5,
622 0x40 : UUID.Version.randomNumberBased,
623 0x50 : UUID.Version.nameBasedSHA1,
624 0x60 : UUID.Version.unknown,
625 0x70 : UUID.Version.unknown,
626 0x80 : UUID.Version.unknown,
627 0x90 : UUID.Version.unknown,
628 0xa0 : UUID.Version.unknown,
629 0xb0 : UUID.Version.unknown,
630 0xc0 : UUID.Version.unknown,
631 0xd0 : UUID.Version.unknown,
632 0xe0 : UUID.Version.unknown,
633 0xf0 : UUID.Version.unknown];
634 foreach (key, value; tests)
636 UUID u;
637 u.data[6] = key;
638 assert(u.uuidVersion == value);
643 * Swap the data of this UUID with the data of rhs.
645 @safe pure nothrow @nogc void swap(ref UUID rhs)
647 immutable bck = data;
648 data = rhs.data;
649 rhs.data = bck;
653 @safe unittest
655 immutable ubyte[16] data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
656 UUID u1;
657 UUID u2 = UUID(data);
658 u1.swap(u2);
660 assert(u1 == UUID(data));
661 assert(u2 == UUID.init);
665 * All of the standard numeric operators are defined for
666 * the UUID struct.
668 @safe pure nothrow @nogc bool opEquals(const UUID s) const
670 return ulongs[0] == s.ulongs[0] && ulongs[1] == s.ulongs[1];
674 @safe pure unittest
676 //compare UUIDs
677 assert(UUID("00000000-0000-0000-0000-000000000000") == UUID.init);
679 //UUIDs in associative arrays:
680 int[UUID] test = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0") : 1,
681 UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a") : 2,
682 UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1") : 3];
684 assert(test[UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")] == 3);
686 //UUIDS can be sorted:
687 import std.algorithm;
688 UUID[] ids = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0"),
689 UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a"),
690 UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")];
691 sort(ids);
695 * ditto
697 @safe pure nothrow @nogc bool opEquals(ref const scope UUID s) const
699 return ulongs[0] == s.ulongs[0] && ulongs[1] == s.ulongs[1];
703 * ditto
705 @safe pure nothrow @nogc int opCmp(const UUID s) const
707 import std.algorithm.comparison : cmp;
708 return cmp(this.data[], s.data[]);
712 * ditto
714 @safe pure nothrow @nogc int opCmp(ref const scope UUID s) const
716 import std.algorithm.comparison : cmp;
717 return cmp(this.data[], s.data[]);
721 * ditto
723 @safe pure nothrow @nogc UUID opAssign(const UUID s)
725 ulongs[0] = s.ulongs[0];
726 ulongs[1] = s.ulongs[1];
727 return this;
731 * ditto
733 @safe pure nothrow @nogc UUID opAssign(ref const scope UUID s)
735 ulongs[0] = s.ulongs[0];
736 ulongs[1] = s.ulongs[1];
737 return this;
741 * ditto
743 //MurmurHash2
744 @safe pure nothrow @nogc size_t toHash() const
746 static if (size_t.sizeof == 4)
748 enum uint m = 0x5bd1e995;
749 enum uint n = 16;
750 enum uint r = 24;
752 uint h = n;
754 uint k = uints[0];
755 k *= m;
756 k ^= k >> r;
757 k *= m;
759 h ^= k;
760 h *= m;
762 k = uints[1];
763 k *= m;
764 k ^= k >> r;
765 k *= m;
767 h ^= k;
768 h *= m;
770 k = uints[2];
771 k *= m;
772 k ^= k >> r;
773 k *= m;
775 h ^= k;
776 h *= m;
778 k = uints[3];
779 k *= m;
780 k ^= k >> r;
781 k *= m;
783 h ^= k;
784 h *= m;
786 else
788 enum ulong m = 0xc6a4a7935bd1e995UL;
789 enum ulong n = m * 16;
790 enum uint r = 47;
792 ulong h = n;
794 ulong k = ulongs[0];
795 k *= m;
796 k ^= k >> r;
797 k *= m;
799 h ^= k;
800 h *= m;
802 k = ulongs[1];
803 k *= m;
804 k ^= k >> r;
805 k *= m;
807 h ^= k;
808 h *= m;
810 return h;
812 @safe unittest
814 assert(UUID("00000000-0000-0000-0000-000000000000") == UUID.init);
815 int[UUID] test = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0") : 1,
816 UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a") : 2,
817 UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1") : 3];
819 assert(test[UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")] == 3);
821 import std.algorithm;
822 UUID[] ids = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0"),
823 UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a"),
824 UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")];
825 sort(ids);
826 auto id2 = ids.dup;
828 ids = [UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a"),
829 UUID("8a94f585-d180-44f7-8929-6fca0189c7d0"),
830 UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")];
831 sort(ids);
832 assert(ids == id2);
834 //test comparsion
835 UUID u1;
836 UUID u2 = UUID(cast(ubyte[16])[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
837 UUID u3 = UUID(cast(ubyte[16])[255,255,255,255,255,255,255,255,255,
838 255,255,255,255,255,255,255]);
840 assert(u1 == u1);
842 assert(u1 != u2);
844 assert(u1 < u2);
845 assert(u2 < u3);
847 assert(u1 <= u1);
848 assert(u1 <= u2);
849 assert(u2 <= u3);
851 assert(u2 >= u2);
852 assert(u3 >= u2);
854 assert(u3 >= u3);
855 assert(u2 >= u1);
856 assert(u3 >= u1);
858 // test hash
859 assert(u1.toHash() != u2.toHash());
860 assert(u2.toHash() != u3.toHash());
861 assert(u3.toHash() != u1.toHash());
866 * Write the UUID into `sink` as an ASCII string in the canonical form,
867 * which is 36 characters in the form "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
868 * Params:
869 * sink = OutputRange or writeable array at least 36 entries long
871 void toString(Writer)(scope Writer sink) const
873 char[36] result = void;
874 foreach (pos; skipSeq)
875 result[pos] = '-';
876 foreach (i, pos; byteSeq)
878 const uint entry = this.data[i];
879 const uint hi = entry >> 4;
880 result[pos ] = toChar!char(hi);
881 const uint lo = (entry) & 0x0F;
882 result[pos+1] = toChar!char(lo);
884 static if (!__traits(compiles, put(sink, result[])) || isSomeString!Writer)
886 foreach (i, c; result)
887 sink[i] = cast(typeof(sink[i]))c;
889 else
891 put(sink, result[]);
896 * Return the UUID as a string in the canonical form.
898 @trusted pure nothrow string toString() const
900 import std.exception : assumeUnique;
901 auto result = new char[36];
902 toString(result);
903 return result.assumeUnique;
907 @safe pure unittest
909 immutable str = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46";
910 auto id = UUID(str);
911 assert(id.toString() == str);
914 @safe pure nothrow @nogc unittest
916 import std.meta : AliasSeq;
917 static foreach (Char; AliasSeq!(char, wchar, dchar))
919 alias String = immutable(Char)[];
920 //CTFE
921 enum String s = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46";
922 enum id = UUID(s);
923 static if (is(Char == char))
925 enum p = id.toString();
926 static assert(s == p);
928 //nogc
929 Char[36] str;
930 id.toString(str[]);
931 assert(str == s);
935 @system pure nothrow @nogc unittest
937 // @system due to cast
938 import std.encoding : Char = AsciiChar;
939 enum utfstr = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46";
940 alias String = immutable(Char)[];
941 enum String s = cast(String) utfstr;
942 enum id = UUID(utfstr);
943 //nogc
944 Char[36] str;
945 id.toString(str[]);
946 assert(str == s);
949 @safe unittest
951 auto u1 = UUID(cast(ubyte[16])[138, 179, 6, 14, 44, 186, 79,
952 35, 183, 76, 181, 45, 179, 189, 251, 70]);
953 assert(u1.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
954 u1 = UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
955 assert(u1.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
957 char[] buf;
958 void sink(scope const(char)[] data)
960 buf ~= data;
962 u1.toString(&sink);
963 assert(buf == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
968 @safe unittest
970 UUID id;
971 assert(id.empty);
973 id = randomUUID;
974 assert(!id.empty);
976 id = UUID(cast(ubyte[16]) [138, 179, 6, 14, 44, 186, 79,
977 35, 183, 76, 181, 45, 179, 189, 251, 70]);
978 assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
982 * This function generates a name based (Version 3) UUID from a namespace UUID and a name.
983 * If no namespace UUID was passed, the empty UUID `UUID.init` is used.
985 * Note:
986 * The default namespaces ($(LREF dnsNamespace), ...) defined by
987 * this module should be used when appropriate.
989 * RFC 4122 recommends to use Version 5 UUIDs (SHA-1) instead of Version 3
990 * UUIDs (MD5) for new applications.
992 * CTFE:
993 * CTFE is not supported.
995 * Note:
996 * RFC 4122 isn't very clear on how UUIDs should be generated from names.
997 * It is possible that different implementations return different UUIDs
998 * for the same input, so be warned. The implementation for UTF-8 strings
999 * and byte arrays used by `std.uuid` is compatible with Boost's implementation.
1000 * `std.uuid` guarantees that the same input to this function will generate
1001 * the same output at any time, on any system (this especially means endianness
1002 * doesn't matter).
1004 * Note:
1005 * This function does not provide overloads for wstring and dstring, as
1006 * there's no clear answer on how that should be implemented. It could be
1007 * argued, that string, wstring and dstring input should have the same output,
1008 * but that wouldn't be compatible with Boost, which generates different output
1009 * for strings and wstrings. It's always possible to pass wstrings and dstrings
1010 * by using the ubyte[] function overload (but be aware of endianness issues!).
1012 @safe pure nothrow @nogc UUID md5UUID(const(char[]) name, const UUID namespace = UUID.init)
1014 return md5UUID(cast(const(ubyte[]))name, namespace);
1017 /// ditto
1018 @safe pure nothrow @nogc UUID md5UUID(const(ubyte[]) data, const UUID namespace = UUID.init)
1020 import std.digest.md : MD5;
1022 MD5 hash;
1023 hash.start();
1026 * NOTE: RFC 4122 says namespace should be converted to big-endian.
1027 * We always keep the UUID data in big-endian representation, so
1028 * that's fine
1030 hash.put(namespace.data[]);
1031 hash.put(data[]);
1033 UUID u;
1034 u.data = hash.finish();
1036 //set variant
1037 //must be 0b10xxxxxx
1038 u.data[8] &= 0b10111111;
1039 u.data[8] |= 0b10000000;
1041 //set version
1042 //must be 0b0011xxxx
1043 u.data[6] &= 0b00111111;
1044 u.data[6] |= 0b00110000;
1046 return u;
1050 @safe unittest
1052 //Use default UUID.init namespace
1053 auto simpleID = md5UUID("test.uuid.any.string");
1055 //use a name-based id as namespace
1056 auto namespace = md5UUID("my.app");
1057 auto id = md5UUID("some-description", namespace);
1060 @safe pure unittest
1062 auto simpleID = md5UUID("test.uuid.any.string");
1063 assert(simpleID.data == cast(ubyte[16])[126, 206, 86, 72, 29, 233, 62, 213, 178, 139, 198, 136,
1064 188, 135, 153, 123]);
1065 auto namespace = md5UUID("my.app");
1066 auto id = md5UUID("some-description", namespace);
1067 assert(id.data == cast(ubyte[16])[166, 138, 167, 79, 48, 219, 55, 166, 170, 103, 39, 73, 216,
1068 150, 144, 164]);
1070 auto constTest = md5UUID(cast(const(char)[])"test");
1071 constTest = md5UUID(cast(const(char[]))"test");
1073 char[] mutable = "test".dup;
1074 id = md5UUID(mutable, namespace);
1076 const(ubyte)[] data = cast(ubyte[])[0,1,2,244,165,222];
1077 id = md5UUID(data);
1078 assert(id.data == cast(ubyte[16])[16, 50, 29, 247, 243, 185, 61, 178, 157, 100, 253, 236, 73,
1079 76, 51, 47]);
1081 assert(id.variant == UUID.Variant.rfc4122);
1082 assert(id.uuidVersion == UUID.Version.nameBasedMD5);
1084 auto correct = UUID("3d813cbb-47fb-32ba-91df-831e1593ac29");
1086 auto u = md5UUID("www.widgets.com", dnsNamespace);
1087 //enum ctfeId = md5UUID("www.widgets.com", dnsNamespace);
1088 //assert(ctfeId == u);
1089 assert(u == correct);
1090 assert(u.variant == UUID.Variant.rfc4122);
1091 assert(u.uuidVersion == UUID.Version.nameBasedMD5);
1095 * This function generates a name based (Version 5) UUID from a namespace
1096 * UUID and a name.
1097 * If no namespace UUID was passed, the empty UUID `UUID.init` is used.
1099 * Note:
1100 * The default namespaces ($(LREF dnsNamespace), ...) defined by
1101 * this module should be used when appropriate.
1103 * CTFE:
1104 * CTFE is not supported.
1106 * Note:
1107 * RFC 4122 isn't very clear on how UUIDs should be generated from names.
1108 * It is possible that different implementations return different UUIDs
1109 * for the same input, so be warned. The implementation for UTF-8 strings
1110 * and byte arrays used by `std.uuid` is compatible with Boost's implementation.
1111 * `std.uuid` guarantees that the same input to this function will generate
1112 * the same output at any time, on any system (this especially means endianness
1113 * doesn't matter).
1115 * Note:
1116 * This function does not provide overloads for wstring and dstring, as
1117 * there's no clear answer on how that should be implemented. It could be
1118 * argued, that string, wstring and dstring input should have the same output,
1119 * but that wouldn't be compatible with Boost, which generates different output
1120 * for strings and wstrings. It's always possible to pass wstrings and dstrings
1121 * by using the ubyte[] function overload (but be aware of endianness issues!).
1123 @safe pure nothrow @nogc UUID sha1UUID(scope const(char)[] name, scope const UUID namespace = UUID.init)
1125 return sha1UUID(cast(const(ubyte[]))name, namespace);
1128 /// ditto
1129 @safe pure nothrow @nogc UUID sha1UUID(scope const(ubyte)[] data, scope const UUID namespace = UUID.init)
1131 import std.digest.sha : SHA1;
1133 SHA1 sha;
1134 sha.start();
1137 * NOTE: RFC 4122 says namespace should be converted to big-endian.
1138 * We always keep the UUID data in big-endian representation, so
1139 * that's fine
1141 sha.put(namespace.data[]);
1142 sha.put(data[]);
1144 auto hash = sha.finish();
1145 auto u = UUID();
1146 u.data[] = hash[0 .. 16];
1148 //set variant
1149 //must be 0b10xxxxxx
1150 u.data[8] &= 0b10111111;
1151 u.data[8] |= 0b10000000;
1153 //set version
1154 //must be 0b0101xxxx
1155 u.data[6] &= 0b01011111;
1156 u.data[6] |= 0b01010000;
1158 return u;
1162 @safe unittest
1164 //Use default UUID.init namespace
1165 auto simpleID = sha1UUID("test.uuid.any.string");
1167 //use a name-based id as namespace
1168 auto namespace = sha1UUID("my.app");
1169 auto id = sha1UUID("some-description", namespace);
1172 @safe pure unittest
1174 auto simpleID = sha1UUID("test.uuid.any.string");
1175 assert(simpleID.data == cast(ubyte[16])[16, 209, 239, 61, 99, 12, 94, 70, 159, 79, 255, 250,
1176 131, 79, 14, 147]);
1177 auto namespace = sha1UUID("my.app");
1178 auto id = sha1UUID("some-description", namespace);
1179 assert(id.data == cast(ubyte[16])[225, 94, 195, 219, 126, 75, 83, 71, 157, 52, 247, 43, 238, 248,
1180 148, 46]);
1182 auto constTest = sha1UUID(cast(const(char)[])"test");
1183 constTest = sha1UUID(cast(const(char[]))"test");
1185 char[] mutable = "test".dup;
1186 id = sha1UUID(mutable, namespace);
1188 const(ubyte)[] data = cast(ubyte[])[0,1,2,244,165,222];
1189 id = sha1UUID(data);
1190 assert(id.data == cast(ubyte[16])[60, 65, 92, 240, 96, 46, 95, 238, 149, 100, 12, 64, 199, 194,
1191 243, 12]);
1193 auto correct = UUID("21f7f8de-8051-5b89-8680-0195ef798b6a");
1195 auto u = sha1UUID("www.widgets.com", dnsNamespace);
1196 assert(u == correct);
1197 assert(u.variant == UUID.Variant.rfc4122);
1198 assert(u.uuidVersion == UUID.Version.nameBasedSHA1);
1202 * This function generates a random number based UUID from a random
1203 * number generator.
1205 * This function is not supported at compile time.
1207 * Params:
1208 * randomGen = uniform RNG
1209 * See_Also: $(REF isUniformRNG, std,random)
1211 @nogc nothrow @safe UUID randomUUID()
1213 import std.random : rndGen;
1214 // A PRNG with fewer than `n` bytes of state cannot produce
1215 // every distinct `n` byte sequence.
1216 static if (typeof(rndGen).sizeof >= UUID.sizeof)
1218 return randomUUID(rndGen);
1220 else
1222 import std.random : unpredictableSeed, Xorshift192;
1223 static assert(Xorshift192.sizeof >= UUID.sizeof);
1224 static Xorshift192 rng;
1225 static bool initialized;
1226 if (!initialized)
1228 rng.seed(unpredictableSeed);
1229 initialized = true;
1231 return randomUUID(rng);
1235 /// ditto
1236 UUID randomUUID(RNG)(ref RNG randomGen)
1237 if (isInputRange!RNG && isIntegral!(ElementType!RNG))
1239 import std.random : isUniformRNG;
1240 static assert(isUniformRNG!RNG, "randomGen must be a uniform RNG");
1242 alias E = ElementEncodingType!RNG;
1243 enum size_t elemSize = E.sizeof;
1244 static assert(elemSize <= 16);
1245 static assert(16 % elemSize == 0);
1247 UUID u;
1248 foreach (ref E e ; u.asArrayOf!E())
1250 e = randomGen.front;
1251 randomGen.popFront();
1254 //set variant
1255 //must be 0b10xxxxxx
1256 u.data[8] &= 0b10111111;
1257 u.data[8] |= 0b10000000;
1259 //set version
1260 //must be 0b0100xxxx
1261 u.data[6] &= 0b01001111;
1262 u.data[6] |= 0b01000000;
1264 return u;
1268 @safe unittest
1270 import std.random : Xorshift192, unpredictableSeed;
1272 //simple call
1273 auto uuid = randomUUID();
1275 //provide a custom RNG. Must be seeded manually.
1276 Xorshift192 gen;
1278 gen.seed(unpredictableSeed);
1279 auto uuid3 = randomUUID(gen);
1282 @safe unittest
1284 import std.random : Xorshift192, unpredictableSeed;
1285 //simple call
1286 auto uuid = randomUUID();
1288 //provide a custom RNG. Must be seeded manually.
1289 Xorshift192 gen;
1290 gen.seed(unpredictableSeed);
1291 auto uuid3 = randomUUID(gen);
1293 auto u1 = randomUUID();
1294 auto u2 = randomUUID();
1295 assert(u1 != u2);
1296 assert(u1.variant == UUID.Variant.rfc4122);
1297 assert(u1.uuidVersion == UUID.Version.randomNumberBased);
1301 * This is a less strict parser compared to the parser used in the
1302 * UUID constructor. It enforces the following rules:
1304 * $(UL
1305 * $(LI hex numbers are always two hexdigits([0-9a-fA-F]))
1306 * $(LI there must be exactly 16 such pairs in the input, not less, not more)
1307 * $(LI there can be exactly one dash between two hex-pairs, but not more)
1308 * $(LI there can be multiple characters enclosing the 16 hex pairs,
1309 * as long as these characters do not contain [0-9a-fA-F])
1312 * Note:
1313 * Like most parsers, it consumes its argument. This means:
1314 * -------------------------
1315 * string s = "8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46";
1316 * parseUUID(s);
1317 * assert(s == "");
1318 * -------------------------
1320 * Throws:
1321 * $(LREF UUIDParsingException) if the input is invalid
1323 * CTFE:
1324 * This function is supported in CTFE code. Note that error messages
1325 * caused by a malformed UUID parsed at compile time can be cryptic,
1326 * but errors are detected and reported at compile time.
1328 UUID parseUUID(T)(T uuidString)
1329 if (isSomeString!T)
1331 return parseUUID(uuidString);
1334 ///ditto
1335 UUID parseUUID(Range)(ref Range uuidRange)
1336 if (isInputRange!Range && isSomeChar!(ElementType!Range))
1338 import std.ascii : isHexDigit;
1339 import std.conv : ConvException, parse;
1341 static if (isForwardRange!Range)
1342 auto errorCopy = uuidRange.save;
1344 void parserError()(size_t pos, UUIDParsingException.Reason reason, string message, Throwable next = null,
1345 string file = __FILE__, size_t line = __LINE__)
1347 static if (isForwardRange!Range)
1349 import std.conv : to;
1350 static if (isInfinite!Range)
1352 throw new UUIDParsingException(to!string(take(errorCopy, pos)), pos, reason, message,
1353 next, file, line);
1355 else
1357 throw new UUIDParsingException(to!string(errorCopy), pos, reason, message, next, file,
1358 line);
1361 else
1363 throw new UUIDParsingException("", pos, reason, message, next, file, line);
1367 static if (hasLength!Range)
1369 import std.conv : to;
1370 if (uuidRange.length < 32)
1372 throw new UUIDParsingException(to!string(uuidRange), 0, UUIDParsingException.Reason.tooLittle,
1373 "Insufficient Input");
1377 UUID result;
1378 size_t consumed;
1379 size_t element = 0;
1381 //skip garbage
1382 size_t skip()()
1384 size_t skipped;
1385 while (!uuidRange.empty && !isHexDigit(uuidRange.front))
1387 skipped++;
1388 uuidRange.popFront();
1390 return skipped;
1393 consumed += skip();
1395 if (uuidRange.empty)
1396 parserError(consumed, UUIDParsingException.Reason.tooLittle, "Insufficient Input");
1398 bool dashAllowed = false;
1400 parseLoop: while (!uuidRange.empty)
1402 immutable character = uuidRange.front;
1404 if (character == '-')
1406 if (!dashAllowed)
1407 parserError(consumed, UUIDParsingException.Reason.invalidChar, "Unexpected '-'");
1408 else
1409 dashAllowed = false;
1411 consumed++;
1413 else if (!isHexDigit(character))
1415 parserError(consumed, UUIDParsingException.Reason.invalidChar,
1416 "Unexpected character (wanted a hexDigit)");
1418 else
1422 consumed += 2;
1423 static if (isSomeString!Range)
1425 if (uuidRange.length < 2)
1427 parserError(consumed, UUIDParsingException.Reason.tooLittle,
1428 "Insufficient Input");
1430 auto part = uuidRange[0 .. 2];
1431 result.data[element++] = parse!ubyte(part, 16);
1432 uuidRange.popFront();
1434 else
1436 dchar[2] copyBuf;
1437 copyBuf[0] = character;
1438 uuidRange.popFront();
1439 if (uuidRange.empty)
1441 parserError(consumed, UUIDParsingException.Reason.tooLittle,
1442 "Insufficient Input");
1444 copyBuf[1] = uuidRange.front;
1445 auto part = copyBuf[];
1446 result.data[element++] = parse!ubyte(part, 16);
1449 if (element == 16)
1451 uuidRange.popFront();
1452 break parseLoop;
1455 dashAllowed = true;
1457 catch (ConvException e)
1459 parserError(consumed, UUIDParsingException.Reason.invalidChar,
1460 "Couldn't parse ubyte", e);
1463 uuidRange.popFront();
1465 assert(element <= 16);
1467 if (element < 16)
1468 parserError(consumed, UUIDParsingException.Reason.tooLittle, "Insufficient Input");
1470 consumed += skip();
1471 if (!uuidRange.empty)
1472 parserError(consumed, UUIDParsingException.Reason.invalidChar, "Unexpected character");
1474 return result;
1478 @safe unittest
1480 auto id = parseUUID("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46");
1481 //no dashes
1482 id = parseUUID("8ab3060e2cba4f23b74cb52db3bdfb46");
1483 //dashes at different positions
1484 id = parseUUID("8a-b3-06-0e2cba4f23b74c-b52db3bdfb-46");
1485 //leading / trailing characters
1486 id = parseUUID("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}");
1487 //unicode
1488 id = parseUUID("ü8ab3060e2cba4f23b74cb52db3bdfb46ü");
1489 //multiple trailing/leading characters
1490 id = parseUUID("///8ab3060e2cba4f23b74cb52db3bdfb46||");
1492 //Can also be used in CTFE, for example as UUID literals:
1493 enum ctfeID = parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
1494 //here parsing is done at compile time, no runtime overhead!
1497 @safe pure unittest
1499 import std.conv : to;
1500 import std.exception;
1501 import std.meta;
1503 struct TestRange(bool forward)
1505 dstring input;
1507 @property dchar front()
1509 return input.front;
1512 void popFront()
1514 input.popFront();
1517 @property bool empty()
1519 return input.empty;
1522 static if (forward)
1524 @property TestRange!true save()
1526 return this;
1530 alias TestInputRange = TestRange!false;
1531 alias TestForwardRange = TestRange!true;
1533 assert(isInputRange!TestInputRange);
1534 assert(is(ElementType!TestInputRange == dchar));
1535 assert(isInputRange!TestForwardRange);
1536 assert(isForwardRange!TestForwardRange);
1537 assert(is(ElementType!TestForwardRange == dchar));
1539 //Helper function for unittests - Need to pass ranges by ref
1540 UUID parseHelper(T)(string input)
1542 static if (is(T == TestInputRange) || is(T == TestForwardRange))
1544 T range = T(to!dstring(input));
1545 return parseUUID(range);
1547 else
1548 return parseUUID(to!T(input));
1551 static foreach (S; AliasSeq!(char[], const(char)[], immutable(char)[],
1552 wchar[], const(wchar)[], immutable(wchar)[],
1553 dchar[], const(dchar)[], immutable(dchar)[],
1554 immutable(char[]), immutable(wchar[]), immutable(dchar[]),
1555 TestForwardRange, TestInputRange))
1557 //Verify examples.
1558 auto id = parseHelper!S("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46");
1559 //no dashes
1560 id = parseHelper!S("8ab3060e2cba4f23b74cb52db3bdfb46");
1561 //dashes at different positions
1562 id = parseHelper!S("8a-b3-06-0e2cba4f23b74c-b52db3bdfb-46");
1563 //leading / trailing characters
1564 id = parseHelper!S("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}");
1565 //unicode
1566 id = parseHelper!S("ü8ab3060e2cba4f23b74cb52db3bdfb46ü");
1567 //multiple trailing/leading characters
1568 id = parseHelper!S("///8ab3060e2cba4f23b74cb52db3bdfb46||");
1569 enum ctfeId = parseHelper!S("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
1570 assert(parseHelper!S("8AB3060E-2cba-4f23-b74c-b52db3bdfb46") == ctfeId);
1572 //Test valid, working cases
1573 assert(parseHelper!S("00000000-0000-0000-0000-000000000000").empty);
1574 assert(parseHelper!S("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46").data
1575 == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45, 179, 189, 251, 70]);
1577 assert(parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a").data
1578 == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);
1580 //wstring / dstring
1581 assert(parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a").data
1582 == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);
1583 assert(parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a").data
1584 == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);
1586 //Test too short UUIDS
1587 auto except = collectException!UUIDParsingException(
1588 parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886"));
1589 assert(except && except.reason == UUIDParsingException.Reason.tooLittle);
1591 //Test too long UUIDS
1592 except = collectException!UUIDParsingException(
1593 parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886aa"));
1594 assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
1596 //Test too long UUIDS 2
1597 except = collectException!UUIDParsingException(
1598 parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a-aa"));
1599 assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
1601 //Test dashes
1602 assert(parseHelper!S("8ab3060e2cba-4f23-b74c-b52db3bdfb46")
1603 == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1604 assert(parseHelper!S("8ab3-060e2cba-4f23-b74c-b52db3bdfb46")
1605 == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1606 assert(parseHelper!S("8ab3060e2cba4f23b74cb52db3bdfb46")
1607 == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1609 except = collectException!UUIDParsingException(
1610 parseHelper!S("8-ab3060e2cba-4f23-b74c-b52db3bdfb46"));
1611 assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
1613 //Test leading/trailing characters
1614 assert(parseHelper!S("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}")
1615 == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1616 assert(parseHelper!S("{8ab3060e2cba4f23b74cb52db3bdfb46}")
1617 == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1619 //Boost test
1620 auto u_increasing = UUID(cast(ubyte[16])[0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
1621 0xcd, 0xef,0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
1622 assert(parseHelper!S("0123456789abcdef0123456789ABCDEF") == UUID(cast(ubyte[16])[0x01,
1623 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]));
1625 //unicode
1626 assert(parseHelper!S("ü8ab3060e2cba4f23b74cb52db3bdfb46ü")
1627 == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1629 //multiple trailing/leading characters
1630 assert(parseHelper!S("///8ab3060e2cba4f23b74cb52db3bdfb46||")
1631 == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1634 // Test input range with non-dchar element type.
1636 import std.utf : byCodeUnit;
1637 auto range = "8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46".byCodeUnit;
1638 assert(parseUUID(range).data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45, 179, 189, 251, 70]);
1643 * Default namespace from RFC 4122
1645 * Name string is a fully-qualified domain name
1647 enum dnsNamespace = UUID("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
1650 * Default namespace from RFC 4122
1652 * Name string is a URL
1654 enum urlNamespace = UUID("6ba7b811-9dad-11d1-80b4-00c04fd430c8");
1657 * Default namespace from RFC 4122
1659 * Name string is an ISO OID
1661 enum oidNamespace = UUID("6ba7b812-9dad-11d1-80b4-00c04fd430c8");
1664 * Default namespace from RFC 4122
1666 * Name string is an X.500 DN (in DER or a text output format)
1668 enum x500Namespace = UUID("6ba7b814-9dad-11d1-80b4-00c04fd430c8");
1671 * Regex string to extract UUIDs from text.
1673 enum uuidRegex = "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}"~
1674 "-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}";
1677 @safe unittest
1679 import std.algorithm;
1680 import std.regex;
1682 string test = "Lorem ipsum dolor sit amet, consetetur "~
1683 "6ba7b814-9dad-11d1-80b4-00c04fd430c8 sadipscing \n"~
1684 "elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore \r\n"~
1685 "magna aliquyam erat, sed diam voluptua. "~
1686 "8ab3060e-2cba-4f23-b74c-b52db3bdfb46 At vero eos et accusam et "~
1687 "justo duo dolores et ea rebum.";
1689 auto r = regex(uuidRegex, "g");
1690 UUID[] found;
1691 foreach (c; match(test, r))
1693 found ~= UUID(c.hit);
1695 assert(found == [
1696 UUID("6ba7b814-9dad-11d1-80b4-00c04fd430c8"),
1697 UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"),
1702 * This exception is thrown if an error occurs when parsing a UUID
1703 * from a string.
1705 public class UUIDParsingException : Exception
1708 * The reason why parsing the UUID string failed (if known)
1710 enum Reason
1712 unknown, ///
1713 tooLittle, ///The passed in input was correct, but more input was expected.
1714 tooMuch, ///The input data is too long (There's no guarantee the first part of the data is valid)
1715 invalidChar, ///Encountered an invalid character
1718 ///ditto
1719 Reason reason;
1720 ///The original input string which should have been parsed.
1721 string input;
1722 ///The position in the input string where the error occurred.
1723 size_t position;
1725 private this(string input, size_t pos, Reason why = Reason.unknown, string msg = "",
1726 Throwable next = null, string file = __FILE__, size_t line = __LINE__) pure @trusted
1728 import std.array : replace;
1729 import std.format : format;
1730 this.input = input;
1731 this.position = pos;
1732 this.reason = why;
1733 string message = format("An error occured in the UUID parser: %s\n" ~
1734 " * Input:\t'%s'\n * Position:\t%s", msg, replace(replace(input,
1735 "\r", "\\r"), "\n", "\\n"), pos);
1736 super(message, file, line, next);
1741 @safe unittest
1743 import std.exception : collectException;
1745 const inputUUID = "this-is-an-invalid-uuid";
1746 auto ex = collectException!UUIDParsingException(UUID(inputUUID));
1747 assert(ex !is null); // check that exception was thrown
1748 assert(ex.input == inputUUID);
1749 assert(ex.position == 0);
1750 assert(ex.reason == UUIDParsingException.Reason.tooLittle);
1753 @safe unittest
1755 auto ex = new UUIDParsingException("foo", 10, UUIDParsingException.Reason.tooMuch);
1756 assert(ex.input == "foo");
1757 assert(ex.position == 10);
1758 assert(ex.reason == UUIDParsingException.Reason.tooMuch);