The OpenD Programming Language

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.
8  *
9 $(SCRIPT inhibitQuickIndex = 1;)
10 
11 $(DIVC quickindex,
12 $(BOOKTABLE ,
13 $(TR $(TH Category) $(TH Functions)
14 )
15 $(TR $(TDNW Parsing UUIDs)
16      $(TD $(MYREF parseUUID)
17           $(MYREF UUID)
18           $(MYREF UUIDParsingException)
19           $(MYREF uuidRegex)
20           )
21      )
22 $(TR $(TDNW Generating UUIDs)
23      $(TD $(MYREF sha1UUID)
24           $(MYREF randomUUID)
25           $(MYREF md5UUID)
26           )
27      )
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)
37           )
38      )
39 $(TR $(TDNW UUID namespaces)
40      $(TD $(MYREF dnsNamespace)
41           $(MYREF urlNamespace)
42           $(MYREF oidNamespace)
43           $(MYREF x500Namespace)
44           )
45      )
46 )
47 )
48 
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).
59  *
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.
63  *
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).
68  *
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.
73  *
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.
77  *
78  * Standards:
79  * $(LINK2 http://www.ietf.org/rfc/rfc4122.txt, RFC 4122)
80  *
81  * See_Also:
82  * $(LINK http://en.wikipedia.org/wiki/Universally_unique_identifier)
83  *
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)
88  *
89  * Macros:
90  * MYREF2 = <a href="#$2">$(TT $1)</a>&nbsp;
91  * MYREF3 = <a href="#$2">`$1`</a>
92  */
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)
97  */
98 module std.uuid;
99 
100 ///
101 @safe unittest
102 {
103     import std.uuid;
104 
105     UUID[] ids;
106     ids ~= randomUUID();
107     ids ~= md5UUID("test.name.123");
108     ids ~= sha1UUID("test.name.123");
109 
110     foreach (entry; ids)
111     {
112         assert(entry.variant == UUID.Variant.rfc4122);
113     }
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);
120 }
121 
122 import std.range.primitives;
123 import std.traits;
124 
125 /**
126  *
127  */
128 public struct UUID
129 {
130     import std.meta : AliasSeq, allSatisfy;
131 
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);
135 
136         @safe pure nothrow @nogc Char toChar(Char)(size_t i) const
137         {
138             if (i <= 9)
139                 return cast(Char)('0' + i);
140             else
141                 return cast(Char)('a' + (i-10));
142         }
143 
144         @safe pure nothrow unittest
145         {
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");
148         }
149 
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)
153         {
154             return *cast(typeof(return)*)&data;
155         }
156 
157     public:
158         /**
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.
163          *
164          * Note: Do not confuse this with $(REF _Variant, std,_variant).
165          */
166         enum Variant
167         {
168             ncs, /// NCS backward compatibility
169             rfc4122, /// Defined in RFC 4122 document
170             microsoft, /// Microsoft Corporation backward compatibility
171             future ///Reserved for future use
172         }
173 
174         /**
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.
178          *
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.
182          */
183         enum Version
184         {
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
197         }
198 
199         union
200         {
201             /**
202              * It is sometimes useful to get or set the 16 bytes of a UUID
203              * directly.
204              *
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.
210              *
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              * -----------------------------------------------
218              */
219             ubyte[16] data;
220             private ulong[2] ulongs;
221             static if (size_t.sizeof == 4)
222                 private uint[4] uints;
223         }
224 
225         /*
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.
230          */
231 
232         @safe pure unittest
233         {
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]);
242 
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]);
246         }
247 
248         /**
249          * Construct a UUID struct from the 16 byte representation
250          * of a UUID.
251          */
252         @safe pure nothrow @nogc this(ref const scope ubyte[16] uuidData)
253         {
254             data = uuidData;
255         }
256         /// ditto
257         @safe pure nothrow @nogc this(const ubyte[16] uuidData)
258         {
259             data = uuidData;
260         }
261 
262         ///
263         @safe pure unittest
264         {
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);
270         }
271 
272         /**
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.
276          */
277         @safe pure this(T...)(T uuidData)
278             if (uuidData.length == 16 && allSatisfy!(isIntegral, T))
279         {
280             import std.conv : to;
281 
282             foreach (idx, it; uuidData)
283             {
284                 this.data[idx] = to!ubyte(it);
285             }
286         }
287 
288         ///
289         @safe unittest
290         {
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]);
294         }
295 
296         @safe unittest
297         {
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]);
301 
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);
304 
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))));
307 
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))));
310         }
311 
312         /**
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
316          *
317          * Throws:
318          * $(LREF UUIDParsingException) if the input is invalid
319          *
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.
325          *
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.
331          *
332          * For a less strict parser, see $(LREF parseUUID)
333          */
334         this(T)(in T[] uuid) if (isSomeChar!T)
335         {
336             import std.conv : to, parse;
337             if (uuid.length < 36)
338             {
339                 throw new UUIDParsingException(to!string(uuid), 0,
340                     UUIDParsingException.Reason.tooLittle, "Insufficient Input");
341             }
342             if (uuid.length > 36)
343             {
344                 throw new UUIDParsingException(to!string(uuid), 35, UUIDParsingException.Reason.tooMuch,
345                     "Input is too long, need exactly 36 characters");
346             }
347             static immutable skipInd = [skipSeq];
348             foreach (pos; skipInd)
349                 if (uuid[pos] != '-')
350                     throw new UUIDParsingException(to!string(uuid), pos,
351                         UUIDParsingException.Reason.invalidChar, "Expected '-'");
352 
353             ubyte[16] data2; //ctfe bug
354             uint pos = void;
355 
356             foreach (i, p; byteSeq)
357             {
358                 enum uint s = 'a'-10-'0';
359                 uint h = uuid[p];
360                 uint l = uuid[p+1];
361                 pos = p;
362                 if (h < '0') goto Lerr;
363                 if (l < '0') goto Lerr;
364                 if (h > '9')
365                 {
366                     h |= 0x20; //poorman's tolower
367                     if (h < 'a') goto Lerr;
368                     if (h > 'f') goto Lerr;
369                     h -= s;
370                 }
371                 if (l > '9')
372                 {
373                     l |= 0x20; //poorman's tolower
374                     if (l < 'a') goto Lerr;
375                     if (l > 'f') goto Lerr;
376                     l -= s;
377                 }
378                 h -= '0';
379                 l -= '0';
380 
381                 data2[i] = cast(ubyte)((h << 4) ^ l);
382             }
383             this.data = data2;
384             return;
385 
386         Lerr: throw new UUIDParsingException(to!string(uuid), pos,
387                 UUIDParsingException.Reason.invalidChar, "Couldn't parse ubyte");
388         }
389 
390         ///
391         @safe pure unittest
392         {
393             auto id = UUID("8AB3060E-2cba-4f23-b74c-b52db3bdfb46");
394             assert(id.data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76,
395                181, 45, 179, 189, 251, 70]);
396             assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
397 
398             //Can also be used in CTFE, for example as UUID literals:
399             enum ctfeID = UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
400             //here parsing is done at compile time, no runtime overhead!
401         }
402 
403         @safe pure unittest
404         {
405             import std.conv : to;
406             import std.exception;
407             import std.meta : AliasSeq;
408 
409             static foreach (S; AliasSeq!(char[], const(char)[], immutable(char)[],
410                                   wchar[], const(wchar)[], immutable(wchar)[],
411                                   dchar[], const(dchar)[], immutable(dchar)[],
412                                   immutable(char[]), immutable(wchar[]), immutable(dchar[])))
413             {{
414                 //Test valid, working cases
415                 assert(UUID(to!S("00000000-0000-0000-0000-000000000000")).empty);
416 
417                 auto id = UUID(to!S("8AB3060E-2cba-4f23-b74c-b52db3bdfb46"));
418                 assert(id.data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76,
419                     181, 45, 179, 189, 251, 70]);
420                 assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
421 
422                 enum UUID ctfe = UUID(to!S("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
423                 assert(ctfe == id);
424 
425                 assert(UUID(to!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a")).data
426                     == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);
427 
428                 //Test too short UUIDS
429                 auto except = collectException!UUIDParsingException(
430                     UUID(to!S("5668122d-9df0-49a4-ad0b-b9b0a57f886")));
431                 assert(except && except.reason == UUIDParsingException.Reason.tooLittle);
432 
433                 //Test too long UUIDS
434                 except = collectException!UUIDParsingException(
435                     UUID(to!S("5668122d-9df0-49a4-ad0b-b9b0a57f886aa")));
436                 assert(except && except.reason == UUIDParsingException.Reason.tooMuch);
437 
438                 //Test dashes
439                 except = collectException!UUIDParsingException(
440                     UUID(to!S("8ab3060e2cba-4f23-b74c-b52db3bdfb-46")));
441                 assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
442 
443                 //Test dashes 2
444                 except = collectException!UUIDParsingException(
445                     UUID(to!S("8ab3-060e2cba-4f23-b74c-b52db3bdfb46")));
446                 assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
447 
448                 //Test invalid characters
449                 //make sure 36 characters in total or we'll get a 'tooMuch' reason
450                 except = collectException!UUIDParsingException(
451                     UUID(to!S("{8ab3060e-2cba-4f23-b74c-b52db3bdf6}")));
452                 assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
453 
454                 //Boost test
455                 assert(UUID(to!S("01234567-89ab-cdef-0123-456789ABCDEF"))
456                     == UUID(cast(ubyte[16])[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0x01,
457                     0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]));
458             }
459         }}
460 
461         /**
462          * Returns true if and only if the UUID is equal
463          * to {00000000-0000-0000-0000-000000000000}
464          */
465         @trusted pure nothrow @nogc @property bool empty() const
466         {
467             if (__ctfe)
468                 return data == (ubyte[16]).init;
469 
470             auto p = cast(const(size_t*))data.ptr;
471             static if (size_t.sizeof == 4)
472                 return p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0;
473             else static if (size_t.sizeof == 8)
474                 return p[0] == 0 && p[1] == 0;
475             else
476                 static assert(false, "nonsense, it's not 32 or 64 bit");
477         }
478 
479         ///
480         @safe pure unittest
481         {
482             UUID id;
483             assert(id.empty);
484             id = UUID("00000000-0000-0000-0000-000000000001");
485             assert(!id.empty);
486         }
487 
488         @safe pure unittest
489         {
490             ubyte[16] getData(size_t i)
491             {
492                 ubyte[16] data;
493                 data[i] = 1;
494                 return data;
495             }
496 
497             for (size_t i = 0; i < 16; i++)
498             {
499                 assert(!UUID(getData(i)).empty);
500             }
501 
502             enum ctfeEmpty = UUID.init.empty;
503             assert(ctfeEmpty);
504 
505             bool ctfeTest()
506             {
507                 for (size_t i = 0; i < 16; i++)
508                 {
509                     auto ctfeEmpty2 = UUID(getData(i)).empty;
510                     assert(!ctfeEmpty2);
511                 }
512                 return true;
513             }
514             enum res = ctfeTest();
515         }
516 
517         /**
518          * RFC 4122 defines different internal data layouts for UUIDs.
519          * Returns the format used by this UUID.
520          *
521          * Note: Do not confuse this with $(REF _Variant, std,_variant).
522          * The type of this property is $(MYREF3 std.uuid.UUID.Variant, _Variant).
523          *
524          * See_Also:
525          * $(MYREF3 UUID.Variant, Variant)
526          */
527         @safe pure nothrow @nogc @property Variant variant() const
528         {
529             //variant is stored in octet 7
530             //which is index 8, since indexes count backwards
531             immutable octet7 = data[8]; //octet 7 is array index 8
532 
533             if ((octet7 & 0x80) == 0x00) //0b0xxxxxxx
534                 return Variant.ncs;
535             else if ((octet7 & 0xC0) == 0x80) //0b10xxxxxx
536                 return Variant.rfc4122;
537             else if ((octet7 & 0xE0) == 0xC0) //0b110xxxxx
538                 return Variant.microsoft;
539             else
540             {
541                 //assert((octet7 & 0xE0) == 0xE0, "Unknown UUID variant!") //0b111xxxx
542                 return Variant.future;
543             }
544         }
545 
546         ///
547         @safe pure unittest
548         {
549             assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").variant
550                == UUID.Variant.rfc4122);
551         }
552         @system pure unittest
553         {
554             // @system due to Variant
555             Variant[ubyte] tests = cast(Variant[ubyte])[0x00 : Variant.ncs,
556                                     0x10 : Variant.ncs,
557                                     0x20 : Variant.ncs,
558                                     0x30 : Variant.ncs,
559                                     0x40 : Variant.ncs,
560                                     0x50 : Variant.ncs,
561                                     0x60 : Variant.ncs,
562                                     0x70 : Variant.ncs,
563                                     0x80 : Variant.rfc4122,
564                                     0x90 : Variant.rfc4122,
565                                     0xa0 : Variant.rfc4122,
566                                     0xb0 : Variant.rfc4122,
567                                     0xc0 : Variant.microsoft,
568                                     0xd0 : Variant.microsoft,
569                                     0xe0 : Variant.future,
570                                     0xf0 : Variant.future];
571             foreach (key, value; tests)
572             {
573                 UUID u;
574                 u.data[8] = key;
575                 assert(u.variant == value);
576             }
577         }
578 
579         /**
580          * RFC 4122 defines different UUID versions. The version shows
581          * how a UUID was generated, e.g. a version 4 UUID was generated
582          * from a random number, a version 3 UUID from an MD5 hash of a name.
583          * Returns the version used by this UUID.
584          *
585          * See_Also:
586          * $(MYREF3 UUID.Version, Version)
587          */
588         @safe pure nothrow @nogc @property Version uuidVersion() const
589         {
590             //version is stored in octet 9
591             //which is index 6, since indexes count backwards
592             immutable octet9 = data[6];
593             if ((octet9 & 0xF0) == 0x10)
594                 return Version.timeBased;
595             else if ((octet9 & 0xF0) == 0x20)
596                 return Version.dceSecurity;
597             else if ((octet9 & 0xF0) == 0x30)
598                 return Version.nameBasedMD5;
599             else if ((octet9 & 0xF0) == 0x40)
600                 return Version.randomNumberBased;
601             else if ((octet9 & 0xF0) == 0x50)
602                 return Version.nameBasedSHA1;
603             else
604                 return Version.unknown;
605         }
606 
607         ///
608         @safe unittest
609         {
610             assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").uuidVersion
611                 == UUID.Version.randomNumberBased);
612         }
613         @system unittest
614         {
615             // @system due to cast
616             Version[ubyte] tests = cast(Version[ubyte]) [
617                 0x00 : UUID.Version.unknown,
618                 0x10 : UUID.Version.timeBased,
619                 0x20 : UUID.Version.dceSecurity,
620                 0x30 : UUID.Version.nameBasedMD5,
621                 0x40 : UUID.Version.randomNumberBased,
622                 0x50 : UUID.Version.nameBasedSHA1,
623                 0x60 : UUID.Version.unknown,
624                 0x70 : UUID.Version.unknown,
625                 0x80 : UUID.Version.unknown,
626                 0x90 : UUID.Version.unknown,
627                 0xa0 : UUID.Version.unknown,
628                 0xb0 : UUID.Version.unknown,
629                 0xc0 : UUID.Version.unknown,
630                 0xd0 : UUID.Version.unknown,
631                 0xe0 : UUID.Version.unknown,
632                 0xf0 : UUID.Version.unknown];
633             foreach (key, value; tests)
634             {
635                 UUID u;
636                 u.data[6] = key;
637                 assert(u.uuidVersion == value);
638             }
639         }
640 
641         /**
642          * Swap the data of this UUID with the data of rhs.
643          */
644         @safe pure nothrow @nogc void swap(ref UUID rhs)
645         {
646             immutable bck = data;
647             data = rhs.data;
648             rhs.data = bck;
649         }
650 
651         ///
652         @safe unittest
653         {
654             immutable ubyte[16] data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
655             UUID u1;
656             UUID u2 = UUID(data);
657             u1.swap(u2);
658 
659             assert(u1 == UUID(data));
660             assert(u2 == UUID.init);
661         }
662 
663         /**
664          * All of the standard numeric operators are defined for
665          * the UUID struct.
666          */
667         @safe pure nothrow @nogc bool opEquals(const UUID s) const
668         {
669             return ulongs[0] == s.ulongs[0] && ulongs[1] == s.ulongs[1];
670         }
671 
672         ///
673         @safe pure unittest
674         {
675             //compare UUIDs
676             assert(UUID("00000000-0000-0000-0000-000000000000") == UUID.init);
677 
678             //UUIDs in associative arrays:
679             int[UUID] test = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0") : 1,
680                 UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a") : 2,
681                 UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1") : 3];
682 
683             assert(test[UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")] == 3);
684 
685             //UUIDS can be sorted:
686             import std.algorithm;
687             UUID[] ids = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0"),
688                           UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a"),
689                           UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")];
690             sort(ids);
691         }
692 
693         /**
694          * ditto
695          */
696         @safe pure nothrow @nogc bool opEquals(ref const scope UUID s) const
697         {
698             return ulongs[0] == s.ulongs[0] && ulongs[1] == s.ulongs[1];
699         }
700 
701         /**
702          * ditto
703          */
704         @safe pure nothrow @nogc int opCmp(const UUID s) const
705         {
706             import std.algorithm.comparison : cmp;
707             return cmp(this.data[], s.data[]);
708         }
709 
710         /**
711          * ditto
712          */
713         @safe pure nothrow @nogc int opCmp(ref const scope UUID s) const
714         {
715             import std.algorithm.comparison : cmp;
716             return cmp(this.data[], s.data[]);
717         }
718 
719         /**
720          * ditto
721          */
722        @safe pure nothrow @nogc UUID opAssign(const UUID s)
723         {
724             ulongs[0] = s.ulongs[0];
725             ulongs[1] = s.ulongs[1];
726             return this;
727         }
728 
729         /**
730          * ditto
731          */
732         @safe pure nothrow @nogc UUID opAssign(ref const scope UUID s)
733         {
734             ulongs[0] = s.ulongs[0];
735             ulongs[1] = s.ulongs[1];
736             return this;
737         }
738 
739         /**
740          * ditto
741          */
742         //MurmurHash2
743         @safe pure nothrow @nogc size_t toHash() const
744         {
745             static if (size_t.sizeof == 4)
746             {
747                 enum uint m = 0x5bd1e995;
748                 enum uint n = 16;
749                 enum uint r = 24;
750 
751                 uint h = n;
752 
753                 uint k = uints[0];
754                 k *= m;
755                 k ^= k >> r;
756                 k *= m;
757 
758                 h ^= k;
759                 h *= m;
760 
761                 k = uints[1];
762                 k *= m;
763                 k ^= k >> r;
764                 k *= m;
765 
766                 h ^= k;
767                 h *= m;
768 
769                 k = uints[2];
770                 k *= m;
771                 k ^= k >> r;
772                 k *= m;
773 
774                 h ^= k;
775                 h *= m;
776 
777                 k = uints[3];
778                 k *= m;
779                 k ^= k >> r;
780                 k *= m;
781 
782                 h ^= k;
783                 h *= m;
784             }
785             else
786             {
787                 enum ulong m = 0xc6a4a7935bd1e995UL;
788                 enum ulong n = m * 16;
789                 enum uint r = 47;
790 
791                 ulong h = n;
792 
793                 ulong k = ulongs[0];
794                 k *= m;
795                 k ^= k >> r;
796                 k *= m;
797 
798                 h ^= k;
799                 h *= m;
800 
801                 k = ulongs[1];
802                 k *= m;
803                 k ^= k >> r;
804                 k *= m;
805 
806                 h ^= k;
807                 h *= m;
808             }
809             return h;
810         }
811         @safe unittest
812         {
813             assert(UUID("00000000-0000-0000-0000-000000000000") == UUID.init);
814             int[UUID] test = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0") : 1,
815                 UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a") : 2,
816                 UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1") : 3];
817 
818             assert(test[UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")] == 3);
819 
820             import std.algorithm;
821             UUID[] ids = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0"),
822                           UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a"),
823                           UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")];
824             sort(ids);
825             auto id2 = ids.dup;
826 
827             ids = [UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a"),
828                    UUID("8a94f585-d180-44f7-8929-6fca0189c7d0"),
829                    UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")];
830             sort(ids);
831             assert(ids == id2);
832 
833             //test comparsion
834             UUID u1;
835             UUID u2 = UUID(cast(ubyte[16])[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
836             UUID u3 = UUID(cast(ubyte[16])[255,255,255,255,255,255,255,255,255,
837                 255,255,255,255,255,255,255]);
838 
839             assert(u1 == u1);
840 
841             assert(u1 != u2);
842 
843             assert(u1 < u2);
844             assert(u2 < u3);
845 
846             assert(u1 <= u1);
847             assert(u1 <= u2);
848             assert(u2 <= u3);
849 
850             assert(u2 >= u2);
851             assert(u3 >= u2);
852 
853             assert(u3 >= u3);
854             assert(u2 >= u1);
855             assert(u3 >= u1);
856 
857             // test hash
858             assert(u1.toHash() != u2.toHash());
859             assert(u2.toHash() != u3.toHash());
860             assert(u3.toHash() != u1.toHash());
861         }
862 
863 
864         /**
865          * Write the UUID into `sink` as an ASCII string in the canonical form,
866          * which is 36 characters in the form "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
867          * Params:
868          *      sink = OutputRange or writeable array at least 36 entries long
869          */
870         void toString(Writer)(scope Writer sink) const
871         {
872             char[36] result = void;
873             foreach (pos; skipSeq)
874                 result[pos] = '-';
875             foreach (i, pos; byteSeq)
876             {
877                 const uint entry = this.data[i];
878                 const uint hi = entry >> 4;
879                 result[pos  ] = toChar!char(hi);
880                 const uint lo = (entry) & 0x0F;
881                 result[pos+1] = toChar!char(lo);
882             }
883             static if (!__traits(compiles, put(sink, result[])) || isSomeString!Writer)
884             {
885                 foreach (i, c; result)
886                     sink[i] = cast(typeof(sink[i]))c;
887             }
888             else
889             {
890                 put(sink, result[]);
891             }
892         }
893 
894         /**
895          * Return the UUID as a string in the canonical form.
896          */
897         @trusted pure nothrow string toString() const
898         {
899             import std.exception : assumeUnique;
900             auto result = new char[36];
901             toString(result);
902             return result.assumeUnique;
903         }
904 
905         ///
906         @safe pure unittest
907         {
908             immutable str = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46";
909             auto id = UUID(str);
910             assert(id.toString() == str);
911         }
912 
913         @safe pure nothrow @nogc unittest
914         {
915             import std.meta : AliasSeq;
916             static foreach (Char; AliasSeq!(char, wchar, dchar))
917             {{
918                 alias String = immutable(Char)[];
919                 //CTFE
920                 enum String s = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46";
921                 enum id = UUID(s);
922                 static if (is(Char == char))
923                 {
924                     enum p = id.toString();
925                     static assert(s == p);
926                 }
927                 //nogc
928                 Char[36] str;
929                 id.toString(str[]);
930                 assert(str == s);
931             }}
932         }
933 
934         @system pure nothrow @nogc unittest
935         {
936             // @system due to cast
937             import std.encoding : Char = AsciiChar;
938             enum  utfstr = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46";
939             alias String = immutable(Char)[];
940             enum String s = cast(String) utfstr;
941             enum id = UUID(utfstr);
942             //nogc
943             Char[36] str;
944             id.toString(str[]);
945             assert(str == s);
946         }
947 
948         @safe unittest
949         {
950             auto u1 = UUID(cast(ubyte[16])[138, 179, 6, 14, 44, 186, 79,
951                 35, 183, 76, 181, 45, 179, 189, 251, 70]);
952             assert(u1.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
953             u1 = UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
954             assert(u1.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
955 
956             char[] buf;
957             void sink(scope const(char)[] data)
958             {
959                 buf ~= data;
960             }
961             u1.toString(&sink);
962             assert(buf == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
963         }
964 }
965 
966 ///
967 @safe unittest
968 {
969     UUID id;
970     assert(id.empty);
971 
972     id = randomUUID;
973     assert(!id.empty);
974 
975     id = UUID(cast(ubyte[16]) [138, 179, 6, 14, 44, 186, 79,
976         35, 183, 76, 181, 45, 179, 189, 251, 70]);
977     assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
978 }
979 
980 /**
981  * This function generates a name based (Version 3) UUID from a namespace UUID and a name.
982  * If no namespace UUID was passed, the empty UUID `UUID.init` is used.
983  *
984  * Note:
985  * The default namespaces ($(LREF dnsNamespace), ...) defined by
986  * this module should be used when appropriate.
987  *
988  * RFC 4122 recommends to use Version 5 UUIDs (SHA-1) instead of Version 3
989  * UUIDs (MD5) for new applications.
990  *
991  * CTFE:
992  * CTFE is not supported.
993  *
994  * Note:
995  * RFC 4122 isn't very clear on how UUIDs should be generated from names.
996  * It is possible that different implementations return different UUIDs
997  * for the same input, so be warned. The implementation for UTF-8 strings
998  * and byte arrays used by `std.uuid` is compatible with Boost's implementation.
999  * `std.uuid` guarantees that the same input to this function will generate
1000  * the same output at any time, on any system (this especially means endianness
1001  * doesn't matter).
1002  *
1003  * Note:
1004  * This function does not provide overloads for wstring and dstring, as
1005  * there's no clear answer on how that should be implemented. It could be
1006  * argued, that string, wstring and dstring input should have the same output,
1007  * but that wouldn't be compatible with Boost, which generates different output
1008  * for strings and wstrings. It's always possible to pass wstrings and dstrings
1009  * by using the ubyte[] function overload (but be aware of endianness issues!).
1010  */
1011 @safe pure nothrow @nogc UUID md5UUID(const(char[]) name, const UUID namespace = UUID.init)
1012 {
1013     return md5UUID(cast(const(ubyte[]))name, namespace);
1014 }
1015 
1016 /// ditto
1017 @safe pure nothrow @nogc UUID md5UUID(const(ubyte[]) data, const UUID namespace = UUID.init)
1018 {
1019     import std.digest.md : MD5;
1020 
1021     MD5 hash;
1022     hash.start();
1023 
1024     /*
1025      * NOTE: RFC 4122 says namespace should be converted to big-endian.
1026      * We always keep the UUID data in big-endian representation, so
1027      * that's fine
1028      */
1029     hash.put(namespace.data[]);
1030     hash.put(data[]);
1031 
1032     UUID u;
1033     u.data = hash.finish();
1034 
1035     //set variant
1036     //must be 0b10xxxxxx
1037     u.data[8] &= 0b10111111;
1038     u.data[8] |= 0b10000000;
1039 
1040     //set version
1041     //must be 0b0011xxxx
1042     u.data[6] &= 0b00111111;
1043     u.data[6] |= 0b00110000;
1044 
1045     return u;
1046 }
1047 
1048 ///
1049 @safe unittest
1050 {
1051     //Use default UUID.init namespace
1052     auto simpleID = md5UUID("test.uuid.any.string");
1053 
1054     //use a name-based id as namespace
1055     auto namespace = md5UUID("my.app");
1056     auto id = md5UUID("some-description", namespace);
1057 }
1058 
1059 @safe pure unittest
1060 {
1061     auto simpleID = md5UUID("test.uuid.any.string");
1062     assert(simpleID.data == cast(ubyte[16])[126, 206, 86, 72, 29, 233, 62, 213, 178, 139, 198, 136,
1063         188, 135, 153, 123]);
1064     auto namespace = md5UUID("my.app");
1065     auto id = md5UUID("some-description", namespace);
1066     assert(id.data == cast(ubyte[16])[166, 138, 167, 79, 48, 219, 55, 166, 170, 103, 39, 73, 216,
1067         150, 144, 164]);
1068 
1069     auto constTest = md5UUID(cast(const(char)[])"test");
1070     constTest = md5UUID(cast(const(char[]))"test");
1071 
1072     char[] mutable = "test".dup;
1073     id = md5UUID(mutable, namespace);
1074 
1075     const(ubyte)[] data = cast(ubyte[])[0,1,2,244,165,222];
1076     id = md5UUID(data);
1077     assert(id.data == cast(ubyte[16])[16, 50, 29, 247, 243, 185, 61, 178, 157, 100, 253, 236, 73,
1078         76, 51, 47]);
1079 
1080     assert(id.variant == UUID.Variant.rfc4122);
1081     assert(id.uuidVersion == UUID.Version.nameBasedMD5);
1082 
1083     auto correct = UUID("3d813cbb-47fb-32ba-91df-831e1593ac29");
1084 
1085     auto u = md5UUID("www.widgets.com", dnsNamespace);
1086     //enum ctfeId = md5UUID("www.widgets.com", dnsNamespace);
1087     //assert(ctfeId == u);
1088     assert(u == correct);
1089     assert(u.variant == UUID.Variant.rfc4122);
1090     assert(u.uuidVersion == UUID.Version.nameBasedMD5);
1091 }
1092 
1093  /**
1094  * This function generates a name based (Version 5) UUID from a namespace
1095  * UUID and a name.
1096  * If no namespace UUID was passed, the empty UUID `UUID.init` is used.
1097  *
1098  * Note:
1099  * The default namespaces ($(LREF dnsNamespace), ...) defined by
1100  * this module should be used when appropriate.
1101  *
1102  * CTFE:
1103  * CTFE is not supported.
1104  *
1105  * Note:
1106  * RFC 4122 isn't very clear on how UUIDs should be generated from names.
1107  * It is possible that different implementations return different UUIDs
1108  * for the same input, so be warned. The implementation for UTF-8 strings
1109  * and byte arrays used by `std.uuid` is compatible with Boost's implementation.
1110  * `std.uuid` guarantees that the same input to this function will generate
1111  * the same output at any time, on any system (this especially means endianness
1112  * doesn't matter).
1113  *
1114  * Note:
1115  * This function does not provide overloads for wstring and dstring, as
1116  * there's no clear answer on how that should be implemented. It could be
1117  * argued, that string, wstring and dstring input should have the same output,
1118  * but that wouldn't be compatible with Boost, which generates different output
1119  * for strings and wstrings. It's always possible to pass wstrings and dstrings
1120  * by using the ubyte[] function overload (but be aware of endianness issues!).
1121  */
1122 @safe pure nothrow @nogc UUID sha1UUID(scope const(char)[] name, scope const UUID namespace = UUID.init)
1123 {
1124     return sha1UUID(cast(const(ubyte[]))name, namespace);
1125 }
1126 
1127 /// ditto
1128 @safe pure nothrow @nogc UUID sha1UUID(scope const(ubyte)[] data, scope const UUID namespace = UUID.init)
1129 {
1130     import std.digest.sha : SHA1;
1131 
1132     SHA1 sha;
1133     sha.start();
1134 
1135     /*
1136      * NOTE: RFC 4122 says namespace should be converted to big-endian.
1137      * We always keep the UUID data in big-endian representation, so
1138      * that's fine
1139      */
1140     sha.put(namespace.data[]);
1141     sha.put(data[]);
1142 
1143     auto hash = sha.finish();
1144     auto u = UUID();
1145     u.data[] = hash[0 .. 16];
1146 
1147     //set variant
1148     //must be 0b10xxxxxx
1149     u.data[8] &= 0b10111111;
1150     u.data[8] |= 0b10000000;
1151 
1152     //set version
1153     //must be 0b0101xxxx
1154     u.data[6] &= 0b01011111;
1155     u.data[6] |= 0b01010000;
1156 
1157     return u;
1158 }
1159 
1160 ///
1161 @safe unittest
1162 {
1163     //Use default UUID.init namespace
1164     auto simpleID = sha1UUID("test.uuid.any.string");
1165 
1166     //use a name-based id as namespace
1167     auto namespace = sha1UUID("my.app");
1168     auto id = sha1UUID("some-description", namespace);
1169 }
1170 
1171 @safe pure unittest
1172 {
1173     auto simpleID = sha1UUID("test.uuid.any.string");
1174     assert(simpleID.data == cast(ubyte[16])[16, 209, 239, 61, 99, 12, 94, 70, 159, 79, 255, 250,
1175         131, 79, 14, 147]);
1176     auto namespace = sha1UUID("my.app");
1177     auto id = sha1UUID("some-description", namespace);
1178     assert(id.data == cast(ubyte[16])[225, 94, 195, 219, 126, 75, 83, 71, 157, 52, 247, 43, 238, 248,
1179         148, 46]);
1180 
1181     auto constTest = sha1UUID(cast(const(char)[])"test");
1182     constTest = sha1UUID(cast(const(char[]))"test");
1183 
1184     char[] mutable = "test".dup;
1185     id = sha1UUID(mutable, namespace);
1186 
1187     const(ubyte)[] data = cast(ubyte[])[0,1,2,244,165,222];
1188     id = sha1UUID(data);
1189     assert(id.data == cast(ubyte[16])[60, 65, 92, 240, 96, 46, 95, 238, 149, 100, 12, 64, 199, 194,
1190         243, 12]);
1191 
1192     auto correct = UUID("21f7f8de-8051-5b89-8680-0195ef798b6a");
1193 
1194     auto u = sha1UUID("www.widgets.com", dnsNamespace);
1195     assert(u == correct);
1196     assert(u.variant == UUID.Variant.rfc4122);
1197     assert(u.uuidVersion == UUID.Version.nameBasedSHA1);
1198 }
1199 
1200 /**
1201  * This function generates a random number based UUID from a random
1202  * number generator.
1203  *
1204  * This function is not supported at compile time.
1205  *
1206  * Params:
1207  *      randomGen = uniform RNG
1208  * See_Also: $(REF isUniformRNG, std,random)
1209  */
1210 @safe UUID randomUUID()
1211 {
1212     import std.random : rndGen;
1213     // A PRNG with fewer than `n` bytes of state cannot produce
1214     // every distinct `n` byte sequence.
1215     static if (typeof(rndGen).sizeof >= UUID.sizeof)
1216     {
1217         return randomUUID(rndGen);
1218     }
1219     else
1220     {
1221         import std.random : unpredictableSeed, Xorshift192;
1222         static assert(Xorshift192.sizeof >= UUID.sizeof);
1223         static Xorshift192 rng;
1224         static bool initialized;
1225         if (!initialized)
1226         {
1227             rng.seed(unpredictableSeed);
1228             initialized = true;
1229         }
1230         return randomUUID(rng);
1231     }
1232 }
1233 
1234 /// ditto
1235 UUID randomUUID(RNG)(ref RNG randomGen)
1236 if (isInputRange!RNG && isIntegral!(ElementType!RNG))
1237 {
1238     import std.random : isUniformRNG;
1239     static assert(isUniformRNG!RNG, "randomGen must be a uniform RNG");
1240 
1241     alias E = ElementEncodingType!RNG;
1242     enum size_t elemSize = E.sizeof;
1243     static assert(elemSize <= 16);
1244     static assert(16 % elemSize == 0);
1245 
1246     UUID u;
1247     foreach (ref E e ; u.asArrayOf!E())
1248     {
1249         e = randomGen.front;
1250         randomGen.popFront();
1251     }
1252 
1253     //set variant
1254     //must be 0b10xxxxxx
1255     u.data[8] &= 0b10111111;
1256     u.data[8] |= 0b10000000;
1257 
1258     //set version
1259     //must be 0b0100xxxx
1260     u.data[6] &= 0b01001111;
1261     u.data[6] |= 0b01000000;
1262 
1263     return u;
1264 }
1265 
1266 ///
1267 @safe unittest
1268 {
1269     import std.random : Xorshift192, unpredictableSeed;
1270 
1271     //simple call
1272     auto uuid = randomUUID();
1273 
1274     //provide a custom RNG. Must be seeded manually.
1275     Xorshift192 gen;
1276 
1277     gen.seed(unpredictableSeed);
1278     auto uuid3 = randomUUID(gen);
1279 }
1280 
1281 @safe unittest
1282 {
1283     import std.random : Xorshift192, unpredictableSeed;
1284     //simple call
1285     auto uuid = randomUUID();
1286 
1287     //provide a custom RNG. Must be seeded manually.
1288     Xorshift192 gen;
1289     gen.seed(unpredictableSeed);
1290     auto uuid3 = randomUUID(gen);
1291 
1292     auto u1 = randomUUID();
1293     auto u2 = randomUUID();
1294     assert(u1 != u2);
1295     assert(u1.variant == UUID.Variant.rfc4122);
1296     assert(u1.uuidVersion == UUID.Version.randomNumberBased);
1297 }
1298 
1299 /**
1300  * This is a less strict parser compared to the parser used in the
1301  * UUID constructor. It enforces the following rules:
1302  *
1303  * $(UL
1304  *   $(LI hex numbers are always two hexdigits([0-9a-fA-F]))
1305  *   $(LI there must be exactly 16 such pairs in the input, not less, not more)
1306  *   $(LI there can be exactly one dash between two hex-pairs, but not more)
1307  *   $(LI there can be multiple characters enclosing the 16 hex pairs,
1308  *     as long as these characters do not contain [0-9a-fA-F])
1309  * )
1310  *
1311  * Note:
1312  * Like most parsers, it consumes its argument. This means:
1313  * -------------------------
1314  * string s = "8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46";
1315  * parseUUID(s);
1316  * assert(s == "");
1317  * -------------------------
1318  *
1319  * Throws:
1320  * $(LREF UUIDParsingException) if the input is invalid
1321  *
1322  * CTFE:
1323  * This function is supported in CTFE code. Note that error messages
1324  * caused by a malformed UUID parsed at compile time can be cryptic,
1325  * but errors are detected and reported at compile time.
1326  */
1327 UUID parseUUID(T)(T uuidString)
1328 if (isSomeString!T)
1329 {
1330     return parseUUID(uuidString);
1331 }
1332 
1333 ///ditto
1334 UUID parseUUID(Range)(ref Range uuidRange)
1335 if (isInputRange!Range && isSomeChar!(ElementType!Range))
1336 {
1337     import std.ascii : isHexDigit;
1338     import std.conv : ConvException, parse;
1339 
1340     static if (isForwardRange!Range)
1341         auto errorCopy = uuidRange.save;
1342 
1343     void parserError()(size_t pos, UUIDParsingException.Reason reason, string message, Throwable next = null,
1344         string file = __FILE__, size_t line = __LINE__)
1345     {
1346         static if (isForwardRange!Range)
1347         {
1348             import std.conv : to;
1349             static if (isInfinite!Range)
1350             {
1351                 throw new UUIDParsingException(to!string(take(errorCopy, pos)), pos, reason, message,
1352                     next, file, line);
1353             }
1354             else
1355             {
1356                 throw new UUIDParsingException(to!string(errorCopy), pos, reason, message, next, file,
1357                     line);
1358             }
1359         }
1360         else
1361         {
1362             throw new UUIDParsingException("", pos, reason, message, next, file, line);
1363         }
1364     }
1365 
1366     static if (hasLength!Range)
1367     {
1368         import std.conv : to;
1369         if (uuidRange.length < 32)
1370         {
1371             throw new UUIDParsingException(to!string(uuidRange), 0, UUIDParsingException.Reason.tooLittle,
1372                 "Insufficient Input");
1373         }
1374     }
1375 
1376     UUID result;
1377     size_t consumed;
1378     size_t element = 0;
1379 
1380     //skip garbage
1381     size_t skip()()
1382     {
1383         size_t skipped;
1384         while (!uuidRange.empty && !isHexDigit(uuidRange.front))
1385         {
1386             skipped++;
1387             uuidRange.popFront();
1388         }
1389         return skipped;
1390     }
1391 
1392     consumed += skip();
1393 
1394     if (uuidRange.empty)
1395         parserError(consumed, UUIDParsingException.Reason.tooLittle, "Insufficient Input");
1396 
1397     bool dashAllowed = false;
1398 
1399     parseLoop: while (!uuidRange.empty)
1400     {
1401         immutable character = uuidRange.front;
1402 
1403         if (character == '-')
1404         {
1405             if (!dashAllowed)
1406                 parserError(consumed, UUIDParsingException.Reason.invalidChar, "Unexpected '-'");
1407             else
1408                 dashAllowed = false;
1409 
1410             consumed++;
1411         }
1412         else if (!isHexDigit(character))
1413         {
1414             parserError(consumed, UUIDParsingException.Reason.invalidChar,
1415                 "Unexpected character (wanted a hexDigit)");
1416         }
1417         else
1418         {
1419             try
1420             {
1421                 consumed += 2;
1422                 static if (isSomeString!Range)
1423                 {
1424                     if (uuidRange.length < 2)
1425                     {
1426                         parserError(consumed, UUIDParsingException.Reason.tooLittle,
1427                             "Insufficient Input");
1428                     }
1429                     auto part = uuidRange[0 .. 2];
1430                     result.data[element++] = parse!ubyte(part, 16);
1431                     uuidRange.popFront();
1432                 }
1433                 else
1434                 {
1435                     dchar[2] copyBuf;
1436                     copyBuf[0] = character;
1437                     uuidRange.popFront();
1438                     if (uuidRange.empty)
1439                     {
1440                         parserError(consumed, UUIDParsingException.Reason.tooLittle,
1441                             "Insufficient Input");
1442                     }
1443                     copyBuf[1] = uuidRange.front;
1444                     auto part = copyBuf[];
1445                     result.data[element++] = parse!ubyte(part, 16);
1446                 }
1447 
1448                 if (element == 16)
1449                 {
1450                     uuidRange.popFront();
1451                     break parseLoop;
1452                 }
1453 
1454                 dashAllowed = true;
1455             }
1456             catch (ConvException e)
1457             {
1458                 parserError(consumed, UUIDParsingException.Reason.invalidChar,
1459                     "Couldn't parse ubyte", e);
1460             }
1461         }
1462         uuidRange.popFront();
1463     }
1464     assert(element <= 16);
1465 
1466     if (element < 16)
1467         parserError(consumed, UUIDParsingException.Reason.tooLittle, "Insufficient Input");
1468 
1469     consumed += skip();
1470     if (!uuidRange.empty)
1471         parserError(consumed, UUIDParsingException.Reason.invalidChar, "Unexpected character");
1472 
1473     return result;
1474 }
1475 
1476 ///
1477 @safe unittest
1478 {
1479     auto id = parseUUID("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46");
1480     //no dashes
1481     id = parseUUID("8ab3060e2cba4f23b74cb52db3bdfb46");
1482     //dashes at different positions
1483     id = parseUUID("8a-b3-06-0e2cba4f23b74c-b52db3bdfb-46");
1484     //leading / trailing characters
1485     id = parseUUID("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}");
1486     //unicode
1487     id = parseUUID("ü8ab3060e2cba4f23b74cb52db3bdfb46ü");
1488     //multiple trailing/leading characters
1489     id = parseUUID("///8ab3060e2cba4f23b74cb52db3bdfb46||");
1490 
1491     //Can also be used in CTFE, for example as UUID literals:
1492     enum ctfeID = parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
1493     //here parsing is done at compile time, no runtime overhead!
1494 }
1495 
1496 @safe pure unittest
1497 {
1498     import std.conv : to;
1499     import std.exception;
1500     import std.meta;
1501 
1502     struct TestRange(bool forward)
1503     {
1504         dstring input;
1505 
1506         @property dchar front()
1507         {
1508             return input.front;
1509         }
1510 
1511         void popFront()
1512         {
1513             input.popFront();
1514         }
1515 
1516         @property bool empty()
1517         {
1518             return input.empty;
1519         }
1520 
1521         static if (forward)
1522         {
1523             @property TestRange!true save()
1524             {
1525                 return this;
1526             }
1527         }
1528     }
1529     alias TestInputRange = TestRange!false;
1530     alias TestForwardRange = TestRange!true;
1531 
1532     assert(isInputRange!TestInputRange);
1533     assert(is(ElementType!TestInputRange == dchar));
1534     assert(isInputRange!TestForwardRange);
1535     assert(isForwardRange!TestForwardRange);
1536     assert(is(ElementType!TestForwardRange == dchar));
1537 
1538     //Helper function for unittests - Need to pass ranges by ref
1539     UUID parseHelper(T)(string input)
1540     {
1541         static if (is(T == TestInputRange) || is(T == TestForwardRange))
1542         {
1543             T range = T(to!dstring(input));
1544             return parseUUID(range);
1545         }
1546         else
1547             return parseUUID(to!T(input));
1548     }
1549 
1550     static foreach (S; AliasSeq!(char[], const(char)[], immutable(char)[],
1551                           wchar[], const(wchar)[], immutable(wchar)[],
1552                           dchar[], const(dchar)[], immutable(dchar)[],
1553                           immutable(char[]), immutable(wchar[]), immutable(dchar[]),
1554                           TestForwardRange, TestInputRange))
1555     {{
1556         //Verify examples.
1557         auto id = parseHelper!S("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46");
1558         //no dashes
1559         id = parseHelper!S("8ab3060e2cba4f23b74cb52db3bdfb46");
1560         //dashes at different positions
1561         id = parseHelper!S("8a-b3-06-0e2cba4f23b74c-b52db3bdfb-46");
1562         //leading / trailing characters
1563         id = parseHelper!S("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}");
1564         //unicode
1565         id = parseHelper!S("ü8ab3060e2cba4f23b74cb52db3bdfb46ü");
1566         //multiple trailing/leading characters
1567         id = parseHelper!S("///8ab3060e2cba4f23b74cb52db3bdfb46||");
1568         enum ctfeId = parseHelper!S("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");
1569         assert(parseHelper!S("8AB3060E-2cba-4f23-b74c-b52db3bdfb46") == ctfeId);
1570 
1571         //Test valid, working cases
1572         assert(parseHelper!S("00000000-0000-0000-0000-000000000000").empty);
1573         assert(parseHelper!S("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46").data
1574             == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45, 179, 189, 251, 70]);
1575 
1576         assert(parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a").data
1577             == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);
1578 
1579         //wstring / dstring
1580         assert(parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a").data
1581             == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);
1582         assert(parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a").data
1583             == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);
1584 
1585         //Test too short UUIDS
1586         auto except = collectException!UUIDParsingException(
1587             parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886"));
1588         assert(except && except.reason == UUIDParsingException.Reason.tooLittle);
1589 
1590         //Test too long UUIDS
1591         except = collectException!UUIDParsingException(
1592             parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886aa"));
1593         assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
1594 
1595         //Test too long UUIDS 2
1596         except = collectException!UUIDParsingException(
1597             parseHelper!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a-aa"));
1598         assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
1599 
1600         //Test dashes
1601         assert(parseHelper!S("8ab3060e2cba-4f23-b74c-b52db3bdfb46")
1602             == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1603         assert(parseHelper!S("8ab3-060e2cba-4f23-b74c-b52db3bdfb46")
1604             == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1605         assert(parseHelper!S("8ab3060e2cba4f23b74cb52db3bdfb46")
1606             == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1607 
1608         except = collectException!UUIDParsingException(
1609             parseHelper!S("8-ab3060e2cba-4f23-b74c-b52db3bdfb46"));
1610         assert(except && except.reason == UUIDParsingException.Reason.invalidChar);
1611 
1612         //Test leading/trailing characters
1613         assert(parseHelper!S("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}")
1614             == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1615         assert(parseHelper!S("{8ab3060e2cba4f23b74cb52db3bdfb46}")
1616             == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1617 
1618         //Boost test
1619         auto u_increasing = UUID(cast(ubyte[16])[0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
1620             0xcd, 0xef,0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
1621         assert(parseHelper!S("0123456789abcdef0123456789ABCDEF") == UUID(cast(ubyte[16])[0x01,
1622             0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]));
1623 
1624         //unicode
1625         assert(parseHelper!S("ü8ab3060e2cba4f23b74cb52db3bdfb46ü")
1626             == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1627 
1628         //multiple trailing/leading characters
1629         assert(parseHelper!S("///8ab3060e2cba4f23b74cb52db3bdfb46||")
1630             == parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));
1631     }}
1632 
1633     // Test input range with non-dchar element type.
1634     {
1635         import std.utf : byCodeUnit;
1636         auto range = "8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46".byCodeUnit;
1637         assert(parseUUID(range).data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45, 179, 189, 251, 70]);
1638     }
1639 }
1640 
1641 /**
1642  * Default namespace from RFC 4122
1643  *
1644  * Name string is a fully-qualified domain name
1645  */
1646 enum dnsNamespace = UUID("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
1647 
1648 /**
1649  * Default namespace from RFC 4122
1650  *
1651  * Name string is a URL
1652  */
1653 enum urlNamespace = UUID("6ba7b811-9dad-11d1-80b4-00c04fd430c8");
1654 
1655 /**
1656  * Default namespace from RFC 4122
1657  *
1658  * Name string is an ISO OID
1659  */
1660 enum oidNamespace = UUID("6ba7b812-9dad-11d1-80b4-00c04fd430c8");
1661 
1662 /**
1663  * Default namespace from RFC 4122
1664  *
1665  * Name string is an X.500 DN (in DER or a text output format)
1666  */
1667 enum x500Namespace = UUID("6ba7b814-9dad-11d1-80b4-00c04fd430c8");
1668 
1669 /**
1670  * Regex string to extract UUIDs from text.
1671  */
1672 enum uuidRegex = "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}"~
1673     "-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}";
1674 
1675 ///
1676 @safe unittest
1677 {
1678     import std.algorithm;
1679     import std.regex;
1680 
1681     string test = "Lorem ipsum dolor sit amet, consetetur "~
1682     "6ba7b814-9dad-11d1-80b4-00c04fd430c8 sadipscing \n"~
1683     "elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore \r\n"~
1684     "magna aliquyam erat, sed diam voluptua. "~
1685     "8ab3060e-2cba-4f23-b74c-b52db3bdfb46 At vero eos et accusam et "~
1686     "justo duo dolores et ea rebum.";
1687 
1688     auto r = regex(uuidRegex, "g");
1689     UUID[] found;
1690     foreach (c; match(test, r))
1691     {
1692         found ~= UUID(c.hit);
1693     }
1694     assert(found == [
1695         UUID("6ba7b814-9dad-11d1-80b4-00c04fd430c8"),
1696         UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"),
1697     ]);
1698 }
1699 
1700 /**
1701  * This exception is thrown if an error occurs when parsing a UUID
1702  * from a string.
1703  */
1704 public class UUIDParsingException : Exception
1705 {
1706     /**
1707      * The reason why parsing the UUID string failed (if known)
1708      */
1709     enum Reason
1710     {
1711         unknown, ///
1712         tooLittle, ///The passed in input was correct, but more input was expected.
1713         tooMuch, ///The input data is too long (There's no guarantee the first part of the data is valid)
1714         invalidChar, ///Encountered an invalid character
1715 
1716     }
1717     ///ditto
1718     Reason reason;
1719     ///The original input string which should have been parsed.
1720     string input;
1721     ///The position in the input string where the error occurred.
1722     size_t position;
1723 
1724     private this(string input, size_t pos, Reason why = Reason.unknown, string msg = "",
1725         Throwable next = null, string file = __FILE__, size_t line = __LINE__) pure @trusted
1726     {
1727         import std.array : replace;
1728         import std.format : format;
1729         this.input = input;
1730         this.position = pos;
1731         this.reason = why;
1732         string message = format("An error occured in the UUID parser: %s\n" ~
1733           " * Input:\t'%s'\n * Position:\t%s", msg, replace(replace(input,
1734           "\r", "\\r"), "\n", "\\n"), pos);
1735         super(message, file, line, next);
1736     }
1737 }
1738 
1739 ///
1740 @safe unittest
1741 {
1742     import std.exception : collectException;
1743 
1744     const inputUUID = "this-is-an-invalid-uuid";
1745     auto ex = collectException!UUIDParsingException(UUID(inputUUID));
1746     assert(ex !is null); // check that exception was thrown
1747     assert(ex.input == inputUUID);
1748     assert(ex.position == 0);
1749     assert(ex.reason == UUIDParsingException.Reason.tooLittle);
1750 }
1751 
1752 @safe unittest
1753 {
1754     auto ex = new UUIDParsingException("foo", 10, UUIDParsingException.Reason.tooMuch);
1755     assert(ex.input == "foo");
1756     assert(ex.position == 10);
1757     assert(ex.reason == UUIDParsingException.Reason.tooMuch);
1758 }