Esempio n. 1
0
        /* Function: SetTo
         * Sets the number set to another set's value.
         */
        public void SetTo(NumberSet toCopy)
        {
            if (toCopy.usedRanges == 0)
            {
                if (ranges != null && ShouldShrinkTo(ranges.Length, 0) == 0)
                {
                    ranges = null;
                }

                usedRanges = 0;
            }
            else
            {
                if (ranges == null ||
                    ranges.Length < toCopy.usedRanges ||
                    ShouldShrinkTo(ranges.Length, toCopy.usedRanges) != ranges.Length)
                {
                    ranges = new NumberRange[toCopy.usedRanges];
                }

                usedRanges = toCopy.usedRanges;

                Array.Copy(toCopy.ranges, ranges, usedRanges);
            }
        }
Esempio n. 2
0
        /* Function: InsertAtIndex
         * Creates a space in <ranges> for a new <NumberRange> at the specified index.  If necessary, will reallocate
         * the array.  The values in the new space are undefined.
         */
        protected void InsertAtIndex(int index)
        {
            int length    = (ranges == null ? 0 : ranges.Length);
            int newLength = ShouldGrowTo(length, usedRanges + 1);

            if (newLength > length)
            {
                NumberRange[] newArray = new NumberRange[newLength];

                if (index > 0)
                {
                    Array.Copy(ranges, 0, newArray, 0, index);
                }
                if (index < usedRanges)
                {
                    Array.Copy(ranges, index, newArray, index + 1, usedRanges - index);
                }

                ranges = newArray;
                usedRanges++;
            }

            else              // we don't have to reallocate the array
            {
                // This is safe to use with overlapping regions of the same array.
                if (index < usedRanges)
                {
                    Array.Copy(ranges, index, ranges, index + 1, usedRanges - index);
                }

                usedRanges++;
            }
        }
Esempio n. 3
0
        /* Constructor: NumberSet
         * Creates a number set by duplicating the passed one.
         */
        public NumberSet(NumberSet toCopy)
        {
            ranges     = new NumberRange[toCopy.usedRanges];
            usedRanges = toCopy.usedRanges;

            Array.Copy(toCopy.ranges, ranges, usedRanges);
        }
Esempio n. 4
0
        /* Function: RemoveAtIndex
         * Removes a <NumberRange> from <ranges> at the specified index and moves everything else down.
         */
        protected void RemoveAtIndex(int index)
        {
            int shouldShrinkTo = ShouldShrinkTo(ranges.Length, usedRanges - 1);

            if (shouldShrinkTo == 0)
            {
                ranges = null;
            }

            else if (shouldShrinkTo < ranges.Length)
            {
                NumberRange[] newArray = new NumberRange[shouldShrinkTo];

                if (index > 0)
                {
                    Array.Copy(ranges, newArray, index);
                }
                if (index + 1 < usedRanges)
                {
                    Array.Copy(ranges, index + 1, newArray, index, usedRanges - index - 1);
                }

                ranges = newArray;
            }

            // Otherwise just move everything down.  This is safe to use with overlapping regions of the same array.
            else if (index != usedRanges - 1)
            {
                Array.Copy(ranges, index + 1, ranges, index, usedRanges - index - 1);
            }

            usedRanges--;
        }
Esempio n. 5
0
        /* Function: Clear
         * Removes all entries from the set, making it empty.
         */
        public void Clear()
        {
            usedRanges = 0;

            int shouldShrinkTo = ShouldShrinkTo(ranges.Length, 0);

            if (shouldShrinkTo < ranges.Length)
            {
                ranges = new NumberRange[shouldShrinkTo];
            }
        }
Esempio n. 6
0
        /* Function: ReadFrom
         * Reads a number set from the current position in a <BinaryFile>.
         */
        public void ReadFrom(BinaryFile binaryFile)
        {
            // [int32: ranges]

            int newRangeCount = binaryFile.ReadInt32();

            if (newRangeCount < 0)
            {
                throw new FormatException();
            }


            // Reallocate if needed

            if (newRangeCount == 0)
            {
                if (ranges != null && ShouldShrinkTo(ranges.Length, 0) == 0)
                {
                    ranges = null;
                }

                usedRanges = 0;
            }
            else
            {
                int arraySize    = (ranges == null ? 0 : ranges.Length);
                int newArraySize = (newRangeCount >= arraySize ? ShouldGrowTo(arraySize, newRangeCount)
                                                                                                                                                                                        : ShouldShrinkTo(arraySize, newRangeCount));

                if (arraySize != newArraySize)
                {
                    ranges = new NumberRange[newArraySize];
                }


                // [int32: low] [int32: high]
                // [int32: low] [int32: high]
                // ...

                for (int i = 0; i < newRangeCount; i++)
                {
                    ranges[i].Low  = binaryFile.ReadInt32();
                    ranges[i].High = binaryFile.ReadInt32();
                }

                usedRanges = newRangeCount;
            }

            if (!Validate())
            {
                throw new FormatException();
            }
        }
Esempio n. 7
0
        /* Function: GetEnumerator
         * Returns an enumerator that returns each value.  This allows the number set to be used with foreach.
         */
        IEnumerator <int> IEnumerable <int> .GetEnumerator()
        {
            for (int rangeIndex = 0; rangeIndex < usedRanges; rangeIndex++)
            {
                NumberRange range = ranges[rangeIndex];

                for (int number = range.Low; number <= range.High; number++)
                {
                    yield return(number);
                }
            }
        }
Esempio n. 8
0
        /* Constructor: NumberSet
         * Creates an empty number set with the passed number of ranges preallocated.
         */
        protected NumberSet(int numberOfRanges)
        {
            if (numberOfRanges == 0)
            {
                ranges = null;
            }
            else
            {
                ranges = new NumberRange[numberOfRanges];
            }

            usedRanges = 0;
        }
Esempio n. 9
0
        /* Function: InsertAtIndex
         * Creates a space in <ranges> for a new <NumberRange> at the specified index.  If necessary, will reallocate
         * the array.  The values in the new space are undefined.
         */
        protected void InsertAtIndex(int index)
        {
            if (usedRanges == ranges.Length)
            {
                int newLength;

                if (usedRanges == 1)
                {
                    newLength = 4;
                }
                else
                {
                    newLength = usedRanges * 2;
                }

                NumberRange[] newArray = new NumberRange[newLength];

                if (index > 0)
                {
                    Array.Copy(ranges, 0, newArray, 0, index);
                }
                if (index < usedRanges)
                {
                    Array.Copy(ranges, index, newArray, index + 1, usedRanges - index);
                }

                ranges = newArray;
                usedRanges++;
            }

            else              // we don't have to reallocate the array
            {
                // This is safe to use with overlapping regions of the same array.
                if (index < usedRanges)
                {
                    Array.Copy(ranges, index, ranges, index + 1, usedRanges - index);
                }

                usedRanges++;
            }
        }
Esempio n. 10
0
        /* Function: SetTo
         * Sets the NumberSet to the values encoded in a string.  It is safe to pass a null or empty string.  Throws an exception if
         * it's not in the correct format.  The format isn't documented because it should only be used with strings generated by
         * <ToString()>.
         */
        public void SetTo(string input)
        {
            if (string.IsNullOrEmpty(input) || input == EmptySetString)
            {
                if (ranges != null && ShouldShrinkTo(ranges.Length, 0) == 0)
                {
                    ranges = null;
                }

                usedRanges = 0;
                return;
            }

            if (input[0] != '{')
            {
                throw new Exceptions.StringNotInValidFormat(input, this);
            }


            // First parse the string to perform basic validation and determine the array size.

            int  newRangeCount = 1;
            int  number;
            int  inputIndex     = 1;
            bool onSecondNumber = false;

            for (;;)
            {
                if (inputIndex >= input.Length || input[inputIndex] < '0' || input[inputIndex] > '9')
                {
                    throw new Exceptions.StringNotInValidFormat(input, this);
                }

                number = (int)(input[inputIndex] - '0');
                inputIndex++;

                while (inputIndex < input.Length && input[inputIndex] >= '0' && input[inputIndex] <= '9')
                {
                    number *= 10;
                    number += (int)(input[inputIndex] - '0');
                    inputIndex++;
                }

                if (inputIndex >= input.Length)
                {
                    throw new Exceptions.StringNotInValidFormat(input, this);
                }

                if (input[inputIndex] == '}')
                {
                    break;
                }
                else if (input[inputIndex] == ',')
                {
                    newRangeCount++;
                    onSecondNumber = false;
                    inputIndex++;
                }
                else if (input[inputIndex] == '-')
                {
                    if (onSecondNumber == false)
                    {
                        onSecondNumber = true;
                        inputIndex++;
                    }
                    else
                    {
                        throw new Exceptions.StringNotInValidFormat(input, this);
                    }
                }
                else
                {
                    throw new Exceptions.StringNotInValidFormat(input, this);
                }
            }


            // If we're here the string is valid enough to parse, though it still may contain errors like "3-5,6-9" which should be "3-9".

            // Reallocate the range array if necessary.

            int arraySize    = (ranges == null ? 0 : ranges.Length);
            int newArraySize = (newRangeCount >= arraySize ? ShouldGrowTo(arraySize, newRangeCount)
                                                                                                                                                                                : ShouldShrinkTo(arraySize, newRangeCount));

            if (newArraySize != arraySize)
            {
                ranges = new NumberRange[newArraySize];
            }

            usedRanges = newRangeCount;


            // Copy in the new data as is.

            inputIndex = 1;
            int rangeIndex = 0;

            onSecondNumber = false;

            for (;;)
            {
                number = (int)(input[inputIndex] - '0');
                inputIndex++;

                while (input[inputIndex] >= '0' && input[inputIndex] <= '9')
                {
                    number *= 10;
                    number += (int)(input[inputIndex] - '0');
                    inputIndex++;
                }

                if (onSecondNumber)
                {
                    ranges[rangeIndex].High = number;
                }
                else
                {
                    ranges[rangeIndex].Low = number;
                }

                if (input[inputIndex] == '}')
                {
                    if (onSecondNumber == false)
                    {
                        ranges[rangeIndex].High = number;
                    }

                    break;
                }
                else if (input[inputIndex] == ',')
                {
                    if (onSecondNumber == false)
                    {
                        ranges[rangeIndex].High = number;
                    }

                    rangeIndex++;
                    onSecondNumber = false;
                    inputIndex++;
                }
                else                 // (input[inputIndex] == '-')
                {
                    inputIndex++;
                    onSecondNumber = true;
                }
            }

            // Catch any remaining errors like "3-5,6-9".
            if (!Validate())
            {
                usedRanges = 0;
                throw new Exceptions.StringNotInValidFormat(input, this);
            }
        }
Esempio n. 11
0
        /* Function: Remove
         * Removes the contents of an entire set from this one.
         */
        public void Remove(NumberSet setToRemove)
        {
            int position            = 0;
            int setToRemovePosition = 0;

            while (position < usedRanges && setToRemovePosition < setToRemove.usedRanges)
            {
                // Remember that these are structs, so to update the list you have to update the original struct, not this one.
                NumberRange range         = ranges[position];
                NumberRange rangeToRemove = setToRemove.ranges[setToRemovePosition];

                // If the lower bounds is less than the removal lower bounds...
                if (range.Low < rangeToRemove.Low)
                {
                    // If the upper bounds is also less than the removal lower bounds, advance the position.
                    if (range.High < rangeToRemove.Low)
                    {
                        position++;
                    }

                    // The upper bounds is somewhere in or past the removal range.  If it is less than or equal to the removal
                    // upper bounds, we can just truncate this range.
                    else if (range.High <= rangeToRemove.High)
                    {
                        ranges[position].High = rangeToRemove.Low - 1;
                        position++;
                    }

                    // The upper bounds is past the removal range.  Split it.
                    else
                    {
                        InsertAtIndex(position + 1);
                        ranges[position + 1].High = range.High;
                        ranges[position + 1].Low  = rangeToRemove.High + 1;
                        ranges[position].High     = rangeToRemove.Low - 1;

                        position++;
                        setToRemovePosition++;
                    }
                }

                // If the lower bounds is equal to the removal lower bounds...
                else if (range.Low == rangeToRemove.Low)
                {
                    // If the upper bounds is less than or equal to the removal upper bounds, remove the range entirely.
                    if (range.High <= rangeToRemove.High)
                    {
                        RemoveAtIndex(position);
                    }

                    // The upper bounds is greater than the removal upper bounds, truncate the range.
                    else
                    {
                        ranges[position].Low = rangeToRemove.High + 1;
                        setToRemovePosition++;
                    }
                }

                // If the lower bounds is greater than the removal lower bounds...
                else
                {
                    // If the lower bounds is also greater than the removal upper bounds, advance the removal.
                    if (range.Low > rangeToRemove.High)
                    {
                        setToRemovePosition++;
                    }

                    // The removal upper bounds is in or past the range.  If it's greater than or equal to the upper bounds,
                    // remove the range.
                    else if (range.High <= rangeToRemove.High)
                    {
                        RemoveAtIndex(position);
                    }

                    // Since it's less than the upper bounds, truncate the range.
                    else
                    {
                        ranges[position].Low = rangeToRemove.High + 1;
                        setToRemovePosition++;
                    }
                }
            }
        }
Esempio n. 12
0
        /* Function: Add
         * Adds the contents of an entire set from this one.
         */
        public void Add(NumberSet setToAdd)
        {
            if (IsEmpty)
            {
                SetTo(setToAdd);
                return;
            }

            int position         = 0;
            int setToAddPosition = 0;

            while (position < usedRanges && setToAddPosition < setToAdd.usedRanges)
            {
                // Remember that these are structs, so to update the list you have to update the original struct, not this one.
                NumberRange range      = ranges[position];
                NumberRange rangeToAdd = setToAdd.ranges[setToAddPosition];

                // If the range starts below or on the range to add...
                if (range.Low <= rangeToAdd.Low)
                {
                    // If the entire range is below the range to add, we can just advance.
                    if (range.High < rangeToAdd.Low - 1)
                    {
                        position++;
                    }

                    // If the entire range to add is within the existing range, we can just advance that.
                    else if (range.High >= rangeToAdd.High)
                    {
                        setToAddPosition++;
                    }

                    // The range to add extends past the existing one.  If it covers the gap between it and the next existing one,
                    // merge them.
                    else if (position + 1 < usedRanges && ranges[position + 1].Low <= rangeToAdd.High + 1)
                    {
                        ranges[position].High = ranges[position + 1].High;
                        RemoveAtIndex(position + 1);
                        // Go through the loop again without advancing since the range to add may merge multiple ranges into
                        // this one.
                    }

                    // There are no more existing ranges or it doesn't cause them to connect.  Extend the existing one.
                    else
                    {
                        ranges[position].High = rangeToAdd.High;
                        setToAddPosition++;

                        // We can advance this too.  The range we just added won't intersect with the next range to add, if there is one.
                        // The range we just altered won't either because it now has the same high value.
                        position++;
                    }
                }

                // If the range starts above the range to add...
                else                 // range.Low > rangeToAdd.Low
                {
                    // If the range to add extends into the existing range, extend it.
                    if (rangeToAdd.High >= range.Low - 1)
                    {
                        ranges[position].Low = rangeToAdd.Low;
                        // Go through the loop again without advancing.
                    }

                    // The range to add is below the existing range, insert it.
                    else
                    {
                        InsertAtIndex(position);
                        ranges[position].Low  = rangeToAdd.Low;
                        ranges[position].High = rangeToAdd.High;

                        position++;
                        setToAddPosition++;
                    }
                }
            }

            // If there's still more ranges left to add, add them to the end.
            if (setToAddPosition < setToAdd.usedRanges)
            {
                int rangesLeftToAdd = setToAdd.usedRanges - setToAddPosition;

                int newLength = ShouldGrowTo(ranges.Length, usedRanges + rangesLeftToAdd);

                if (newLength > ranges.Length)
                {
                    NumberRange[] newArray = new NumberRange[newLength];
                    Array.Copy(ranges, 0, newArray, 0, ranges.Length);

                    ranges = newArray;
                }

                Array.Copy(setToAdd.ranges, setToAddPosition, ranges, usedRanges, rangesLeftToAdd);
                usedRanges += rangesLeftToAdd;
            }
        }
Esempio n. 13
0
        /* Constructor: NumberSet
         * Creates a number set from the passed string.  It is safe to use with null or the empty string.
         */
        public NumberSet(string input)
        {
            if (string.IsNullOrEmpty(input) || input == EmptySetString)
            {
                ranges     = new NumberRange[1];
                usedRanges = 0;
                return;
            }

            if (input[0] != '{')
            {
                throw new Exceptions.StringNotInValidFormat(input, this);
            }


            // First parse the string to perform basic validation and determine the array size.

            int  arraySize = 1;
            int  number;
            int  inputIndex   = 1;
            bool secondNumber = false;

            for (;;)
            {
                if (inputIndex >= input.Length || input[inputIndex] < '0' || input[inputIndex] > '9')
                {
                    throw new Exceptions.StringNotInValidFormat(input, this);
                }

                number = (int)(input[inputIndex] - '0');
                inputIndex++;

                while (inputIndex < input.Length && input[inputIndex] >= '0' && input[inputIndex] <= '9')
                {
                    number *= 10;
                    number += (int)(input[inputIndex] - '0');
                    inputIndex++;
                }

                if (inputIndex >= input.Length)
                {
                    throw new Exceptions.StringNotInValidFormat(input, this);
                }

                if (input[inputIndex] == '}')
                {
                    break;
                }
                else if (input[inputIndex] == ',')
                {
                    arraySize++;
                    secondNumber = false;
                    inputIndex++;
                }
                else if (input[inputIndex] == '-')
                {
                    if (secondNumber == false)
                    {
                        secondNumber = true;
                        inputIndex++;
                    }
                    else
                    {
                        throw new Exceptions.StringNotInValidFormat(input, this);
                    }
                }
                else
                {
                    throw new Exceptions.StringNotInValidFormat(input, this);
                }
            }


            // If we're here the string is valid enough to parse, though it still may contain errors like "3-5,6-9" which should be "3-9".

            ranges     = new NumberRange[arraySize];
            usedRanges = arraySize;

            inputIndex = 1;
            int rangeIndex = 0;

            secondNumber = false;

            for (;;)
            {
                number = (int)(input[inputIndex] - '0');
                inputIndex++;

                while (input[inputIndex] >= '0' && input[inputIndex] <= '9')
                {
                    number *= 10;
                    number += (int)(input[inputIndex] - '0');
                    inputIndex++;
                }

                if (secondNumber)
                {
                    ranges[rangeIndex].High = number;
                }
                else
                {
                    ranges[rangeIndex].Low = number;
                }

                if (input[inputIndex] == '}')
                {
                    if (secondNumber == false)
                    {
                        ranges[rangeIndex].High = number;
                    }

                    break;
                }
                else if (input[inputIndex] == ',')
                {
                    if (secondNumber == false)
                    {
                        ranges[rangeIndex].High = number;
                    }

                    rangeIndex++;
                    secondNumber = false;
                    inputIndex++;
                }
                else                 // (input[inputIndex] == '-')
                {
                    inputIndex++;
                    secondNumber = true;
                }
            }

            // Catch any remaining errors like "3-5,6-9".
            if (!Validate())
            {
                usedRanges = 0;
                throw new Exceptions.StringNotInValidFormat(input, this);
            }
        }
Esempio n. 14
0
        // Group: Functions
        // __________________________________________________________________________


        /* Constructor: NumberSet
         * Creates an empty number set.
         */
        public NumberSet()
        {
            ranges     = new NumberRange[1];
            usedRanges = 0;
        }
Esempio n. 15
0
 /* Constructor: NumberSet
  * Reads a number set with the passed number of ranges preallocated.
  */
 protected NumberSet(int numberOfRanges)
 {
     ranges     = new NumberRange[numberOfRanges];
     usedRanges = 0;
 }