예제 #1
0
        /// <summary>
        /// Moves unique entries to the front of the list.
        /// </summary>
        private int MoveUniqueEntriesToFront(List <OrderByPropertyEntry> sortedData, OrderByPropertyComparer comparer)
        {
            // If we have sorted data then we know we have at least one unique item
            int uniqueCount = sortedData.Count > 0 ? 1 : 0;

            // Move the first of each unique entry to the front of the list
            for (int uniqueItemIndex = 0, nextUniqueItemIndex = 1; uniqueItemIndex < sortedData.Count && uniqueCount != Top; uniqueItemIndex++, nextUniqueItemIndex++)
            {
                // Identify the index of the next unique item
                while (nextUniqueItemIndex < sortedData.Count && comparer.Compare(sortedData[uniqueItemIndex], sortedData[nextUniqueItemIndex]) == 0)
                {
                    nextUniqueItemIndex++;
                }

                // If there are no more unique items, break
                if (nextUniqueItemIndex == sortedData.Count)
                {
                    break;
                }

                // Move the next unique item forward and increment the unique item counter
                sortedData[uniqueItemIndex + 1] = sortedData[nextUniqueItemIndex];
                uniqueCount++;
            }

            return(uniqueCount);
        }
예제 #2
0
        /// <summary>
        /// Process every input object to group them.
        /// </summary>
        protected override void ProcessRecord()
        {
            if (InputObject != null && InputObject != AutomationNull.Value)
            {
                OrderByPropertyEntry currentEntry = null;

                if (!_hasProcessedFirstInputObject)
                {
                    if (Property == null)
                    {
                        Property = OrderByProperty.GetDefaultKeyPropertySet(InputObject);
                    }
                    _orderByProperty.ProcessExpressionParameter(this, Property);

                    currentEntry = _orderByProperty.CreateOrderByPropertyEntry(this, InputObject, CaseSensitive, _cultureInfo);
                    bool[] ascending = new bool[currentEntry.orderValues.Count];
                    for (int index = 0; index < currentEntry.orderValues.Count; index++)
                    {
                        ascending[index] = true;
                    }
                    _orderByPropertyComparer = new OrderByPropertyComparer(ascending, _cultureInfo, CaseSensitive);

                    _hasProcessedFirstInputObject = true;
                }
                else
                {
                    currentEntry = _orderByProperty.CreateOrderByPropertyEntry(this, InputObject, CaseSensitive, _cultureInfo);
                }

                DoGrouping(currentEntry, this.NoElement, _groups, _tupleToGroupInfoMappingDictionary, _orderByPropertyComparer);
            }
        }
예제 #3
0
        /// <summary>
        /// Process every input object to group them.
        /// </summary>
        protected override void ProcessRecord()
        {
            if (InputObject != null && InputObject != AutomationNull.Value)
            {
                OrderByPropertyEntry currentEntry;

                if (!_hasProcessedFirstInputObject)
                {
                    if (Property == null)
                    {
                        Property = OrderByProperty.GetDefaultKeyPropertySet(InputObject);
                    }

                    _orderByProperty.ProcessExpressionParameter(this, Property);

                    if (AsString && !AsHashTable)
                    {
                        ArgumentException ex = new ArgumentException(UtilityCommonStrings.GroupObjectWithHashTable);
                        ErrorRecord       er = new ErrorRecord(ex, "ArgumentException", ErrorCategory.InvalidArgument, AsString);
                        ThrowTerminatingError(er);
                    }

                    if (AsHashTable && !AsString && (Property != null && (Property.Length > 1 || _orderByProperty.MshParameterList.Count > 1)))
                    {
                        ArgumentException ex = new ArgumentException(UtilityCommonStrings.GroupObjectSingleProperty);
                        ErrorRecord       er = new ErrorRecord(ex, "ArgumentException", ErrorCategory.InvalidArgument, Property);
                        ThrowTerminatingError(er);
                    }

                    currentEntry = _orderByProperty.CreateOrderByPropertyEntry(this, InputObject, CaseSensitive, _cultureInfo);
                    bool[] ascending = new bool[currentEntry.orderValues.Count];
                    for (int index = 0; index < currentEntry.orderValues.Count; index++)
                    {
                        ascending[index] = true;
                    }

                    _orderByPropertyComparer = new OrderByPropertyComparer(ascending, _cultureInfo, CaseSensitive);

                    _hasProcessedFirstInputObject = true;
                }
                else
                {
                    currentEntry = _orderByProperty.CreateOrderByPropertyEntry(this, InputObject, CaseSensitive, _cultureInfo);
                }

                _entriesToOrder.Add(currentEntry);

                var currentEntryOrderValues = currentEntry.orderValues;
                if (!_hasDifferentValueTypes)
                {
                    UpdateOrderPropertyTypeInfo(currentEntryOrderValues);
                }
            }
        }
예제 #4
0
        private static OrderByPropertyComparer CreateComparer(
            List <OrderByPropertyEntry> orderMatrix,
            List <MshParameter> mshParameterList,
            bool ascending,
            CultureInfo cultureInfo,
            bool caseSensitive)
        {
            if (orderMatrix == null || orderMatrix.Count == 0)
            {
                return(null);
            }

            bool?[] ascendingOverrides = null;
            if (mshParameterList != null && mshParameterList.Count != 0)
            {
                ascendingOverrides = new bool?[mshParameterList.Count];
                for (int k = 0; k < ascendingOverrides.Length; k++)
                {
                    object ascendingVal = mshParameterList[k].GetEntry(
                        SortObjectParameterDefinitionKeys.AscendingEntryKey);
                    object descendingVal = mshParameterList[k].GetEntry(
                        SortObjectParameterDefinitionKeys.DescendingEntryKey);
                    bool isAscendingDefined  = isOrderEntryKeyDefined(ascendingVal);
                    bool isDescendingDefined = isOrderEntryKeyDefined(descendingVal);
                    if (!isAscendingDefined && !isDescendingDefined)
                    {
                        // if neither ascending nor descending is defined
                        ascendingOverrides[k] = null;
                    }
                    else if (isAscendingDefined && isDescendingDefined &&
                             (bool)ascendingVal == (bool)descendingVal)
                    {
                        // if both ascending and descending defined but their values conflict
                        // they are ignored.
                        ascendingOverrides[k] = null;
                    }
                    else if (isAscendingDefined)
                    {
                        ascendingOverrides[k] = (bool)ascendingVal;
                    }
                    else
                    {
                        ascendingOverrides[k] = !(bool)descendingVal;
                    }
                }
            }

            OrderByPropertyComparer comparer =
                OrderByPropertyComparer.CreateComparer(orderMatrix, ascending,
                                                       ascendingOverrides, cultureInfo, caseSensitive);

            return(comparer);
        }
예제 #5
0
 private void InitComparer()
 {
     if (this.comparer == null)
     {
         List <PSObject> inputObjects = new List <PSObject>(this.ReferenceObject);
         this.orderByProperty = new OrderByProperty(this, inputObjects, this.Property, true, base._cultureInfo, (bool)base.CaseSensitive);
         if (((this.orderByProperty.Comparer != null) && (this.orderByProperty.OrderMatrix != null)) && (this.orderByProperty.OrderMatrix.Count != 0))
         {
             this.comparer         = this.orderByProperty.Comparer;
             this.referenceEntries = this.orderByProperty.OrderMatrix;
         }
     }
 }
예제 #6
0
        /// <summary>
        /// Utility function called by Group-Object to create Groups.
        /// </summary>
        /// <param name="currentObjectEntry">Input object that needs to be grouped.</param>
        /// <param name="noElement">True if we are not accumulating objects.</param>
        /// <param name="groups">List containing Groups.</param>
        /// <param name="groupInfoDictionary">Dictionary used to keep track of the groups with hash of the property values being the key.</param>
        /// <param name="orderByPropertyComparer">The Comparer to be used while comparing to check if new group has to be created.</param>
        private static void DoOrderedGrouping(
            OrderByPropertyEntry currentObjectEntry,
            bool noElement,
            List <GroupInfo> groups,
            Dictionary <object, GroupInfo> groupInfoDictionary,
            OrderByPropertyComparer orderByPropertyComparer)
        {
            var currentObjectOrderValues = currentObjectEntry.orderValues;

            if (currentObjectOrderValues != null && currentObjectOrderValues.Count > 0)
            {
                object currentTupleObject = PSTuple.ArrayToTuple(currentObjectOrderValues);

                if (groupInfoDictionary.TryGetValue(currentTupleObject, out var currentGroupInfo))
                {
                    // add this inputObject to an existing group
                    currentGroupInfo.Add(currentObjectEntry.inputObject);
                }
                else
                {
                    bool isCurrentItemGrouped = false;

                    if (groups.Count > 0)
                    {
                        var lastGroup = groups[groups.Count - 1];

                        // Check if the current input object can be converted to one of the already known types
                        // by looking up in the type to GroupInfo mapping.
                        if (orderByPropertyComparer.Compare(lastGroup.GroupValue, currentObjectEntry) == 0)
                        {
                            lastGroup.Add(currentObjectEntry.inputObject);
                            isCurrentItemGrouped = true;
                        }
                    }

                    if (!isCurrentItemGrouped)
                    {
                        // create a new group
                        s_tracer.WriteLine("Create a new group: {0}", currentObjectOrderValues);
                        GroupInfo newObjGrp = noElement
                            ? new GroupInfoNoElement(currentObjectEntry)
                            : new GroupInfo(currentObjectEntry);

                        groups.Add(newObjGrp);

                        groupInfoDictionary.Add(currentTupleObject, newObjGrp);
                    }
                }
            }
        }
예제 #7
0
        /// <summary>
        /// Utility function called by Group-Object to create Groups.
        /// </summary>
        /// <param name="currentObjectEntry">Input object that needs to be grouped.</param>
        /// <param name="noElement">true if we are not accumulating objects</param>
        /// <param name="groups">List containing Groups.</param>
        /// <param name="groupInfoDictionary">Dictionary used to keep track of the groups with hash of the property values being the key.</param>
        /// <param name="orderByPropertyComparer">The Comparer to be used while comparing to check if new group has to be created.</param>
        internal static void DoGrouping(OrderByPropertyEntry currentObjectEntry, bool noElement, List <GroupInfo> groups, Dictionary <object, GroupInfo> groupInfoDictionary,
                                        OrderByPropertyComparer orderByPropertyComparer)
        {
            if (currentObjectEntry != null && currentObjectEntry.orderValues != null && currentObjectEntry.orderValues.Count > 0)
            {
                object currentTupleObject = PSTuple.ArrayToTuple(currentObjectEntry.orderValues.ToArray());

                GroupInfo currentGroupInfo = null;
                if (groupInfoDictionary.TryGetValue(currentTupleObject, out currentGroupInfo))
                {
                    if (currentGroupInfo != null)
                    {
                        //add this inputObject to an existing group
                        currentGroupInfo.Add(currentObjectEntry.inputObject);
                    }
                }
                else
                {
                    bool isCurrentItemGrouped = false;

                    for (int groupsIndex = 0; groupsIndex < groups.Count; groupsIndex++)
                    {
                        // Check if the current input object can be converted to one of the already known types
                        // by looking up in the type to GroupInfo mapping.
                        if (orderByPropertyComparer.Compare(groups[groupsIndex].GroupValue, currentObjectEntry) == 0)
                        {
                            groups[groupsIndex].Add(currentObjectEntry.inputObject);
                            isCurrentItemGrouped = true;
                            break;
                        }
                    }

                    if (!isCurrentItemGrouped)
                    {
                        // create a new group
                        s_tracer.WriteLine("Create a new group: {0}", currentObjectEntry.orderValues);
                        GroupInfo newObjGrp = noElement ? new GroupInfoNoElement(currentObjectEntry) : new GroupInfo(currentObjectEntry);
                        groups.Add(newObjGrp);

                        groupInfoDictionary.Add(currentTupleObject, newObjGrp);
                    }
                }
            }
        }
예제 #8
0
        /// <summary>
        /// Sort unsorted OrderByPropertyEntry data using a full sort.
        /// </summary>
        private int FullSort(List <OrderByPropertyEntry> dataToSort, OrderByPropertyComparer comparer)
        {
            // Track how many items in the list are sorted
            int sortedItemCount = dataToSort.Count;

            // Future: It may be worth comparing List.Sort with SortedSet when handling unique
            // records in case SortedSet is faster (SortedSet was not an option in earlier
            // versions of PowerShell).
            dataToSort.Sort(comparer);

            if (_unique)
            {
                // Move unique entries to the front of the list (this is significantly faster
                // than removing them)
                sortedItemCount = MoveUniqueEntriesToFront(dataToSort, comparer);
            }

            return(sortedItemCount);
        }
예제 #9
0
 private static OrderByPropertyComparer CreateComparer(List <OrderByPropertyEntry> orderMatrix, List <MshParameter> mshParameterList, bool ascending, CultureInfo cultureInfo, bool caseSensitive)
 {
     if ((orderMatrix == null) || (orderMatrix.Count == 0))
     {
         return(null);
     }
     bool?[] ascendingOverrides = null;
     if ((mshParameterList != null) && (mshParameterList.Count != 0))
     {
         ascendingOverrides = new bool?[mshParameterList.Count];
         for (int i = 0; i < ascendingOverrides.Length; i++)
         {
             object entry         = mshParameterList[i].GetEntry("ascending");
             object orderEntryKey = mshParameterList[i].GetEntry("descending");
             bool   flag          = isOrderEntryKeyDefined(entry);
             bool   flag2         = isOrderEntryKeyDefined(orderEntryKey);
             if (!flag && !flag2)
             {
                 ascendingOverrides[i] = null;
             }
             else if ((flag && flag2) && (((bool)entry) == ((bool)orderEntryKey)))
             {
                 ascendingOverrides[i] = null;
             }
             else if (flag)
             {
                 ascendingOverrides[i] = new bool?((bool)entry);
             }
             else
             {
                 ascendingOverrides[i] = new bool?(!((bool)orderEntryKey));
             }
         }
     }
     return(OrderByPropertyComparer.CreateComparer(orderMatrix, ascending, ascendingOverrides, cultureInfo, caseSensitive));
 }
예제 #10
0
        private void InitComparer()
        {
            if (_comparer != null)
            {
                return;
            }

            List <PSObject> referenceObjectList = new List <PSObject>(ReferenceObject);

            _orderByProperty = new OrderByProperty(
                this, referenceObjectList, Property, true, _cultureInfo, CaseSensitive);
            Diagnostics.Assert(_orderByProperty.Comparer != null, "no comparer");
            Diagnostics.Assert(
                _orderByProperty.OrderMatrix != null &&
                _orderByProperty.OrderMatrix.Count == ReferenceObject.Length,
                "no OrderMatrix");
            if (_orderByProperty.Comparer == null || _orderByProperty.OrderMatrix == null || _orderByProperty.OrderMatrix.Count == 0)
            {
                return;
            }

            _comparer         = _orderByProperty.Comparer;
            _referenceEntries = _orderByProperty.OrderMatrix;
        }
예제 #11
0
        /// <summary>
        /// Sort unsorted OrderByPropertyEntry data using an indexed min-/max-heap sort.
        /// </summary>
        private int Heapify(List <OrderByPropertyEntry> dataToSort, OrderByPropertyComparer orderByPropertyComparer)
        {
            // Instantiate the Heapify comparer, which takes index into account for sort stability
            var comparer = new IndexedOrderByPropertyComparer(orderByPropertyComparer);

            // Identify how many items will be in the heap and the current number of items
            int heapCount    = 0;
            int heapCapacity = Top > 0 ? Top : Bottom;

            // Identify the comparator (the value all comparisons will be made against based on whether we're
            // doing a Top N or Bottom N sort)
            // Note: All comparison results in the loop below are performed related to the value of the
            // comparator. OrderByPropertyComparer.Compare will return -1 to indicate that the lhs is smaller
            // if an ascending sort is being executed, or -1 to indicate that the lhs is larger if a descending
            // sort is being executed. The comparator will be -1 if we're executing a Top N sort, or 1 if we're
            // executing a Bottom N sort. These two pairs of states allow us to perform the proper comparison
            // regardless of whether we're executing an ascending or descending Top N or Bottom N sort. This
            // allows us to build a min-heap or max-heap for each of these sorts with the exact same logic.
            // Min-heap: used for faster processing of a top N descending sort and a bottom N ascending sort
            // Max-heap: used for faster processing of a top N ascending sort and a bottom N descending sort
            int comparator = Top > 0 ? -1 : 1;

            // For unique sorts, use a sorted set to avoid adding unique items to the heap
            SortedSet <OrderByPropertyEntry> uniqueSet = _unique ? new SortedSet <OrderByPropertyEntry>(orderByPropertyComparer) : null;

            // Tracking the index is necessary so that unsortable items can be output at the end, in the order
            // in which they were received.
            for (int dataIndex = 0, discardedDuplicates = 0; dataIndex < dataToSort.Count - discardedDuplicates; dataIndex++)
            {
                // Min-heap: if the heap is full and the root item is larger than the entry, discard the entry
                // Max-heap: if the heap is full and the root item is smaller than the entry, discard the entry
                if (heapCount == heapCapacity && comparer.Compare(dataToSort[0], dataToSort[dataIndex]) == comparator)
                {
                    continue;
                }

                // If we're doing a unique sort and the entry is not unique, discard the duplicate entry
                if (_unique && !uniqueSet.Add(dataToSort[dataIndex]))
                {
                    discardedDuplicates++;
                    if (dataIndex != dataToSort.Count - discardedDuplicates)
                    {
                        // When discarding duplicates, replace them with an item at the end of the list and
                        // adjust our counter so that we check the item we just swapped in next
                        dataToSort[dataIndex] = dataToSort[dataToSort.Count - discardedDuplicates];
                        dataIndex--;
                    }

                    continue;
                }

                // Add the current item to the heap and bubble it up into the correct position
                int childIndex = dataIndex;
                while (childIndex > 0)
                {
                    int parentIndex = ((childIndex > (heapCapacity - 1) ? heapCapacity : childIndex) - 1) >> 1;

                    // Min-heap: if the child item is larger than its parent, break
                    // Max-heap: if the child item is smaller than its parent, break
                    if (comparer.Compare(dataToSort[childIndex], dataToSort[parentIndex]) == comparator)
                    {
                        break;
                    }

                    var temp = dataToSort[parentIndex];
                    dataToSort[parentIndex] = dataToSort[childIndex];
                    dataToSort[childIndex]  = temp;

                    childIndex = parentIndex;
                }

                heapCount++;

                // If the heap size is too large, remove the root and rearrange the heap
                if (heapCount > heapCapacity)
                {
                    // Move the last item to the root and reset the heap count (this effectively removes the last item)
                    dataToSort[0] = dataToSort[dataIndex];
                    heapCount     = heapCapacity;

                    // Bubble the root item down into the correct position
                    int parentIndex     = 0;
                    int parentItemCount = heapCapacity >> 1;
                    while (parentIndex < parentItemCount)
                    {
                        // Min-heap: use the smaller of the two children in the comparison
                        // Max-heap: use the larger of the two children in the comparison
                        int leftChildIndex  = (parentIndex << 1) + 1;
                        int rightChildIndex = leftChildIndex + 1;
                        childIndex = rightChildIndex == heapCapacity || comparer.Compare(dataToSort[leftChildIndex], dataToSort[rightChildIndex]) != comparator
                            ? leftChildIndex
                            : rightChildIndex;

                        // Min-heap: if the smallest child is larger than or equal to its parent, break
                        // Max-heap: if the largest child is smaller than or equal to its parent, break
                        int childComparisonResult = comparer.Compare(dataToSort[childIndex], dataToSort[parentIndex]);
                        if (childComparisonResult == 0 || childComparisonResult == comparator)
                        {
                            break;
                        }

                        var temp = dataToSort[childIndex];
                        dataToSort[childIndex]  = dataToSort[parentIndex];
                        dataToSort[parentIndex] = temp;

                        parentIndex = childIndex;
                    }
                }
            }

            dataToSort.Sort(0, heapCount, comparer);

            return(heapCount);
        }
예제 #12
0
 internal OrderByProperty(PSCmdlet cmdlet, List <PSObject> inputObjects, object[] expr, bool ascending, CultureInfo cultureInfo, bool caseSensitive)
 {
     ProcessExpressionParameter(inputObjects, cmdlet, expr, out this._mshParameterList);
     this.orderMatrix = CreateOrderMatrix(cmdlet, inputObjects, this._mshParameterList);
     this.comparer    = CreateComparer(this.orderMatrix, this._mshParameterList, ascending, cultureInfo, caseSensitive);
 }
예제 #13
0
 internal IndexedOrderByPropertyComparer(OrderByPropertyComparer orderByPropertyComparer)
 {
     _orderByPropertyComparer = orderByPropertyComparer;
 }
예제 #14
0
        internal static List <GroupInfo> DoGrouping(List <OrderByPropertyEntry> orderMatrix, OrderByPropertyComparer comparer, bool noElement)
        {
            if (((orderMatrix == null) || (orderMatrix.Count == 0)) || (comparer == null))
            {
                return(null);
            }
            List <GroupInfo> groups = new List <GroupInfo>();

            foreach (OrderByPropertyEntry entry in orderMatrix)
            {
                int num = FindInObjectGroups(groups, entry, comparer);
                if (num == -1)
                {
                    tracer.WriteLine(string.Format(CultureInfo.InvariantCulture, "Create a new group: {0}", new object[] { entry.orderValues }), new object[0]);
                    GroupInfo item = noElement ? new GroupInfoNoElement(entry) : new GroupInfo(entry);
                    groups.Add(item);
                }
                else
                {
                    tracer.WriteLine(string.Format(CultureInfo.InvariantCulture, "Add to group {0}: {1}", new object[] { num, entry.orderValues }), new object[0]);
                    PSObject inputObject = entry.inputObject;
                    groups[num].Add(inputObject);
                }
            }
            return(groups);
        }
예제 #15
0
 private static int FindInObjectGroups(List <GroupInfo> groups, OrderByPropertyEntry target, OrderByPropertyComparer comparer)
 {
     for (int i = 0; i < groups.Count; i++)
     {
         if (comparer.Compare(groups[i].GroupValue, target) == 0)
         {
             return(i);
         }
     }
     return(-1);
 }