/// <summary>
        /// Create a new partition
        /// </summary>
        /// <param name="symCard">The symbol alphabet cardinality</param>
        internal Partition(int symCard, TaskState task)
        {
            this.myTask = task;
            CharRange.Init(symCard);
            PartitionElement.Reset();

            elements.Add(PartitionElement.AllChars());
        }
 internal MapRun(int min, int max, int val)
 {
     hash  = (max - min + 1) * val;
     range = new CharRange(min, max);
     if (min == max)
     {
         tag = TagType.singleton;
     }
     else if (max - min + 1 >= Partition.CutOff)
     {
         tag = TagType.longRun;
     }
     else
     {
         tag = TagType.shortRun;
     }
 }
        /// <summary>
        /// Canonicalize the set. This may mutate
        /// both this.ranges and the invert flag.
        /// </summary>
        internal void Canonicalize()
        {
            if (this.isCanonical)
            {
                return;
            }
            if (!invert && this.ranges.Count <= 1)
            {
                this.isCanonical = true;
                return; // Empty, singleton and upper/lower pair RangeLists are trivially canonical
            }
            // Process non-empty lists.
            int listIx = 0;

            this.ranges.Sort();
            List <CharRange> newList      = new List <CharRange>();
            CharRange        currentRange = ranges[listIx++];

            while (listIx < ranges.Count)
            {
                CharRange nextRange = ranges[listIx++];
                if (nextRange.minChr > currentRange.maxChr + 1) // Merge contiguous ranges
                {
                    newList.Add(currentRange);
                    currentRange = nextRange;
                }
                else if
                (nextRange.minChr <= (currentRange.maxChr + 1) &&
                 nextRange.maxChr >= currentRange.maxChr)
                {
                    currentRange = new CharRange(currentRange.minChr, nextRange.maxChr);
                }
                // Else skip ...
            }
            newList.Add(currentRange);
            this.ranges = newList;
            if (this.invert)
            {
                this.invert = false;
                this.ranges = this.InvertedList();
            }
            isCanonical = true;
        }
        /// <summary>
        /// Return a new RangeList that is the intersection of
        /// "this" and rhOp.  Neither operand is mutated.
        /// </summary>
        /// <param name="rhOp"></param>
        /// <returns></returns>
        internal RangeList AND(RangeList rhOp)
        {
            if (!isCanonical || !rhOp.isCanonical)
            {
                throw new GplexInternalException("RangeList non canonicalized");
            }
            if (this.ranges.Count == 0 || rhOp.ranges.Count == 0)
            {
                return(new RangeList(false)); // return empty RangeList
            }
            int thisIx;
            int rhOpIx = 0;
            int thisNm = this.ranges.Count;
            int rhOpNm = rhOp.ranges.Count;
            List <CharRange> newList  = new List <CharRange>();
            RangeList        result   = new RangeList(newList, false);
            CharRange        rhOpElem = rhOp.ranges[rhOpIx++];

            for (thisIx = 0; thisIx < thisNm; thisIx++)
            {
                CharRange thisElem = this.ranges[thisIx];
                // Attempt to find an overlapping element.
                // If necessary fetch new elements from rhOp
                // until maxChr of the new element is greater
                // than minChr of the current thisElem.
                while (rhOpElem.maxChr < thisElem.minChr)
                {
                    if (rhOpIx < rhOpNm)
                    {
                        rhOpElem = rhOp.ranges[rhOpIx++];
                    }
                    else
                    {
                        return(result);
                    }
                }
                // It is possible that the rhOpElem is entirely beyond thisElem
                // It is also possible that rhOpElem and several following
                // elements are all overlapping with thisElem.
                while (rhOpElem.minChr <= thisElem.maxChr)
                {
                    // process overlap
                    newList.Add(new CharRange(
                                    (thisElem.minChr < rhOpElem.minChr ? rhOpElem.minChr : thisElem.minChr),
                                    (thisElem.maxChr < rhOpElem.maxChr ? thisElem.maxChr : rhOpElem.maxChr)));
                    // If rhOpElem extends beyond thisElem.maxChr it is possible that
                    // it will overlap with the next thisElem, so do not advance rhOpIx.
                    if (rhOpElem.maxChr > thisElem.maxChr)
                    {
                        break;
                    }
                    else if (rhOpIx == rhOpNm)
                    {
                        return(result);
                    }
                    else
                    {
                        rhOpElem = rhOp.ranges[rhOpIx++];
                    }
                }
            }
            return(result);
        }
 internal void Add(CharRange rng)
 {
     ranges.Add(rng);  // AddToRange
     isCanonical = !invert && ranges.Count == 1;
 }