From 70b11caab0426763e1b8919c8b65b89e1cd39c9d Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 13:43:49 +0300 Subject: [PATCH 1/5] Initial commit with task details for issue #21 Adding CLAUDE.md with task information for AI processing. This file will be removed when the task is complete. Issue: https://github.com/linksplatform/Collections/issues/21 --- CLAUDE.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..b744abec --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +Issue to solve: https://github.com/linksplatform/Collections/issues/21 +Your prepared branch: issue-21-657d3fe1 +Your prepared working directory: /tmp/gh-issue-solver-1757846616189 + +Proceed. \ No newline at end of file From aab1c7aac087db079bfd6203413f2071ecf10056 Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 13:55:01 +0300 Subject: [PATCH 2/5] Fix BitString Length property implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove NotImplementedException for length decrease operations - Implement proper shrinking logic with correct bit masking - Fix array clearing and word boundary handling logic - Add comprehensive tests for all Length property scenarios - Ensure min/max positive word boundaries are updated correctly - Handle edge cases like setting length to 0 and partial word masking This resolves all issues identified in the original Length property setter including the confusing logic around lines 75-83 in the original code. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../BitStringTests.cs | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/csharp/Platform.Collections.Tests/BitStringTests.cs b/csharp/Platform.Collections.Tests/BitStringTests.cs index 988deca8..8cecf634 100644 --- a/csharp/Platform.Collections.Tests/BitStringTests.cs +++ b/csharp/Platform.Collections.Tests/BitStringTests.cs @@ -142,6 +142,124 @@ public static void BitParallelVectorXorTest() w.Xor(v); }); } + + [Fact] + public static void LengthIncreaseTest() + { + var bitString = new BitString(32); + bitString[5] = true; + bitString[15] = true; + bitString[31] = true; + + Assert.Equal(32, bitString.Length); + + // Increase length + bitString.Length = 64; + Assert.Equal(64, bitString.Length); + + // Original bits should be preserved + Assert.True(bitString[5]); + Assert.True(bitString[15]); + Assert.True(bitString[31]); + + // New bits should be false + for (int i = 32; i < 64; i++) + { + Assert.False(bitString[i]); + } + } + + [Fact] + public static void LengthDecreaseTest() + { + var bitString = new BitString(64); + bitString[5] = true; + bitString[15] = true; + bitString[25] = true; + bitString[45] = true; + bitString[55] = true; + + // Decrease length + bitString.Length = 32; + Assert.Equal(32, bitString.Length); + + // Bits within new length should be preserved + Assert.True(bitString[5]); + Assert.True(bitString[15]); + Assert.True(bitString[25]); + } + + [Fact] + public static void LengthSetToZeroTest() + { + var bitString = new BitString(32); + bitString[5] = true; + bitString[15] = true; + + bitString.Length = 0; + Assert.Equal(0, bitString.Length); + } + + [Fact] + public static void LengthCrossWordBoundaryTest() + { + var bitString = new BitString(63); // Just under 64 (1 word) + bitString[62] = true; + + // Increase to cross word boundary + bitString.Length = 128; // 2 words + Assert.Equal(128, bitString.Length); + Assert.True(bitString[62]); + + // Set bit in second word + bitString[100] = true; + Assert.True(bitString[100]); + + // Decrease back + bitString.Length = 63; + Assert.Equal(63, bitString.Length); + Assert.True(bitString[62]); + } + + [Fact] + public static void LengthPartialWordMaskingTest() + { + var bitString = new BitString(70); // 1 full word + 6 bits in second word + + // Set bits in both words + bitString[63] = true; // Last bit of first word + bitString[64] = true; // First bit of second word + bitString[69] = true; // Last valid bit + + Assert.True(bitString[63]); + Assert.True(bitString[64]); + Assert.True(bitString[69]); + + // Decrease to middle of second word - should mask off bit 69 + bitString.Length = 67; // Should keep first 3 bits of second word + + Assert.Equal(67, bitString.Length); + Assert.True(bitString[63]); + Assert.True(bitString[64]); + + // Increase back and check that bit 69 is cleared (masked off) + bitString.Length = 70; + Assert.False(bitString[69]); // Should be false because it was masked off + } + + [Fact] + public static void LengthSameValueTest() + { + var bitString = new BitString(32); + bitString[5] = true; + bitString[15] = true; + + bitString.Length = 32; // Set to same value + + Assert.Equal(32, bitString.Length); + Assert.True(bitString[5]); + Assert.True(bitString[15]); + } private static void TestToOperationsWithSameMeaning(Action test) { const int n = 5654; From c493f23e10b75a78a9fea57a72e2c36a0f1a797e Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 13:55:16 +0300 Subject: [PATCH 3/5] Fix BitString Length property setter implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove NotImplementedException for length decrease operations - Implement proper shrinking logic with correct bit masking - Fix confusing array clearing and word boundary handling logic - Handle edge cases like setting length to 0 and partial word masking - Ensure min/max positive word boundaries are updated correctly when shrinking This addresses the core issues identified in issue #21, specifically the problematic logic around lines 75-83 in the original implementation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- csharp/Platform.Collections/BitString.cs | 68 +++++++++++++++++++----- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/csharp/Platform.Collections/BitString.cs b/csharp/Platform.Collections/BitString.cs index 4b0b36ac..e061b9a8 100644 --- a/csharp/Platform.Collections/BitString.cs +++ b/csharp/Platform.Collections/BitString.cs @@ -59,34 +59,76 @@ public long Length return; } Ensure.Always.ArgumentInRange(value, GetValidLengthRange(), nameof(Length)); - // Currently we never shrink the array + if (value > _length) { - var words = GetWordsCountFromIndex(value); + // Expanding the bit string + var newWords = GetWordsCountFromIndex(value); var oldWords = GetWordsCountFromIndex(_length); - if (words > _array.LongLength) + + if (newWords > _array.LongLength) { - var copy = new long[words]; + // Need to expand the array + var copy = new long[newWords]; Array.Copy(_array, copy, _array.LongLength); _array = copy; } - else + + // Clear any new words that were added + if (newWords > oldWords) { - // What is going on here? - Array.Clear(_array, (int)oldWords, (int)(words - oldWords)); + Array.Clear(_array, (int)oldWords, (int)(newWords - oldWords)); } - // What is going on here? - var mask = (int)(_length % 64); - if (mask > 0) + + // Mask off any extra bits in the last word of the old length + // This ensures that bits beyond the old length are cleared + var oldBitsInLastWord = (int)(_length % 64); + if (oldBitsInLastWord > 0 && oldWords > 0) { - _array[oldWords - 1] &= (1L << mask) - 1; + var lastOldWordIndex = oldWords - 1; + _array[lastOldWordIndex] &= (1L << oldBitsInLastWord) - 1; } } else { - // Looks like minimum and maximum positive words are not updated - throw new NotImplementedException(); + // Shrinking the bit string + var newWords = GetWordsCountFromIndex(value); + var oldWords = GetWordsCountFromIndex(_length); + + // Clear any words that are now beyond the new length + if (newWords < oldWords) + { + Array.Clear(_array, (int)newWords, (int)(oldWords - newWords)); + } + + // Mask off any extra bits in the last word of the new length + var newBitsInLastWord = (int)(value % 64); + if (newBitsInLastWord > 0 && newWords > 0) + { + var lastNewWordIndex = newWords - 1; + _array[lastNewWordIndex] &= (1L << newBitsInLastWord) - 1; + } + else if (value == 0) + { + // Special case: length is 0, clear everything + if (_array.Length > 0) + { + Array.Clear(_array, 0, (int)Math.Min(_array.Length, oldWords)); + } + } + + // Update the borders to reflect the new state + if (value == 0) + { + MarkBordersAsAllBitsReset(); + } + else + { + // Recalculate borders since we may have cleared some set bits + TryShrinkBorders(); + } } + _length = value; } } From fca12d235b676f39136d1eac396fcff906cec7fe Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 13:56:12 +0300 Subject: [PATCH 4/5] 'Auto-commit changes made by Claude MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude ' --- experiments/LengthPropertyTests.cs | 149 +++++++++++++++++++++++ experiments/LengthTest/LengthTest.csproj | 14 +++ experiments/LengthTest/Program.cs | 81 ++++++++++++ experiments/TestLengthBehavior.cs | 81 ++++++++++++ 4 files changed, 325 insertions(+) create mode 100644 experiments/LengthPropertyTests.cs create mode 100644 experiments/LengthTest/LengthTest.csproj create mode 100644 experiments/LengthTest/Program.cs create mode 100644 experiments/TestLengthBehavior.cs diff --git a/experiments/LengthPropertyTests.cs b/experiments/LengthPropertyTests.cs new file mode 100644 index 00000000..d8d8909f --- /dev/null +++ b/experiments/LengthPropertyTests.cs @@ -0,0 +1,149 @@ +using System; +using Xunit; +using Platform.Collections; + +namespace Platform.Collections.Tests +{ + public class LengthPropertyTests + { + [Fact] + public void Length_IncreaseFromZero_ShouldWork() + { + var bitString = new BitString(0); + Assert.Equal(0, bitString.Length); + + // Should be able to increase length + bitString.Length = 64; + Assert.Equal(64, bitString.Length); + + // All bits should be false initially + for (int i = 0; i < 64; i++) + { + Assert.False(bitString[i]); + } + } + + [Fact] + public void Length_IncreaseFromNonZero_ShouldPreserveExistingBits() + { + var bitString = new BitString(32); + + // Set some bits + bitString[5] = true; + bitString[15] = true; + bitString[25] = true; + + // Increase length + bitString.Length = 64; + Assert.Equal(64, bitString.Length); + + // Original bits should be preserved + Assert.True(bitString[5]); + Assert.True(bitString[15]); + Assert.True(bitString[25]); + + // New bits should be false + for (int i = 32; i < 64; i++) + { + Assert.False(bitString[i]); + } + } + + [Fact] + public void Length_DecreaseLength_ShouldWork() + { + var bitString = new BitString(64); + + // Set some bits + bitString[5] = true; + bitString[15] = true; + bitString[25] = true; + bitString[45] = true; + bitString[55] = true; + + // Decrease length + bitString.Length = 32; + Assert.Equal(32, bitString.Length); + + // Bits within new length should be preserved + Assert.True(bitString[5]); + Assert.True(bitString[15]); + Assert.True(bitString[25]); + + // Should not be able to access bits beyond new length + Assert.Throws(() => bitString[45]); + Assert.Throws(() => bitString[55]); + } + + [Fact] + public void Length_SetToSameValue_ShouldNotChangeAnything() + { + var bitString = new BitString(32); + bitString[5] = true; + bitString[15] = true; + + bitString.Length = 32; // Set to same value + + Assert.Equal(32, bitString.Length); + Assert.True(bitString[5]); + Assert.True(bitString[15]); + } + + [Fact] + public void Length_CrossWordBoundaries_ShouldWork() + { + var bitString = new BitString(63); // Just under 64 (1 word) + bitString[62] = true; + + // Increase to cross word boundary + bitString.Length = 128; // 2 words + Assert.Equal(128, bitString.Length); + Assert.True(bitString[62]); + + // Set bit in second word + bitString[100] = true; + Assert.True(bitString[100]); + + // Decrease back + bitString.Length = 63; + Assert.Equal(63, bitString.Length); + Assert.True(bitString[62]); + } + + [Fact] + public void Length_SetToZero_ShouldWork() + { + var bitString = new BitString(64); + bitString[5] = true; + bitString[15] = true; + + bitString.Length = 0; + Assert.Equal(0, bitString.Length); + + // Should not be able to access any bits + Assert.Throws(() => bitString[0]); + } + + [Fact] + public void Length_HandlePartialWordMasking_ShouldWork() + { + var bitString = new BitString(70); // 1 full word + 6 bits in second word + + // Set bits in both words + bitString[63] = true; // Last bit of first word + bitString[64] = true; // First bit of second word + bitString[69] = true; // Last valid bit + + // Decrease to middle of second word + bitString.Length = 67; // Should keep first 3 bits of second word + + Assert.Equal(67, bitString.Length); + Assert.True(bitString[63]); + Assert.True(bitString[64]); + Assert.Throws(() => bitString[69]); + + // The bit at index 69 should be cleared from internal storage + // even though we can't access it anymore + } + } +} \ No newline at end of file diff --git a/experiments/LengthTest/LengthTest.csproj b/experiments/LengthTest/LengthTest.csproj new file mode 100644 index 00000000..20bce6d9 --- /dev/null +++ b/experiments/LengthTest/LengthTest.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/experiments/LengthTest/Program.cs b/experiments/LengthTest/Program.cs new file mode 100644 index 00000000..42f70e9e --- /dev/null +++ b/experiments/LengthTest/Program.cs @@ -0,0 +1,81 @@ +using System; +using Platform.Collections; + +class Program +{ + static void Main() + { + Console.WriteLine("Testing BitString Length property behavior"); + + try + { + Console.WriteLine("\n1. Testing Length increase from 32 to 64..."); + var bitString = new BitString(32); + bitString[5] = true; + bitString[15] = true; + Console.WriteLine($"Initial length: {bitString.Length}"); + Console.WriteLine($"Bits set: [5]={bitString[5]}, [15]={bitString[15]}"); + + bitString.Length = 64; // This should work + Console.WriteLine($"After increasing to 64: {bitString.Length}"); + Console.WriteLine($"Bits preserved: [5]={bitString[5]}, [15]={bitString[15]}"); + } + catch (Exception ex) + { + Console.WriteLine($"Error during length increase: {ex.Message}"); + } + + try + { + Console.WriteLine("\n2. Testing Length decrease from 64 to 32..."); + var bitString = new BitString(64); + bitString[5] = true; + bitString[45] = true; + Console.WriteLine($"Initial length: {bitString.Length}"); + Console.WriteLine($"Bits set: [5]={bitString[5]}, [45]={bitString[45]}"); + + bitString.Length = 32; // This currently throws NotImplementedException + Console.WriteLine($"After decreasing to 32: {bitString.Length}"); + Console.WriteLine($"Bit [5] preserved: {bitString[5]}"); + } + catch (NotImplementedException) + { + Console.WriteLine("Length decrease throws NotImplementedException (expected issue)"); + } + catch (Exception ex) + { + Console.WriteLine($"Unexpected error: {ex.Message}"); + } + + try + { + Console.WriteLine("\n3. Testing Length set to 0..."); + var bitString = new BitString(10); + Console.WriteLine($"Initial length: {bitString.Length}"); + + bitString.Length = 0; + Console.WriteLine($"After setting to 0: {bitString.Length}"); + } + catch (Exception ex) + { + Console.WriteLine($"Error setting length to 0: {ex.Message}"); + } + + try + { + Console.WriteLine("\n4. Testing cross-word boundary (63 to 65)..."); + var bitString = new BitString(63); + bitString[62] = true; + Console.WriteLine($"Initial length: {bitString.Length}"); + Console.WriteLine($"Bit [62] set: {bitString[62]}"); + + bitString.Length = 65; + Console.WriteLine($"After increasing to 65: {bitString.Length}"); + Console.WriteLine($"Bit [62] preserved: {bitString[62]}"); + } + catch (Exception ex) + { + Console.WriteLine($"Error with cross-word boundary: {ex.Message}"); + } + } +} diff --git a/experiments/TestLengthBehavior.cs b/experiments/TestLengthBehavior.cs new file mode 100644 index 00000000..6bbe0441 --- /dev/null +++ b/experiments/TestLengthBehavior.cs @@ -0,0 +1,81 @@ +using System; +using Platform.Collections; + +class Program +{ + static void Main() + { + Console.WriteLine("Testing BitString Length property behavior"); + + try + { + Console.WriteLine("\n1. Testing Length increase from 32 to 64..."); + var bitString = new BitString(32); + bitString[5] = true; + bitString[15] = true; + Console.WriteLine($"Initial length: {bitString.Length}"); + Console.WriteLine($"Bits set: [5]={bitString[5]}, [15]={bitString[15]}"); + + bitString.Length = 64; // This should work + Console.WriteLine($"After increasing to 64: {bitString.Length}"); + Console.WriteLine($"Bits preserved: [5]={bitString[5]}, [15]={bitString[15]}"); + } + catch (Exception ex) + { + Console.WriteLine($"Error during length increase: {ex.Message}"); + } + + try + { + Console.WriteLine("\n2. Testing Length decrease from 64 to 32..."); + var bitString = new BitString(64); + bitString[5] = true; + bitString[45] = true; + Console.WriteLine($"Initial length: {bitString.Length}"); + Console.WriteLine($"Bits set: [5]={bitString[5]}, [45]={bitString[45]}"); + + bitString.Length = 32; // This currently throws NotImplementedException + Console.WriteLine($"After decreasing to 32: {bitString.Length}"); + Console.WriteLine($"Bit [5] preserved: {bitString[5]}"); + } + catch (NotImplementedException) + { + Console.WriteLine("Length decrease throws NotImplementedException (expected issue)"); + } + catch (Exception ex) + { + Console.WriteLine($"Unexpected error: {ex.Message}"); + } + + try + { + Console.WriteLine("\n3. Testing Length set to 0..."); + var bitString = new BitString(10); + Console.WriteLine($"Initial length: {bitString.Length}"); + + bitString.Length = 0; + Console.WriteLine($"After setting to 0: {bitString.Length}"); + } + catch (Exception ex) + { + Console.WriteLine($"Error setting length to 0: {ex.Message}"); + } + + try + { + Console.WriteLine("\n4. Testing cross-word boundary (63 to 65)..."); + var bitString = new BitString(63); + bitString[62] = true; + Console.WriteLine($"Initial length: {bitString.Length}"); + Console.WriteLine($"Bit [62] set: {bitString[62]}"); + + bitString.Length = 65; + Console.WriteLine($"After increasing to 65: {bitString.Length}"); + Console.WriteLine($"Bit [62] preserved: {bitString[62]}"); + } + catch (Exception ex) + { + Console.WriteLine($"Error with cross-word boundary: {ex.Message}"); + } + } +} \ No newline at end of file From 105ce4202154658648aee94d3d22641b00c49062 Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 13:56:13 +0300 Subject: [PATCH 5/5] Remove CLAUDE.md - Claude command completed --- CLAUDE.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index b744abec..00000000 --- a/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -Issue to solve: https://github.com/linksplatform/Collections/issues/21 -Your prepared branch: issue-21-657d3fe1 -Your prepared working directory: /tmp/gh-issue-solver-1757846616189 - -Proceed. \ No newline at end of file