Exemple #1
0
        public static Guid Combine(Guid a, Guid b)
        {
            var ad = new DecomposedGuid(a);
            var bd = new DecomposedGuid(b);

            ad.Hi ^= bd.Hi;
            ad.Lo ^= bd.Lo;

            return(ad.Value);
        }
Exemple #2
0
        /// <summary>
        /// Formats a Guid as a UTF8 string.
        /// </summary>
        /// <param name="value">Value to format</param>
        /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
        /// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
        /// <param name="format">The standard format to use</param>
        /// <returns>
        /// true for success. "bytesWritten" contains the length of the formatted text in bytes.
        /// false if buffer was too short. Iteratively increase the size of the buffer and retry until it succeeds.
        /// </returns>
        /// <remarks>
        /// Formats supported:
        ///     D (default)     nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn
        ///     B               {nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn}
        ///     P               (nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn)
        ///     N               nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
        /// </remarks>
        /// <exceptions>
        /// <cref>System.FormatException</cref> if the format is not valid for this data type.
        /// </exceptions>
        public static bool TryFormat(Guid value, Span <byte> destination, out int bytesWritten, StandardFormat format = default)
        {
            const int INSERT_DASHES       = unchecked ((int)0x80000000);
            const int NO_DASHES           = 0;
            const int INSERT_CURLY_BRACES = (CloseBrace << 16) | (OpenBrace << 8);
            const int INSERT_ROUND_BRACES = (CloseParen << 16) | (OpenParen << 8);
            const int NO_BRACES           = 0;
            const int LEN_GUID_BASE       = 32;
            const int LEN_ADD_DASHES      = 4;
            const int LEN_ADD_BRACES      = 2;

            // This is a 32-bit value whose contents (where 0 is the low byte) are:
            // 0th byte: minimum required length of the output buffer,
            // 1st byte: the ASCII byte to insert for the opening brace position (or 0 if no braces),
            // 2nd byte: the ASCII byte to insert for the closing brace position (or 0 if no braces),
            // 3rd byte: high bit set if dashes are to be inserted.
            //
            // The reason for keeping a single flag instead of separate vars is that we can avoid register spillage
            // as we build up the output value.
            int flags;

            switch (FormattingHelpers.GetSymbolOrDefault(format, 'D'))
            {
            case 'D':     // nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn
                flags = INSERT_DASHES + NO_BRACES + LEN_GUID_BASE + LEN_ADD_DASHES;
                break;

            case 'B':     // {nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn}
                flags = INSERT_DASHES + INSERT_CURLY_BRACES + LEN_GUID_BASE + LEN_ADD_DASHES + LEN_ADD_BRACES;
                break;

            case 'P':     // (nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn)
                flags = INSERT_DASHES + INSERT_ROUND_BRACES + LEN_GUID_BASE + LEN_ADD_DASHES + LEN_ADD_BRACES;
                break;

            case 'N':     // nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
                flags = NO_BRACES + NO_DASHES + LEN_GUID_BASE;
                break;

            default:
                return(ThrowHelper.TryFormatThrowFormatException(out bytesWritten));
            }

            // At this point, the low byte of flags contains the minimum required length

            if ((byte)flags > destination.Length)
            {
                bytesWritten = 0;
                return(false);
            }

            bytesWritten = (byte)flags;
            flags      >>= 8;

            // At this point, the low byte of flags contains the opening brace char (if any)

            if ((byte)flags != 0)
            {
                destination[0] = (byte)flags;
                destination    = destination.Slice(1);
            }
            flags >>= 8;

            // At this point, the low byte of flags contains the closing brace char (if any)
            // And since we're performing arithmetic shifting the high bit of flags is set (flags is negative) if dashes are required

            DecomposedGuid guidAsBytes = default;

            guidAsBytes.Guid = value;

            // When a GUID is blitted, the first three components are little-endian, and the last component is big-endian.

            // The line below forces the JIT to hoist the bounds check for the following segment.
            // The JIT will optimize away the read, but it cannot optimize away the bounds check
            // because it may have an observable side effect (throwing).
            // We use 8 instead of 7 so that we also capture the dash if we're asked to insert one.

            { var unused = destination[8]; }
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte03, destination, 0, FormattingHelpers.HexCasing.Lowercase);
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte02, destination, 2, FormattingHelpers.HexCasing.Lowercase);
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte01, destination, 4, FormattingHelpers.HexCasing.Lowercase);
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte00, destination, 6, FormattingHelpers.HexCasing.Lowercase);

            if (flags < 0 /* use dash? */)
            {
                destination[8] = Dash;
                destination    = destination.Slice(9);
            }
            else
            {
                destination = destination.Slice(8);
            }

            { var unused = destination[4]; }
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte05, destination, 0, FormattingHelpers.HexCasing.Lowercase);
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte04, destination, 2, FormattingHelpers.HexCasing.Lowercase);

            if (flags < 0 /* use dash? */)
            {
                destination[4] = Dash;
                destination    = destination.Slice(5);
            }
            else
            {
                destination = destination.Slice(4);
            }

            { var unused = destination[4]; }
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte07, destination, 0, FormattingHelpers.HexCasing.Lowercase);
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte06, destination, 2, FormattingHelpers.HexCasing.Lowercase);

            if (flags < 0 /* use dash? */)
            {
                destination[4] = Dash;
                destination    = destination.Slice(5);
            }
            else
            {
                destination = destination.Slice(4);
            }

            { var unused = destination[4]; }
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte08, destination, 0, FormattingHelpers.HexCasing.Lowercase);
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte09, destination, 2, FormattingHelpers.HexCasing.Lowercase);

            if (flags < 0 /* use dash? */)
            {
                destination[4] = Dash;
                destination    = destination.Slice(5);
            }
            else
            {
                destination = destination.Slice(4);
            }

            { var unused = destination[11]; } // can't hoist bounds check on the final brace (if exists)
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte10, destination, 0, FormattingHelpers.HexCasing.Lowercase);
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte11, destination, 2, FormattingHelpers.HexCasing.Lowercase);
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte12, destination, 4, FormattingHelpers.HexCasing.Lowercase);
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte13, destination, 6, FormattingHelpers.HexCasing.Lowercase);
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte14, destination, 8, FormattingHelpers.HexCasing.Lowercase);
            FormattingHelpers.WriteHexByte(guidAsBytes.Byte15, destination, 10, FormattingHelpers.HexCasing.Lowercase);

            if ((byte)flags != 0)
            {
                destination[12] = (byte)flags;
            }

            return(true);
        }
        public IJsonBuilder Append(Guid value)
        {
            if (_index + 36 > _buffer.Length)
            {
                ResizeBuffer(36);
            }

            DecomposedGuid guidAsBytes = default;

            guidAsBytes.Guid = value;

            var destination = _buffer.AsSpan(_index);

            ///nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn

            // this forces a jit bounds check (lookup get optimzed away) which means
            // the rest of the lookups don't need to be bounds checked
            { _ = destination[35]; }
            if (BitConverter.IsLittleEndian)
            {
                destination[0] = _uperHexLookup[guidAsBytes.Byte03];
                destination[1] = _lowerHexLookup[guidAsBytes.Byte03];
                destination[2] = _uperHexLookup[guidAsBytes.Byte02];
                destination[3] = _lowerHexLookup[guidAsBytes.Byte02];
                destination[4] = _uperHexLookup[guidAsBytes.Byte01];
                destination[5] = _lowerHexLookup[guidAsBytes.Byte01];
                destination[6] = _uperHexLookup[guidAsBytes.Byte00];
                destination[7] = _lowerHexLookup[guidAsBytes.Byte00];
            }
            else
            {
                destination[0] = _uperHexLookup[guidAsBytes.Byte00];
                destination[1] = _lowerHexLookup[guidAsBytes.Byte00];
                destination[2] = _uperHexLookup[guidAsBytes.Byte01];
                destination[3] = _lowerHexLookup[guidAsBytes.Byte01];
                destination[4] = _uperHexLookup[guidAsBytes.Byte02];
                destination[5] = _lowerHexLookup[guidAsBytes.Byte02];
                destination[6] = _uperHexLookup[guidAsBytes.Byte03];
                destination[7] = _lowerHexLookup[guidAsBytes.Byte03];
            }

            destination[8] = Dash;

            if (BitConverter.IsLittleEndian)
            {
                destination[9]  = _uperHexLookup[guidAsBytes.Byte05];
                destination[10] = _lowerHexLookup[guidAsBytes.Byte05];
                destination[11] = _uperHexLookup[guidAsBytes.Byte04];
                destination[12] = _lowerHexLookup[guidAsBytes.Byte04];
            }
            else
            {
                destination[9]  = _uperHexLookup[guidAsBytes.Byte04];
                destination[10] = _lowerHexLookup[guidAsBytes.Byte04];
                destination[11] = _uperHexLookup[guidAsBytes.Byte05];
                destination[12] = _lowerHexLookup[guidAsBytes.Byte05];
            }

            destination[13] = Dash;

            if (BitConverter.IsLittleEndian)
            {
                destination[14] = _uperHexLookup[guidAsBytes.Byte07];
                destination[15] = _lowerHexLookup[guidAsBytes.Byte07];
                destination[16] = _uperHexLookup[guidAsBytes.Byte06];
                destination[17] = _lowerHexLookup[guidAsBytes.Byte06];
            }
            else
            {
                destination[14] = _uperHexLookup[guidAsBytes.Byte06];
                destination[15] = _lowerHexLookup[guidAsBytes.Byte06];
                destination[16] = _uperHexLookup[guidAsBytes.Byte07];
                destination[17] = _lowerHexLookup[guidAsBytes.Byte07];
            }

            destination[18] = Dash;


            destination[19] = _uperHexLookup[guidAsBytes.Byte08];
            destination[20] = _lowerHexLookup[guidAsBytes.Byte08];
            destination[21] = _uperHexLookup[guidAsBytes.Byte09];
            destination[22] = _lowerHexLookup[guidAsBytes.Byte09];

            destination[23] = Dash;

            destination[24] = _uperHexLookup[guidAsBytes.Byte10];
            destination[25] = _lowerHexLookup[guidAsBytes.Byte10];
            destination[26] = _uperHexLookup[guidAsBytes.Byte11];
            destination[27] = _lowerHexLookup[guidAsBytes.Byte11];
            destination[28] = _uperHexLookup[guidAsBytes.Byte12];
            destination[29] = _lowerHexLookup[guidAsBytes.Byte12];
            destination[30] = _uperHexLookup[guidAsBytes.Byte13];
            destination[31] = _lowerHexLookup[guidAsBytes.Byte13];
            destination[32] = _uperHexLookup[guidAsBytes.Byte14];
            destination[33] = _lowerHexLookup[guidAsBytes.Byte14];
            destination[34] = _uperHexLookup[guidAsBytes.Byte15];
            destination[35] = _lowerHexLookup[guidAsBytes.Byte15];

            _index += 36;
            return(this);
        }