private static HashSet <UInt128> Parse128BitHashes(CosmosObject hashDictionary, string propertyName) { HashSet <UInt128> hashSet = new HashSet <UInt128>(); if (!hashDictionary.TryGetValue(propertyName, out CosmosArray array)) { throw new MalformedContinuationTokenException( $"{nameof(UnorderdDistinctMap)} continuation token was malformed."); } foreach (CosmosElement item in array) { if (!(item is CosmosBinary binary)) { throw new MalformedContinuationTokenException( $"{nameof(UnorderdDistinctMap)} continuation token was malformed."); } // Todo have this method work with span<byte> instead to avoid the allocation. UInt128 uint128 = UInt128.FromByteArray(binary.Value.ToArray()); hashSet.Add(uint128); } return(hashSet); }
/// <summary> /// Adds a string to the distinct map. /// </summary> /// <param name="value">The string to add.</param> /// <returns>Whether or not the value was successfully added.</returns> private bool AddStringValue(string value) { bool added = false; int utf8Length = Encoding.UTF8.GetByteCount(value); // If you fit the string with full fidelity in 24 bytes, then you might as well just hash the string. if (utf8Length <= UnorderdDistinctMap.UInt192Length) { // Zero out the array since you want all trailing bytes to be 0 for the conversions that happen next. Array.Clear(this.utf8Buffer, 0, this.utf8Buffer.Length); Encoding.UTF8.GetBytes(value, 0, utf8Length, this.utf8Buffer, 0); if (utf8Length == 0) { added = this.AddSimpleValue(SimpleValues.EmptyString); } else if (utf8Length <= UnorderdDistinctMap.UIntLength) { uint uintValue = BitConverter.ToUInt32(this.utf8Buffer, 0); added = this.stringsLength4.Add(uintValue); } else if (utf8Length <= UnorderdDistinctMap.ULongLength) { ulong uLongValue = BitConverter.ToUInt64(this.utf8Buffer, 0); added = this.stringLength8.Add(uLongValue); } else if (utf8Length <= UnorderdDistinctMap.UInt128Length) { UInt128 uInt128Value = UInt128.FromByteArray(this.utf8Buffer, 0); added = this.stringLength16.Add(uInt128Value); } else { UInt192 uInt192Value = UInt192.FromByteArray(this.utf8Buffer, 0); added = this.stringLength24.Add(uInt192Value); } } else { // Else the string is too large and we will just store the hash. UInt192 uint192Value = DistinctMap.GetHash(CosmosString.Create(value)); added = this.stringLength24Plus.Add(uint192Value); } return(added); }
/// <summary> /// Adds a string to the distinct map. /// </summary> /// <param name="value">The string to add.</param> /// <returns>Whether or not the value was successfully added.</returns> private bool AddStringValue(string value) { bool added = false; int utf8Length = Encoding.UTF8.GetByteCount(value); // If you can fit the string with full fidelity in 16 bytes, then you might as well just hash the string itself. if (utf8Length <= UnorderdDistinctMap.UInt128Length) { Span <byte> utf8Buffer = stackalloc byte[UInt128Length]; Encoding.UTF8.GetBytes(value, utf8Buffer); if (utf8Length == 0) { added = this.AddSimpleValue(SimpleValues.EmptyString); } else if (utf8Length <= UnorderdDistinctMap.UIntLength) { uint uintValue = MemoryMarshal.Read <uint>(utf8Buffer); added = this.stringsLength4.Add(uintValue); } else if (utf8Length <= UnorderdDistinctMap.ULongLength) { ulong uLongValue = MemoryMarshal.Read <ulong>(utf8Buffer); added = this.stringsLength8.Add(uLongValue); } else { UInt128 uInt128Value = UInt128.FromByteArray(utf8Buffer); added = this.stringsLength16.Add(uInt128Value); } } else { // Else the string is too large and we will just store the hash. UInt128 uint128Value = DistinctHash.GetHash(CosmosString.Create(value)); added = this.stringsLength16Plus.Add(uint128Value); } return(added); }