private static IDictionary<int, Input[]> GenEquivalenceTable(CodePointEquivalenceClasses equivalenceClasses)
 {
     var equivalenceTable = new Dictionary<int, Input[]>();
     foreach(var plane in UnicodePlanes)
     {
         var planeEquivalenceClasses = new Input[0x10000];
         equivalenceTable.Add(plane, planeEquivalenceClasses);
         var planeBits = plane << 16;
         for(var planePlace = 0; planePlace < 0x10000; planePlace++)
             planeEquivalenceClasses[planePlace] = equivalenceClasses.GetClass((CodePoint)(planeBits + planePlace));
     }
     return equivalenceTable;
 }
        private static bool AllEqual(Input[] planeEquivalenceClasses)
        {
            var value = planeEquivalenceClasses[0];
            for(var i = 1; i < planeEquivalenceClasses.Length; i++)
                if(value != planeEquivalenceClasses[i])
                    return false;

            return true;
        }
        private static bool CanPlaceBlockAt(Input[] planeEquivalenceClasses, int block, int place, IList<Input> equivalenceTable)
        {
            var blockStart = block << 8;
            // Since the block place could take us off the end of the equivalenceTable, we may only need to check a portion of the block
            var blockPortion = Math.Min(0xFF, equivalenceTable.Count - place - 1);
            var blockEnd = blockStart + blockPortion;
            for(var blockChar = blockStart; blockChar <= blockEnd; blockChar++, place++)
                if(equivalenceTable[place] != planeEquivalenceClasses[blockChar])
                    return false;

            return true;
        }