예제 #1
0
            /// <summary>
            /// Gets the hash of a JSON string value.
            /// </summary>
            /// <param name="value">The value to hash.</param>
            /// <param name="seed">The seed to use.</param>
            /// <returns>The hash of a JSON string value.</returns>
            private UInt192 GetStringHash(string value, UInt192 seed)
            {
                UInt192 hash = this.GetHash(this.HashSeedValues.String, seed);

                byte[] stringBytes = Encoding.UTF8.GetBytes(value);
                return(this.GetHash(stringBytes, hash));
            }
        /// <summary>
        /// Gets the hash of a JSON number value.
        /// </summary>
        /// <param name="number">The number to hash.</param>
        /// <param name="seed">The seed to use.</param>
        /// <returns>The hash of a JSON number value.</returns>
        private static UInt192 GetNumberHash(double number, UInt192 seed)
        {
            UInt192 hash = DistinctHash.GetHash(DistinctHash.NumberHashSeed, seed);

            hash = DistinctHash.GetHash((UInt192)BitConverter.DoubleToInt64Bits(number), hash);
            return(hash);
        }
예제 #3
0
            /// <summary>
            /// Gets the hash of a JSON number value.
            /// </summary>
            /// <param name="number">The number to hash.</param>
            /// <param name="seed">The seed to use.</param>
            /// <returns>The hash of a JSON number value.</returns>
            private UInt192 GetNumberHash(double number, UInt192 seed)
            {
                UInt192 hash = this.GetHash(this.HashSeedValues.Number, seed);

                hash = this.GetHash((UInt192)BitConverter.DoubleToInt64Bits(number), hash);
                return(hash);
            }
예제 #4
0
            /// <summary>
            /// Gets the hash of a byte array.
            /// </summary>
            /// <param name="bytes">The bytes.</param>
            /// <param name="seed">The seed.</param>
            /// <returns>The hash.</returns>
            public UInt192 GetHash(byte[] bytes, UInt192 seed)
            {
                UInt128 hash128 = MurmurHash3.Hash128(bytes, bytes.Length, UInt128.Create(seed.GetLow(), seed.GetMid()));
                ulong   hash64  = MurmurHash3.Hash64(bytes, bytes.Length, seed.GetHigh());

                return(UInt192.Create(hash128.GetLow(), hash128.GetHigh(), hash64));
            }
        /// <summary>
        /// Gets the hash of a JSON string value.
        /// </summary>
        /// <param name="value">The value to hash.</param>
        /// <param name="seed">The seed to use.</param>
        /// <returns>The hash of a JSON string value.</returns>
        private static UInt192 GetStringHash(string value, UInt192 seed)
        {
            UInt192 hash = DistinctHash.GetHash(DistinctHash.StringHashSeed, seed);

            byte[] stringBytes = Encoding.UTF8.GetBytes(value);
            return(DistinctHash.GetHash(stringBytes, hash));
        }
        /// <summary>
        /// Gets the hash of a JSON object.
        /// </summary>
        /// <param name="cosmosObject">The object to hash.</param>
        /// <param name="seed">The seed to use.</param>
        /// <returns>The hash of a JSON object.</returns>
        private static UInt192 GetObjectHash(CosmosObject cosmosObject, UInt192 seed)
        {
            // Start the object with a distinct hash, so that empty object doesn't hash to another value.
            UInt192 hash = DistinctHash.GetHash(DistinctHash.ObjectHashSeed, seed);

            //// Intermediate hashes of all the properties, which we don't want to xor with the final hash
            //// otherwise the following will collide:
            ////{
            ////    "pet":{
            ////        "name":"alice",
            ////        "age":5
            ////    },
            ////    "pet2":{
            ////        "name":"alice",
            ////        "age":5
            ////    }
            ////}
            ////
            ////{
            ////    "pet":{
            ////        "name":"bob",
            ////        "age":5
            ////    },
            ////    "pet2":{
            ////        "name":"bob",
            ////        "age":5
            ////    }
            ////}
            //// because they only differ on the name, but it gets repeated meaning that
            //// hash({"name":"bob", "age":5}) ^ hash({"name":"bob", "age":5}) is the same as
            //// hash({"name":"alice", "age":5}) ^ hash({"name":"alice", "age":5})
            UInt192 intermediateHash = 0;

            // Property order should not result in a different hash.
            // This is consistent with equality comparison.
            foreach (KeyValuePair <string, CosmosElement> kvp in cosmosObject)
            {
                UInt192 nameHash = DistinctHash.GetHash(
                    CosmosString.Create(kvp.Key),
                    DistinctHash.PropertyNameHashSeed);
                UInt192 propertyHash = DistinctHash.GetHash(kvp.Value, nameHash);

                //// xor is symmetric meaning that a ^ b = b ^ a
                //// Which is great since now we can add the property hashes to the intermediate hash
                //// in any order and get the same result, which upholds our definition of equality.
                //// Note that we don't have to worry about a ^ a = 0 = b ^ b for duplicate property values,
                //// since the hash of property values are seeded with the hash of property names,
                //// which are unique within an object.
                intermediateHash ^= propertyHash;
            }

            // Only if the object was not empty do we want to bring in the intermediate hash.
            if (intermediateHash > 0)
            {
                hash = DistinctHash.GetHash(intermediateHash, hash);
            }

            return(hash);
        }
예제 #7
0
                /// <summary>
                /// Reads the nullable UInt192
                /// </summary>
                /// <param name="reader">The reader to read from.</param>
                /// <param name="objectType">The object type.</param>
                /// <param name="existingValue">The existing value.</param>
                /// <param name="serializer">The serializer.</param>
                /// <returns>The nullable UInt192.</returns>
                public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
                {
                    if (reader.Value == null)
                    {
                        return(null);
                    }

                    return(UInt192.Parse(reader.Value.ToString()));
                }
        /// <summary>
        /// Gets the hash of a byte array.
        /// </summary>
        /// <param name="bytes">The bytes.</param>
        /// <param name="seed">The seed.</param>
        /// <returns>The hash.</returns>
        public static UInt192 GetHash(byte[] bytes, UInt192 seed)
        {
            // TODO: Have MurmurHash3 work on Span<T> instead.
            Documents.UInt128 hash128 = Microsoft.Azure.Documents.Routing.MurmurHash3.Hash128(
                bytes,
                bytes.Length,
                Documents.UInt128.Create(seed.GetLow(), seed.GetMid()));
            ulong hash64 = Microsoft.Azure.Documents.Routing.MurmurHash3.Hash64(bytes, bytes.Length, seed.GetHigh());

            return(UInt192.Create(hash128.GetLow(), hash128.GetHigh(), hash64));
        }
        /// <summary>
        /// Gets the hash of a JToken given a seed.
        /// </summary>
        /// <param name="cosmosElement">The cosmos element to hash.</param>
        /// <param name="seed">The seed to use.</param>
        /// <returns>The hash of the JToken.</returns>
        private static UInt192 GetHash(CosmosElement cosmosElement, UInt192 seed)
        {
            if (cosmosElement == null)
            {
                return(DistinctHash.GetUndefinedHash(seed));
            }

            CosmosElementType cosmosElementType = cosmosElement.Type;
            UInt192           hash;

            switch (cosmosElementType)
            {
            case CosmosElementType.Array:
                hash = DistinctHash.GetArrayHash(cosmosElement as CosmosArray, seed);
                break;

            case CosmosElementType.Boolean:
                hash = DistinctHash.GetBooleanHash((cosmosElement as CosmosBoolean).Value, seed);
                break;

            case CosmosElementType.Null:
                hash = DistinctHash.GetNullHash(seed);
                break;

            case CosmosElementType.Number:
                // TODO: we need to differentiate between the different number types.
                CosmosNumber cosmosNumber = cosmosElement as CosmosNumber;
                double       number;
                if (cosmosNumber.IsFloatingPoint)
                {
                    number = cosmosNumber.AsFloatingPoint().Value;
                }
                else
                {
                    number = cosmosNumber.AsInteger().Value;
                }

                hash = DistinctHash.GetNumberHash(number, seed);
                break;

            case CosmosElementType.Object:
                hash = DistinctHash.GetObjectHash(cosmosElement as CosmosObject, seed);
                break;

            case CosmosElementType.String:
                hash = DistinctHash.GetStringHash((cosmosElement as CosmosString).Value, seed);
                break;

            default:
                throw new ArgumentException($"Unexpected {nameof(CosmosElementType)} : {cosmosElementType}");
            }

            return(hash);
        }
예제 #10
0
            /// <summary>
            /// Gets the hash of a JToken given a seed.
            /// </summary>
            /// <param name="cosmosElement">The cosmos element to hash.</param>
            /// <param name="seed">The seed to use.</param>
            /// <returns>The hash of the JToken.</returns>
            private UInt192 GetHashToken(CosmosElement cosmosElement, UInt192 seed)
            {
                if (cosmosElement == null)
                {
                    return(this.GetUndefinedHash(seed));
                }

                CosmosElementType cosmosElementType = cosmosElement.Type;
                UInt192           hash;

                switch (cosmosElementType)
                {
                case CosmosElementType.Array:
                    hash = this.GetArrayHash(cosmosElement as CosmosArray, seed);
                    break;

                case CosmosElementType.Boolean:
                    hash = this.GetBooleanHash((cosmosElement as CosmosBoolean).Value, seed);
                    break;

                case CosmosElementType.Null:
                    hash = this.GetNullHash(seed);
                    break;

                case CosmosElementType.Number:
                    CosmosNumber cosmosNumber = (cosmosElement as CosmosNumber);
                    double       number;
                    if (cosmosNumber.IsFloatingPoint)
                    {
                        number = cosmosNumber.AsFloatingPoint().Value;
                    }
                    else
                    {
                        number = cosmosNumber.AsInteger().Value;
                    }

                    hash = this.GetNumberHash(number, seed);
                    break;

                case CosmosElementType.Object:
                    hash = this.GetObjectHash(cosmosElement as CosmosObject, seed);
                    break;

                case CosmosElementType.String:
                    hash = this.GetStringHash((cosmosElement as CosmosString).Value, seed);
                    break;

                default:
                    throw new ArgumentException($"Unexpected {nameof(CosmosElementType)} : {cosmosElementType}");
                }

                return(hash);
            }
예제 #11
0
 /// <summary>
 /// Writes the nullable UInt192
 /// </summary>
 /// <param name="writer">The writer.</param>
 /// <param name="value">The value.</param>
 /// <param name="serializer">The serializer.</param>
 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
 {
     if (value == null)
     {
         writer.WriteNull();
     }
     else
     {
         UInt192 uint192 = (UInt192)value;
         JToken  token   = JToken.FromObject(uint192.ToString());
         token.WriteTo(writer);
     }
 }
예제 #12
0
            /// <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);
            }
예제 #13
0
            /// <summary>
            /// Adds a JToken to this map if it hasn't already been added.
            /// </summary>
            /// <param name="cosmosElement">The element to add.</param>
            /// <param name="hash">The hash of the token.</param>
            /// <returns>Whether or not the item was added to this Distinct Map.</returns>
            /// <remarks>This function assumes data is added in sorted order.</remarks>
            public override bool Add(CosmosElement cosmosElement, out UInt192?hash)
            {
                hash = DistinctMap.GetHash(cosmosElement);

                bool added;

                if (this.lastHash != hash)
                {
                    this.lastHash = hash.Value;
                    added         = true;
                }
                else
                {
                    added = false;
                }

                return(added);
            }
예제 #14
0
            /// <summary>
            /// Adds a JToken to this map if it hasn't already been added.
            /// </summary>
            /// <param name="jToken">The token to add.</param>
            /// <param name="hash">The hash of the token.</param>
            /// <returns>Whether or not the item was added to this Distinct Map.</returns>
            /// <remarks>This function assumes data is added in sorted order.</remarks>
            public override bool Add(JToken jToken, out UInt192?hash)
            {
                hash = DistinctMap.GetHash(jToken);

                bool added;

                if (this.lastHash != hash)
                {
                    this.lastHash = hash.Value;
                    added         = true;
                }
                else
                {
                    added = false;
                }

                return(added);
            }
예제 #15
0
            /// <summary>
            /// Gets the hash of a JToken given a seed.
            /// </summary>
            /// <param name="value">The JToken to hash.</param>
            /// <param name="seed">The seed to use.</param>
            /// <returns>The hash of the JToken.</returns>
            private UInt192 GetHashToken(JToken value, UInt192 seed)
            {
                JTokenType jTokenType = value.Type;

                switch (jTokenType)
                {
                case JTokenType.Object:
                    return(this.GetObjectHash((JObject)value, seed));

                case JTokenType.Array:
                    return(this.GetArrayHash((JArray)value, seed));

                case JTokenType.Integer:
                case JTokenType.Float:
                    return(this.GetNumberHash((double)value, seed));

                case JTokenType.Guid:
                case JTokenType.TimeSpan:
                case JTokenType.Uri:
                case JTokenType.Date:
                case JTokenType.String:
                    return(this.GetStringHash(value.ToString(), seed));

                case JTokenType.Boolean:
                    return(this.GetBooleanHash((bool)value, seed));

                case JTokenType.Null:
                    return(this.GetNullHash(seed));

                case JTokenType.None:
                case JTokenType.Undefined:
                    return(this.GetUndefinedHash(seed));

                case JTokenType.Constructor:
                case JTokenType.Property:
                case JTokenType.Comment:
                case JTokenType.Raw:
                case JTokenType.Bytes:
                default:
                    throw new ArgumentException($"Unexpected JTokenType of: {jTokenType}");
                }
            }
        /// <summary>
        /// Gets the hash of a JSON array.
        /// </summary>
        /// <param name="cosmosArray">The array to hash.</param>
        /// <param name="seed">The seed to use.</param>
        /// <returns>The hash of a JSON array.</returns>
        private static UInt192 GetArrayHash(CosmosArray cosmosArray, UInt192 seed)
        {
            // Start the array with a distinct hash, so that empty array doesn't hash to another value.
            UInt192 hash = DistinctHash.GetHash(DistinctHash.ArrayHashSeed, seed);

            // Incorporate all the array items into the hash.
            for (int index = 0; index < cosmosArray.Count; index++)
            {
                CosmosElement arrayItem = cosmosArray[index];

                // Order of array items matter in equality check, so we add the index just to be safe.
                // For now we know that murmurhash will correctly give a different hash for
                // [true, false, true] and [true, true, false]
                // due to the way the seed works.
                // But we add the index just incase that property does not hold in the future.
                UInt192 arrayItemSeed = DistinctHash.ArrayIndexHashSeed + index;
                hash = DistinctHash.GetHash(hash, DistinctHash.GetHash(arrayItem, arrayItemSeed));
            }

            return(hash);
        }
예제 #17
0
 /// <summary>
 /// Initializes a new instance of the HashSeeds struct.
 /// </summary>
 /// <param name="rootHashSeed">The seed used for the JSON root.</param>
 /// <param name="nullHashSeed">The seed used for JSON null values.</param>
 /// <param name="falseHashSeed">The seed used for JSON false values.</param>
 /// <param name="trueHashSeed">The seed used for JSON true values.</param>
 /// <param name="numberHashSeed">The seed used for JSON number values.</param>
 /// <param name="stringHashSeed">The seed used for JSON string values.</param>
 /// <param name="arrayHashSeed">The seed used for JSON array values.</param>
 /// <param name="objectHashSeed">The seed used for JSON object values.</param>
 /// <param name="arrayIndexHashSeed">The seed used for JSON array elements.</param>
 /// <param name="propertyNameHashSeed">The seed used for JSON property names.</param>
 public HashSeeds(
     UInt192 rootHashSeed,
     UInt192 nullHashSeed,
     UInt192 falseHashSeed,
     UInt192 trueHashSeed,
     UInt192 numberHashSeed,
     UInt192 stringHashSeed,
     UInt192 arrayHashSeed,
     UInt192 objectHashSeed,
     UInt192 arrayIndexHashSeed,
     UInt192 propertyNameHashSeed)
 {
     this.Root         = rootHashSeed;
     this.Null         = nullHashSeed;
     this.False        = falseHashSeed;
     this.True         = trueHashSeed;
     this.Number       = numberHashSeed;
     this.String       = stringHashSeed;
     this.Array        = arrayHashSeed;
     this.Object       = objectHashSeed;
     this.ArrayIndex   = arrayIndexHashSeed;
     this.PropertyName = propertyNameHashSeed;
 }
예제 #18
0
 /// <summary>
 /// Initializes a new instance of the OrderedDistinctMap class.
 /// </summary>
 /// <param name="lastHash">The previous hash from the previous continuation.</param>
 public OrderedDistinctMap(UInt192 lastHash)
 {
     this.lastHash = lastHash;
 }
예제 #19
0
        public override async Task <QueryResponseCore> DrainAsync(
            int maxElements,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // Draining GROUP BY is broken down into two stages:
            QueryResponseCore response;

            if (!this.Source.IsDone)
            {
                // Stage 1:
                // Drain the groupings fully from all continuation and all partitions
                QueryResponseCore sourceResponse = await base.DrainAsync(int.MaxValue, cancellationToken);

                if (!sourceResponse.IsSuccess)
                {
                    return(sourceResponse);
                }

                foreach (CosmosElement result in sourceResponse.CosmosElements)
                {
                    // Aggregate the values for all groupings across all continuations.
                    RewrittenGroupByProjection groupByItem = new RewrittenGroupByProjection(result);
                    UInt192 groupByKeysHash = DistinctHash.GetHash(groupByItem.GroupByItems);

                    if (!this.groupingTable.TryGetValue(groupByKeysHash, out SingleGroupAggregator singleGroupAggregator))
                    {
                        singleGroupAggregator = SingleGroupAggregator.Create(
                            this.cosmosQueryClient,
                            EmptyAggregateOperators,
                            this.groupByAliasToAggregateType,
                            this.orderedAliases,
                            this.hasSelectValue,
                            continuationToken: null);
                        this.groupingTable[groupByKeysHash] = singleGroupAggregator;
                    }

                    CosmosElement payload = groupByItem.Payload;
                    singleGroupAggregator.AddValues(payload);
                }

                // We need to give empty pages until the results are fully drained.
                response = QueryResponseCore.CreateSuccess(
                    result: EmptyResults,
                    continuationToken: null,
                    disallowContinuationTokenMessage: GroupByDocumentQueryExecutionComponent.ContinuationTokenNotSupportedWithGroupBy,
                    activityId: sourceResponse.ActivityId,
                    requestCharge: sourceResponse.RequestCharge,
                    diagnostics: sourceResponse.Diagnostics,
                    responseLengthBytes: sourceResponse.ResponseLengthBytes);

                this.isDone = false;
            }
            else
            {
                // Stage 2:
                // Emit the results from the grouping table page by page
                IEnumerable <SingleGroupAggregator> groupByValuesList = this.groupingTable
                                                                        .OrderBy(kvp => kvp.Key)
                                                                        .Skip(this.numPagesDrainedFromGroupingTable * maxElements)
                                                                        .Take(maxElements)
                                                                        .Select(kvp => kvp.Value);

                List <CosmosElement> results = new List <CosmosElement>();
                foreach (SingleGroupAggregator groupByValues in groupByValuesList)
                {
                    results.Add(groupByValues.GetResult());
                }

                response = QueryResponseCore.CreateSuccess(
                    result: results,
                    continuationToken: null,
                    disallowContinuationTokenMessage: GroupByDocumentQueryExecutionComponent.ContinuationTokenNotSupportedWithGroupBy,
                    activityId: null,
                    requestCharge: 0,
                    diagnostics: QueryResponseCore.EmptyDiagnostics,
                    responseLengthBytes: 0);

                this.numPagesDrainedFromGroupingTable++;
                if (this.numPagesDrainedFromGroupingTable * maxElements >= this.groupingTable.Count)
                {
                    this.isDone = true;
                }
            }

            return(response);
        }
 /// <summary>
 /// Gets the hash given a value and a seed.
 /// </summary>
 /// <param name="value">The value to hash.</param>
 /// <param name="seed">The seed.</param>
 /// <returns>The hash.</returns>
 public static UInt192 GetHash(UInt192 value, UInt192 seed)
 {
     return(DistinctHash.GetHash(UInt192.ToByteArray(value), seed));
 }
예제 #21
0
 /// <summary>
 /// Gets the hash given a value and a seed.
 /// </summary>
 /// <param name="value">The value to hash.</param>
 /// <param name="seed">The seed.</param>
 /// <returns>The hash.</returns>
 public UInt192 GetHash(UInt192 value, UInt192 seed)
 {
     return(this.GetHash(UInt192.ToByteArray(value), seed));
 }
예제 #22
0
 /// <summary>
 /// Gets the hash of a null JSON value.
 /// </summary>
 /// <param name="seed">The seed to use.</param>
 /// <returns>The hash of a null JSON value given a seed.</returns>
 private UInt192 GetNullHash(UInt192 seed)
 {
     return(this.GetHash(this.HashSeedValues.Null, seed));
 }
예제 #23
0
 /// <summary>
 /// Gets the hash of a boolean JSON value.
 /// </summary>
 /// <param name="boolean">The boolean to hash.</param>
 /// <param name="seed">The seed.</param>
 /// <returns>The hash of a boolean JSON value.</returns>
 private UInt192 GetBooleanHash(bool boolean, UInt192 seed)
 {
     return(this.GetHash(boolean ? this.HashSeedValues.True : this.HashSeedValues.False, seed));
 }
 /// <summary>
 /// Gets the hash of a boolean JSON value.
 /// </summary>
 /// <param name="boolean">The boolean to hash.</param>
 /// <param name="seed">The seed.</param>
 /// <returns>The hash of a boolean JSON value.</returns>
 private static UInt192 GetBooleanHash(bool boolean, UInt192 seed)
 {
     return(DistinctHash.GetHash(boolean ? DistinctHash.TrueHashSeed : DistinctHash.FalseHashSeed, seed));
 }
 /// <summary>
 /// Gets the hash of a null JSON value.
 /// </summary>
 /// <param name="seed">The seed to use.</param>
 /// <returns>The hash of a null JSON value given a seed.</returns>
 private static UInt192 GetNullHash(UInt192 seed)
 {
     return(DistinctHash.GetHash(DistinctHash.NullHashSeed, seed));
 }
        /// <summary>
        /// Compares to objects and returns their partial sort relationship.
        /// </summary>
        /// <param name="element1">The first element to compare.</param>
        /// <param name="element2">The second element to compare.</param>
        /// <returns>
        /// Less than zero if obj1 comes before obj2 in the sort order.
        /// Zero if obj1 and obj2 are interchangeable in the sort order.
        /// Greater than zero if obj2 comes before obj1 in the sort order.
        /// </returns>
        public int Compare(CosmosElement element1, CosmosElement element2)
        {
            if (object.ReferenceEquals(element1, element2))
            {
                return(0);
            }

            if (object.ReferenceEquals(element1, MinValueItem.Singleton))
            {
                return(-1);
            }

            if (object.ReferenceEquals(element2, MinValueItem.Singleton))
            {
                return(1);
            }

            if (object.ReferenceEquals(element1, MaxValueItem.Singleton))
            {
                return(1);
            }

            if (object.ReferenceEquals(element2, MaxValueItem.Singleton))
            {
                return(-1);
            }

            if (element1 == Undefined)
            {
                return(-1);
            }

            if (element2 == Undefined)
            {
                return(1);
            }

            CosmosElementType type1 = element1.Type;

            int cmp = CompareTypes(element1, element2);

            if (cmp == 0)
            {
                // If they are the same type then you need to break the tie.
                switch (type1)
                {
                case CosmosElementType.Boolean:
                    cmp = Comparer <bool> .Default.Compare(
                        (element1 as CosmosBoolean).Value,
                        (element2 as CosmosBoolean).Value);

                    break;

                case CosmosElementType.Null:
                    // All nulls are the same.
                    cmp = 0;
                    break;

                case CosmosElementType.Number:
                    CosmosNumber number1 = element1 as CosmosNumber;
                    CosmosNumber number2 = element2 as CosmosNumber;
                    if (number1.NumberType == CosmosNumberType.Number64)
                    {
                        double double1;
                        if (number1.IsFloatingPoint)
                        {
                            double1 = number1.AsFloatingPoint().Value;
                        }
                        else
                        {
                            double1 = number1.AsInteger().Value;
                        }

                        double double2;
                        if (number2.IsFloatingPoint)
                        {
                            double2 = number2.AsFloatingPoint().Value;
                        }
                        else
                        {
                            double2 = number2.AsInteger().Value;
                        }

                        cmp = Comparer <double> .Default.Compare(
                            double1,
                            double2);
                    }
                    else if (number1.IsFloatingPoint)
                    {
                        double double1 = number1.AsFloatingPoint().Value;
                        double double2 = number2.AsFloatingPoint().Value;
                        cmp = Comparer <double> .Default.Compare(double1, double2);
                    }
                    else
                    {
                        long integer1 = number1.AsInteger().Value;
                        long integer2 = number2.AsInteger().Value;
                        cmp = Comparer <long> .Default.Compare(integer1, integer2);
                    }

                    break;

                case CosmosElementType.String:
                    CosmosString string1 = element1 as CosmosString;
                    CosmosString string2 = element2 as CosmosString;
                    cmp = string.CompareOrdinal(
                        string1.Value,
                        string2.Value);
                    break;

                case CosmosElementType.Guid:
                    CosmosGuid guid1 = element1 as CosmosGuid;
                    CosmosGuid guid2 = element2 as CosmosGuid;
                    cmp = guid1.Value.CompareTo(guid2.Value);
                    break;

                case CosmosElementType.Binary:
                    CosmosBinary binary1 = element1 as CosmosBinary;
                    CosmosBinary binary2 = element2 as CosmosBinary;
                    cmp = ItemComparer.CompareTo(binary1, binary2);
                    break;

                case CosmosElementType.Array:
                case CosmosElementType.Object:
                {
                    UInt192 hash1 = DistinctHash.GetHash(element1);
                    UInt192 hash2 = DistinctHash.GetHash(element2);
                    return(hash1.CompareTo(hash2));
                }

                default:
                    throw new ArgumentException($"Unknown: {nameof(CosmosElementType)}: {type1}");
                }
            }

            return(cmp);
        }
예제 #27
0
            /// <summary>
            /// Adds an array value to the distinct map.
            /// </summary>
            /// <param name="array">The array to add.</param>
            /// <returns>Whether or not the value was successfully added.</returns>
            private bool AddArrayValue(CosmosArray array)
            {
                UInt192 hash = DistinctMap.GetHash(array);

                return(this.arrays.Add(hash));
            }
예제 #28
0
            /// <summary>
            /// Adds an object value to the distinct map.
            /// </summary>
            /// <param name="cosmosObject">The object to add.</param>
            /// <returns>Whether or not the value was successfully added.</returns>
            private bool AddObjectValue(CosmosObject cosmosObject)
            {
                UInt192 hash = DistinctMap.GetHash(cosmosObject);

                return(this.objects.Add(hash));
            }
 /// <summary>
 /// Gets the hash of a undefined JSON value.
 /// </summary>
 /// <param name="seed">The seed to use.</param>
 /// <returns>The hash of a undefined JSON value.</returns>
 private static UInt192 GetUndefinedHash(UInt192 seed)
 {
     return(seed);
 }