public InversionListCodePointSet(CodePoint codePoint)
 {
     if(codePoint == CodePoint.MaxValue)
         ranges = new[] { codePoint };
     else
         ranges = new[] { codePoint, (CodePoint)(codePoint + 1) };
 }
        public InversionListCodePointSet(CodePoint from, CodePoint to)
        {
            if(from > to)
                throw new ArgumentException("from can't be greater than to");

            if(to == CodePoint.MaxValue)
                ranges = new[] { from };
            else
                ranges = new[] { from, (CodePoint)(to + 1) };
        }
 public bool Contains(CodePoint codePoint)
 {
     // binary search for it
     var low = 0;
     var high = ranges.Length;
     while(low < high)
     {
         var mid = (low + high) / 2;
         if(codePoint >= ranges[mid])
             low = mid + 1;
         else if(codePoint < ranges[mid])
             high = mid;
     }
     var pos = high - 1;
     return (pos & 1) == 0;
 }
 public InversionListCodePointSet Complement()
 {
     if(ranges.Length == 0 || ranges[0] != CodePoint.MinValue)
     {
         var newRanges = new CodePoint[ranges.Length + 1];
         newRanges[0] = CodePoint.MinValue;
         ranges.CopyTo(newRanges, 1);
         return new InversionListCodePointSet(newRanges);
     }
     else
     {
         var length = ranges.Length - 1;
         var newRanges = new CodePoint[length];
         Array.Copy(ranges, 1, newRanges, 0, length);
         return new InversionListCodePointSet(newRanges);
     }
 }
 private InversionListCodePointSet(CodePoint[] ranges)
 {
     this.ranges = ranges;
 }
        public InversionListCodePointSet Union(InversionListCodePointSet value)
        {
            var a = ranges;
            var b = value.ranges;
            var tempResult = new CodePoint[a.Length + b.Length];
            var posA = 0;
            var posB = 0;
            var posResult = 0;
            var count = 0;
            // go through the two sets as though you're merging them
            while(posA < a.Length && posB < b.Length)
            {
                CodePoint c;
                int pos;

                // if the lower entry is in the first array, or if the
                // entries are equal and this one's the start of a range,
                // consider the entry from the first array next
                if(a[posA] < b[posB] || (a[posA] == b[posB] && (posA & 1) == 0))
                {
                    pos = posA;
                    c = a[posA++];
                }
                // otherwise, consider the entry from the second array next
                else
                {
                    pos = posB;
                    c = b[posB++];
                }
                // if the entry is the start of a range (i.e., an even-numbered
                // entry), increment the running count. If the count was zero
                // before incrementing, also write the entry to the result
                // set becuase we are starting an included range.
                if((pos & 1) == 0)
                {
                    if(count == 0)
                        tempResult[posResult++] = c;
                    ++count;
                }
                // if the entry is the end of a range (i.e., an odd-numbered
                // entry), decrement the running count. If this makes the
                // count zero, also write the entry to the result set becuase we
                // are ending the range
                else
                {
                    --count;
                    if(count == 0)
                        tempResult[posResult++] = c;
                }
            }

            // figure out how big the result should really be
            var length = posResult;
            // if we stopped in the middle of a range, decrement the count
            // before figuring out whether there are extra entries to write
            if((posA != a.Length && (posA & 1) == 1)
            || (posB != b.Length && (posB & 1) == 1))
                --count;
            // if, after the adjustment, the count is 0, then all
            // entries from the set we haven't exhausted also go into
            // the result
            if(count == 0)
                length += (a.Length - posA) + (b.Length - posB);
            // copy the results into the actual result array (they may

            // include the excess from the array we hadn't finished
            // examining)
            var result = new CodePoint[length];
            Array.Copy(tempResult, 0, result, 0, posResult);
            if(count == 0)
            {
                // only one of these two calls will do anything
                Array.Copy(a, posA, result, posResult, a.Length - posA);
                Array.Copy(b, posB, result, posResult, b.Length - posB);
            }
            return new InversionListCodePointSet(result);
        }