ClearCanvas.Dicom.DicomUid.FormatGuidAsString C# (CSharp) Метод

FormatGuidAsString() приватный статический Метод

Formats a GUID as a big decimal string of digits.
private static FormatGuidAsString ( System.Guid guid ) : string
guid System.Guid
Результат string
		private static unsafe string FormatGuidAsString(Guid guid)
		{
			// the conversion is based on the pen-and-paper algorithm for converting between bases:
			// 1. divide input by base, remainder is least significant output digit.
			// 2. divide quotient by base, remainder is next least significant output digit.
			// 3. repeat until quotient is zero.
			// 
			// however, we are unable to write normal arirthmetic operations here because the operands are 128-bits, and we can do at best 64-bits!
			// the solution is to do "long division", i.e. division in smaller, manageable units, and carry over the remainder to lower places
			// we choose to break the number into 32-bits at a time, so that we can use 64-bit arirthmetic to accomodate each part plus the carry over
			// put another way, we are "rewriting" the 128-bit number as a 4-digit base 2^32 number
			//
			// thus, our long division algorithm now looks like this:
			// A. divide the most significant word by base, quotient is most significant word of overall quotient
			// B. divide the number (remainder * word base + next most significant word) by base, quotient is next most significant word of overall quotient
			// C. repeat until least significant word, where the remainder is simply the overall remainder
			//
			// the resulting algorithm is perhaps more convoluted than if we were to divide one byte at a time, but this does make it more efficient since
			// we are leveraging the CPU's native 32/64-bit binary base for arithmetic
			//
			// NOTE: The simpler algorithm for converting between bases is to start from the most significant digit, multiply by base, add next most
			// significant digit, multiply all that by base, and so on until you finish the sequence of digits. This does not work for us, because the
			// result of each stage is exponentially increasing, and you will quickly exceed the capabilities of native CPU arithmetic.

			// convert the 128-bits of the GUID to 4x 32-bit unsigned ints
			var bytes = GuidToSystemEndianBytes(guid);

			// allocate space for the string - we know it's at most 39 decimal digits
			const int maxDigits = 39;
			var chars = new char[maxDigits];

			fixed (char* pChars = chars)
			fixed (byte* pBytes = bytes)
			{
				// algorithm produces least significant digit first, so we set digits from the end of the string, and keep track of how many digits
				var countDigits = 0;
				var pC = &pChars[maxDigits - 1];

				// casts the bytes to a uint pointer, since we've rearranged the GUID as such
				var pB = (uint*) pBytes;
				do
				{
					// take the first word, divide by 10, and keep the quotient for the next round of calculations
					ulong r = pB[0];
					ulong q = r/10;
					pB[0] = (uint) q;

					// the remainder (i.e. r - q*10) is prepended to the second word as the most significant digit
					// and then divide by 10, and keep the quotient for the next round of calculations
					r = ((r - q*10) << 32) + pB[1];
					q = r/10;
					pB[1] = (uint) q;

					// the remainder is prepended to the third word as the most significant digit
					// and then divide by 10, and keep the quotient for the next round of calculations
					r = ((r - q*10) << 32) + pB[2];
					q = r/10;
					pB[2] = (uint) q;

					// the remainder is prepended to the fourth word as the most significant digit
					// and then divide by 10, and keep the quotient for the next round of calculations
					r = ((r - q*10) << 32) + pB[3];
					q = r/10;
					pB[3] = (uint) q;

					// the remainder is the next decimal digit in the result
					r = r - q*10;

					// the digits are yielded from least to most significant, so we fill the char array from the end
					*pC-- = (char) ('0' + r); // '0'+r being a way of converting a number between 0 and 9 to the equivalent character '0' to '9'

					// and keep track of how many digits that is
					++countDigits;

					// when the dividend for the next round of calculations is 0 (i.e. all words are 0), we are done
				} while (pB[0] != 0 || pB[1] != 0 || pB[2] != 0 || pB[3] != 0);

				// now return a string based on the pointer and offset based on number of digits we actually produced
				// note that the loop always produces at least one digit, even if that is '0'
				return new string(pChars, maxDigits - countDigits, countDigits);
			}
		}