Wolfgang Thallergcc16 merge934c3885 months agoHistory
2078 lines · 65.9 KB · D
RawDownload
/** * A $(LINK2 http://en.wikipedia.org/wiki/Universally_unique_identifier, UUID), or * $(LINK2 http://en.wikipedia.org/wiki/Universally_unique_identifier, Universally unique identifier), * is intended to uniquely identify information in a distributed environment * without significant central coordination. It can be * used to tag objects with very short lifetimes, or to reliably identify very * persistent objects across a network. *$(SCRIPT inhibitQuickIndex = 1;) $(DIVC quickindex,$(BOOKTABLE ,$(TR $(TH Category) $(TH Functions))$(TR $(TDNW Parsing UUIDs)     $(TD $(MYREF parseUUID)          $(MYREF UUID)          $(MYREF UUIDParsingException)          $(MYREF uuidRegex)          )     )$(TR $(TDNW Generating UUIDs)     $(TD $(MYREF sha1UUID)          $(MYREF randomUUID)          $(MYREF md5UUID)          $(MYREF timestampRandomUUID)          )     )$(TR $(TDNW Using UUIDs)     $(TD $(MYREF2 UUID.uuidVersion, uuidVersion)          $(MYREF2 UUID.variant, variant)          $(MYREF2 UUID.toString, toString)          $(MYREF2 UUID.data, data)          $(MYREF2 UUID.swap, swap)          $(MYREF2 UUID.opEquals, opEquals)          $(MYREF2 UUID.opCmp, opCmp)          $(MYREF2 UUID.toHash, toHash)          )     )$(TR $(TDNW UUID namespaces)     $(TD $(MYREF dnsNamespace)          $(MYREF urlNamespace)          $(MYREF oidNamespace)          $(MYREF x500Namespace)          )     )))  * UUIDs have many applications. Some examples follow: Databases may use UUIDs to identify * rows or records in order to ensure that they are unique across different * databases, or for publication/subscription services. Network messages may be * identified with a UUID to ensure that different parts of a message are put back together * again. Distributed computing may use UUIDs to identify a remote procedure call. * Transactions and classes involved in serialization may be identified by UUIDs. * Microsoft's component object model (COM) uses UUIDs to distinguish different software * component interfaces. UUIDs are inserted into documents from Microsoft Office programs. * UUIDs identify audio or video streams in the Advanced Systems Format (ASF). UUIDs are * also a basis for OIDs (object identifiers), and URNs (uniform resource name). * * An attractive feature of UUIDs when compared to alternatives is their relative small size, * of 128 bits, or 16 bytes. Another is that the creation of UUIDs does not require * a centralized authority. * * When UUIDs are generated by one of the defined mechanisms, they are either guaranteed * to be unique, different from all other generated UUIDs (that is, it has never been * generated before and it will never be generated again), or it is extremely likely * to be unique (depending on the mechanism). * * For efficiency, UUID is implemented as a struct. UUIDs are therefore empty if not explicitly * initialized. An UUID is empty if $(MYREF3 UUID.empty, empty) is true. Empty UUIDs are equal to * `UUID.init`, which is a UUID with all 16 bytes set to 0. * Use UUID's constructors or the UUID generator functions to get an initialized UUID. * * This is a port of $(LINK2 http://www.boost.org/doc/libs/1_42_0/libs/uuid/uuid.html, * boost.uuid) from the Boost project with some minor additions and API * changes for a more D-like API. * * Standards: * $(LINK2 http://www.ietf.org/rfc/rfc4122.txt, RFC 4122) * * See_Also: * $(LINK http://en.wikipedia.org/wiki/Universally_unique_identifier) * * Copyright: Copyright Johannes Pfau 2011 - . * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors:   Johannes Pfau * Source:    $(PHOBOSSRC std/uuid.d) * * Macros: * MYREF2 = <a href="#$2">$(TT $1)</a>&nbsp; * MYREF3 = <a href="#$2">`$1`</a> *//*          Copyright Johannes Pfau 2011 - 2012. * Distributed under the Boost Software License, Version 1.0. *    (See accompanying file LICENSE_1_0.txt or copy at *          http://www.boost.org/LICENSE_1_0.txt) */module std.uuid; ///@safe unittest{    import std.uuid;     UUID[] ids;    ids ~= randomUUID();    ids ~= md5UUID("test.name.123");    ids ~= sha1UUID("test.name.123");     foreach (entry; ids)    {        assert(entry.variant == UUID.Variant.rfc4122);    }    assert(ids[0].uuidVersion == UUID.Version.randomNumberBased);    assert(ids[1].toString() == "22390768-cced-325f-8f0f-cfeaa19d0ccd");    assert(ids[1].data == [34, 57, 7, 104, 204, 237, 50, 95, 143, 15, 207,        234, 161, 157, 12, 205]);    UUID id;    assert(id.empty);} import core.time : dur;import std.bitmanip : bigEndianToNative, nativeToBigEndian;import std.datetime.systime : SysTime;import std.datetime : Clock, DateTime, UTC;import std.range.primitives;import std.traits; /** * */public struct UUID{    import std.meta : AliasSeq, allSatisfy;     private:        alias skipSeq = AliasSeq!(8, 13, 18, 23);        alias byteSeq = AliasSeq!(0,2,4,6,9,11,14,16,19,21,24,26,28,30,32,34);         @safe pure nothrow @nogc Char toChar(Char)(size_t i) const        {            if (i <= 9)                return cast(Char)('0' + i);            else                return cast(Char)('a' + (i-10));        }         @safe pure nothrow unittest        {            assert(UUID(cast(ubyte[16])[138, 179, 6, 14, 44, 186, 79, 35, 183, 76, 181, 45,                179, 189, 251, 70]).toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");        }         // Reinterpret the UUID as an array of some other primitive.        @trusted ref T[16 / T.sizeof] asArrayOf(T)() return        if (isIntegral!T)        {            return *cast(typeof(return)*)&data;        }     public:        /**         * RFC 4122 defines different internal data layouts for UUIDs. These are         * the UUID formats supported by this module. It's         * possible to read, compare and use all these Variants, but         * UUIDs generated by this module will always be in rfc4122 format.         *         * Note: Do not confuse this with $(REF _Variant, std,_variant).         */        enum Variant        {            ncs, /// NCS backward compatibility            rfc4122, /// Defined in RFC 4122 document            microsoft, /// Microsoft Corporation backward compatibility            future ///Reserved for future use        }         /**         * RFC 4122 defines different UUID versions. The version shows         * how a UUID was generated, e.g. a version 4 UUID was generated         * from a random number, a version 3 UUID from an MD5 hash of a name.         *         * Note:         * All of these UUID versions can be read and processed by         * `std.uuid`, but only version 3, 4 and 5 UUIDs can be generated.         */        enum Version        {            ///Unknown version            unknown = -1,            ///Version 1            timeBased = 1,            ///Version 2            dceSecurity = 2,            ///Version 3 (Name based + MD5)            nameBasedMD5 = 3,            ///Version 4 (Random)            randomNumberBased = 4,            ///Version 5 (Name based + SHA-1)            nameBasedSHA1 = 5,            ///Version 7 (milliseconds since unix epoch + random)            timestampRandom = 7        }         union        {            /**             * It is sometimes useful to get or set the 16 bytes of a UUID             * directly.             *             * Note:             * UUID uses a 16-ubyte representation for the UUID data.             * RFC 4122 defines a UUID as a special structure in big-endian             * format. These 16-ubytes always equal the big-endian structure             * defined in RFC 4122.             *             * Example:             * -----------------------------------------------             * auto rawData = uuid.data; //get data             * rawData[0] = 1; //modify             * uuid.data = rawData; //set data             * uuid.data[1] = 2; //modify directly             * -----------------------------------------------             */            ubyte[16] data;            private ulong[2] ulongs;            static if (size_t.sizeof == 4)                private uint[4] uints;        }         /*         * We could use a union here to also provide access to the         * fields specified in RFC 4122, but as we never have to access         * those (only necessary for version 1 (and maybe 2) UUIDs),         * that is not needed right now.         */         @safe pure unittest        {            UUID tmp;            tmp.data = cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,12,                13,14,15];            assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,                12,13,14,15]);            tmp.data[2] = 3;            assert(tmp.data == cast(ubyte[16])[0,1,3,3,4,5,6,7,8,9,10,11,                12,13,14,15]);             auto tmp2 = cast(immutable UUID) tmp;            assert(tmp2.data == cast(ubyte[16])[0,1,3,3,4,5,6,7,8,9,10,11,                12,13,14,15]);        }         /**         * Construct a UUID struct from the 16 byte representation         * of a UUID.         */        @safe pure nothrow @nogc this(ref const scope ubyte[16] uuidData)        {            data = uuidData;        }        /// ditto        @safe pure nothrow @nogc this(const ubyte[16] uuidData)        {            data = uuidData;        }         ///        @safe pure unittest        {            enum ubyte[16] data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];            auto uuid = UUID(data);            enum ctfe = UUID(data);            assert(uuid.data == data);            assert(ctfe.data == data);        }         /**         * Construct a UUID struct from the 16 byte representation         * of a UUID. Variadic constructor to allow a simpler syntax, see examples.         * You need to pass exactly 16 ubytes.         */        @safe pure this(T...)(T uuidData)        if (uuidData.length == 16 && allSatisfy!(isIntegral, T))        {            import std.conv : to;             foreach (idx, it; uuidData)            {                this.data[idx] = to!ubyte(it);            }        }         ///        @safe unittest        {            auto tmp = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);            assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,                12,13,14,15]);        }         @safe unittest        {            UUID tmp = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);            assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11,                12,13,14,15]);             enum UUID ctfeID = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);            assert(ctfeID == tmp);             //Too few arguments            assert(!__traits(compiles, typeof(UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14))));             //Too many arguments            assert(!__traits(compiles, typeof(UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1))));        }         /**         * UUID V7 constructor         *         * This implementation is not guaranteed to use a cryptographically secure PRNG.         * For more information please see: std.random.unpredictableSeed         *         * Params:         *   timestamp = the timestamp part of the UUID V7         *   random = UUID V7 has 74 bits of random data, which rounds to 10 ubyte's.         *    If no random data is given, random data is generated.         */        @safe pure this(SysTime timestamp, ubyte[10] random = generateRandomData!10)        {            ulong epoch = (timestamp - SysTime.fromUnixTime(0)).total!"msecs";            this(epoch, random);        }         /// ditto        @safe pure this(ulong epoch_msecs, ubyte[10] random = generateRandomData!10)        {            ubyte[8] epoch = epoch_msecs.nativeToBigEndian;             this.data[0 .. 6] = epoch[2 .. 8];            this.data[6 .. $] = random;             // version and variant            this.data[6] = (this.data[6] & 0x0F) | 0x70;            this.data[8] = (this.data[8] & 0x3F) | 0x80;        }         ///        @system unittest        {            import std.datetime : DateTime, SysTime;            SysTime st = DateTime(2025, 8, 19, 10, 38, 45);            UUID u = UUID(st);            SysTime o = u.v7Timestamp();            assert(o == st, st.toString() ~ " | " ~ o.toString());        }         /**         * <a name="UUID(string)"></a>         * Parse a UUID from its canonical string form. An UUID in its         * canonical form looks like this: 8ab3060e-2cba-4f23-b74c-b52db3bdfb46         *         * Throws:         * $(LREF UUIDParsingException) if the input is invalid         *         * CTFE:         * This function is supported in CTFE code. Note that error messages         * caused by a malformed UUID parsed at compile time can be cryptic,         * but errors are detected and reported at         * compile time.         *         * Note:         * This is a strict parser. It only accepts the pattern above.         * It doesn't support any leading or trailing characters. It only         * accepts characters used for hex numbers and the string must have         * hyphens exactly like above.         *         * For a less strict parser, see $(LREF parseUUID)         */        this(T)(in T[] uuid)        if (isSomeChar!T)        {            import std.conv : to, parse;            if (uuid.length < 36)            {                throw new UUIDParsingException(to!string(uuid), 0,                    UUIDParsingException.Reason.tooLittle, "Insufficient Input");            }            if (uuid.length > 36)            {                throw new UUIDParsingException(to!string(uuid), 35, UUIDParsingException.Reason.tooMuch,                    "Input is too long, need exactly 36 characters");            }            static immutable skipInd = [skipSeq];            foreach (pos; skipInd)                if (uuid[pos] != '-')                    throw new UUIDParsingException(to!string(uuid), pos,                        UUIDParsingException.Reason.invalidChar, "Expected '-'");             ubyte[16] data2; //ctfe bug            uint pos = void;             foreach (i, p; byteSeq)            {                enum uint s = 'a'-10-'0';                uint h = uuid[p];                uint l = uuid[p+1];                pos = p;                if (h < '0') goto Lerr;                if (l < '0') goto Lerr;                if (h > '9')                {                    h |= 0x20; //poorman's tolower                    if (h < 'a') goto Lerr;                    if (h > 'f') goto Lerr;                    h -= s;                }                if (l > '9')                {                    l |= 0x20; //poorman's tolower                    if (l < 'a') goto Lerr;                    if (l > 'f') goto Lerr;                    l -= s;                }                h -= '0';                l -= '0';                 data2[i] = cast(ubyte)((h << 4) ^ l);            }            this.data = data2;            return;         Lerr: throw new UUIDParsingException(to!string(uuid), pos,                UUIDParsingException.Reason.invalidChar, "Couldn't parse ubyte");        }         ///        @safe pure unittest        {            auto id = UUID("8AB3060E-2cba-4f23-b74c-b52db3bdfb46");            assert(id.data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76,               181, 45, 179, 189, 251, 70]);            assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");             //Can also be used in CTFE, for example as UUID literals:            enum ctfeID = UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46");            //here parsing is done at compile time, no runtime overhead!        }         @safe pure unittest        {            import std.conv : to;            import std.exception;            import std.meta : AliasSeq;             static foreach (S; AliasSeq!(char[], const(char)[], immutable(char)[],                                  wchar[], const(wchar)[], immutable(wchar)[],                                  dchar[], const(dchar)[], immutable(dchar)[],                                  immutable(char[]), immutable(wchar[]), immutable(dchar[])))            {{                //Test valid, working cases                assert(UUID(to!S("00000000-0000-0000-0000-000000000000")).empty);                 auto id = UUID(to!S("8AB3060E-2cba-4f23-b74c-b52db3bdfb46"));                assert(id.data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76,                    181, 45, 179, 189, 251, 70]);                assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46");                 enum UUID ctfe = UUID(to!S("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"));                assert(ctfe == id);                 assert(UUID(to!S("5668122d-9df0-49a4-ad0b-b9b0a57f886a")).data                    == [86, 104, 18, 45, 157, 240, 73, 164, 173, 11, 185, 176, 165, 127, 136, 106]);                 //Test too short UUIDS                auto except = collectException!UUIDParsingException(                    UUID(to!S("5668122d-9df0-49a4-ad0b-b9b0a57f886")));                assert(except && except.reason == UUIDParsingException.Reason.tooLittle);                 //Test too long UUIDS                except = collectException!UUIDParsingException(                    UUID(to!S("5668122d-9df0-49a4-ad0b-b9b0a57f886aa")));                assert(except && except.reason == UUIDParsingException.Reason.tooMuch);                 //Test dashes                except = collectException!UUIDParsingException(                    UUID(to!S("8ab3060e2cba-4f23-b74c-b52db3bdfb-46")));                assert(except && except.reason == UUIDParsingException.Reason.invalidChar);                 //Test dashes 2                except = collectException!UUIDParsingException(                    UUID(to!S("8ab3-060e2cba-4f23-b74c-b52db3bdfb46")));                assert(except && except.reason == UUIDParsingException.Reason.invalidChar);                 //Test invalid characters                //make sure 36 characters in total or we'll get a 'tooMuch' reason                except = collectException!UUIDParsingException(                    UUID(to!S("{8ab3060e-2cba-4f23-b74c-b52db3bdf6}")));                assert(except && except.reason == UUIDParsingException.Reason.invalidChar);

Lines 1–500 of 2078.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t