Tables: Fix scrolling with more than 32 columns (3058). Fix limit of 63 columms instead of 64. Added BitArray.
diff --git a/imgui_internal.h b/imgui_internal.h
index 21882be..3c6009d 100644
--- a/imgui_internal.h
+++ b/imgui_internal.h
@@ -476,6 +476,20 @@
     }
 }
 
+// Helper: ImBitArray class (wrapper over ImBitArray functions)
+// Store 1-bit per value. NOT CLEARED by constructor.
+template<int BITCOUNT>
+struct IMGUI_API ImBitArray
+{
+    ImU32           Storage[(BITCOUNT + 31) >> 5];
+    ImBitArray()                                { }
+    void            ClearBits()                 { memset(Storage, 0, sizeof(Storage)); }
+    bool            TestBit(int n) const        { IM_ASSERT(n < BITCOUNT); return ImBitArrayTestBit(Storage, n); }
+    void            SetBit(int n)               { IM_ASSERT(n < BITCOUNT); ImBitArraySetBit(Storage, n); }
+    void            ClearBit(int n)             { IM_ASSERT(n < BITCOUNT); ImBitArrayClearBit(Storage, n); }
+    void            SetBitRange(int n1, int n2) { ImBitArraySetBitRange(Storage, n1, n2); }
+};
+
 // Helper: ImBitVector
 // Store 1-bit per value.
 struct IMGUI_API ImBitVector
@@ -1820,8 +1834,9 @@
 
 #ifdef IMGUI_HAS_TABLE
 
-#define IM_COL32_DISABLE            IM_COL32(0,0,0,1)   // Special sentinel code
-#define IMGUI_TABLE_MAX_COLUMNS     64                  // sizeof(ImU64) * 8. This is solely because we frequently encode columns set in a ImU64.
+#define IM_COL32_DISABLE                IM_COL32(0,0,0,1)   // Special sentinel code
+#define IMGUI_TABLE_MAX_COLUMNS         64                  // sizeof(ImU64) * 8. This is solely because we frequently encode columns set in a ImU64.
+#define IMGUI_TABLE_MAX_DRAW_CHANNELS   (2 + 64 * 2)        // See TableUpdateDrawChannels()
 
 // [Internal] sizeof() ~ 100
 struct ImGuiTableColumn
diff --git a/imgui_tables.cpp b/imgui_tables.cpp
index b8c0fca..ed55fb3 100644
--- a/imgui_tables.cpp
+++ b/imgui_tables.cpp
@@ -163,7 +163,7 @@
         return false;
 
     // Sanity checks
-    IM_ASSERT(columns_count > 0 && columns_count < IMGUI_TABLE_MAX_COLUMNS && "Only 0..63 columns allowed!");
+    IM_ASSERT(columns_count > 0 && columns_count <= IMGUI_TABLE_MAX_COLUMNS && "Only 1..64 columns allowed!");
     if (flags & ImGuiTableFlags_ScrollX)
         IM_ASSERT(inner_width >= 0.0f);
 
@@ -1252,8 +1252,8 @@
     struct MergeGroup
     {
         ImRect  ClipRect;
-        ImU64   ChannelsMask;
         int     ChannelsCount;
+        ImBitArray<IMGUI_TABLE_MAX_DRAW_CHANNELS> ChannelsMask;
     };
     int merge_group_mask = 0x00;
     MergeGroup merge_groups[4];
@@ -1292,11 +1292,11 @@
                 continue;
 
             const int merge_group_dst_n = (is_frozen_h && column_n < table->FreezeColumnsCount ? 0 : 2) + (is_frozen_v ? merge_group_sub_n : 1);
-            IM_ASSERT(channel_no < 64);
+            IM_ASSERT(channel_no < IMGUI_TABLE_MAX_DRAW_CHANNELS);
             MergeGroup* merge_group = &merge_groups[merge_group_dst_n];
             if (merge_group->ChannelsCount == 0)
                 merge_group->ClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX);
-            merge_group->ChannelsMask |= (ImU64)1 << channel_no;
+            merge_group->ChannelsMask.SetBit(channel_no);
             merge_group->ChannelsCount++;
             merge_group->ClipRect.Add(src_channel->_CmdBuffer[0].ClipRect);
             merge_group_mask |= (1 << merge_group_dst_n);
@@ -1325,12 +1325,15 @@
         // Use shared temporary storage so the allocation gets amortized
         g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - 1);
         ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data;
-        ImU64 remaining_mask = (splitter->_Count < 64) ? ((ImU64)1 << splitter->_Count) - 1 : ~(ImU64)0;
-        remaining_mask &= (ImU64)~1; // Background channel 0 not part of the merge (see channel allocation in TableUpdateDrawChannels)
+        ImBitArray<IMGUI_TABLE_MAX_DRAW_CHANNELS> remaining_mask;
+        remaining_mask.ClearBits();
+        remaining_mask.SetBitRange(1, splitter->_Count - 1); // Background channel 0 not part of the merge (see channel allocation in TableUpdateDrawChannels)
+        int remaining_count = splitter->_Count - 1;
         const bool may_extend_clip_rect_to_host_rect = ImIsPowerOfTwo(merge_group_mask);
         for (int merge_group_n = 0; merge_group_n < 4; merge_group_n++)
-            if (ImU64 merge_channels_mask = merge_groups[merge_group_n].ChannelsMask)
+            if (int merge_channels_count = merge_groups[merge_group_n].ChannelsCount)
             {
+                MergeGroup* merge_group = &merge_groups[merge_group_n];
                 ImRect merge_clip_rect = merge_groups[merge_group_n].ClipRect;
                 if (may_extend_clip_rect_to_host_rect)
                 {
@@ -1340,30 +1343,32 @@
                     merge_clip_rect.Add(merge_groups_all_fit_within_inner_rect ? table->HostClipRect : table->InnerClipRect);
                     //GetOverlayDrawList()->AddRect(merge_clip_rect.Min, merge_clip_rect.Max, IM_COL32(0, 255, 0, 200));
                 }
-                remaining_mask &= ~merge_channels_mask;
-                for (int n = 0; n < splitter->_Count && merge_channels_mask != 0; n++)
+                remaining_count -= merge_group->ChannelsCount;
+                for (int n = 0; n < IM_ARRAYSIZE(remaining_mask.Storage); n++)
+                    remaining_mask.Storage[n] &= ~merge_group->ChannelsMask.Storage[n];
+                for (int n = 0; n < splitter->_Count && merge_channels_count != 0; n++)
                 {
                     // Copy + overwrite new clip rect
-                    const ImU64 n_mask = (ImU64)1 << n;
-                    if ((merge_channels_mask & n_mask) == 0)
+                    if (!merge_group->ChannelsMask.TestBit(n))
                         continue;
+                    merge_group->ChannelsMask.ClearBit(n);
+                    merge_channels_count--;
+
                     ImDrawChannel* channel = &splitter->_Channels[n];
                     IM_ASSERT(channel->_CmdBuffer.Size == 1 && merge_clip_rect.Contains(ImRect(channel->_CmdBuffer[0].ClipRect)));
                     channel->_CmdBuffer[0].ClipRect = merge_clip_rect.ToVec4();
                     memcpy(dst_tmp++, channel, sizeof(ImDrawChannel));
-                    merge_channels_mask &= ~n_mask;
                 }
             }
 
         // Append unmergeable channels that we didn't reorder at the end of the list
-        for (int n = 0; n < splitter->_Count && remaining_mask != 0; n++)
+        for (int n = 0; n < splitter->_Count && remaining_count != 0; n++)
         {
-            const ImU64 n_mask = (ImU64)1 << n;
-            if ((remaining_mask & n_mask) == 0)
+            if (!remaining_mask.TestBit(n))
                 continue;
             ImDrawChannel* channel = &splitter->_Channels[n];
             memcpy(dst_tmp++, channel, sizeof(ImDrawChannel));
-            remaining_mask &= ~n_mask;
+            remaining_count--;
         }
         IM_ASSERT(dst_tmp == g.DrawChannelsTempMergeBuffer.Data + g.DrawChannelsTempMergeBuffer.Size);
         memcpy(splitter->_Channels.Data + 1, g.DrawChannelsTempMergeBuffer.Data, (splitter->_Count - 1) * sizeof(ImDrawChannel));