From a0e990625922f0107823a34cab63a2ace22865c7 Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 07:30:26 +0300 Subject: [PATCH 1/3] Initial commit with task details for issue #55 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/55 --- 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..6e8a890b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +Issue to solve: https://github.com/linksplatform/Collections/issues/55 +Your prepared branch: issue-55-9b5e30ca +Your prepared working directory: /tmp/gh-issue-solver-1757824215460 + +Proceed. \ No newline at end of file From 7d095b9a733d435d622516fe02ef227159fa6f4c Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 07:39:57 +0300 Subject: [PATCH 2/3] Make Segment semantics compatible with ArraySegment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added ArraySegment-compatible API to Segment class: - Static Empty property for creating empty segments - Array property that returns the underlying array when Base is T[] - Constructors that match ArraySegment signature patterns - Slice() methods for creating sub-segments - ToArray() method for copying segment contents to a new array All changes maintain backward compatibility while adding new functionality. Comprehensive test coverage included. πŸ€– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../SegmentTests.cs | 183 ++++++++++++++++++ .../Platform.Collections/Segments/Segment.cs | 101 ++++++++++ 2 files changed, 284 insertions(+) create mode 100644 csharp/Platform.Collections.Tests/SegmentTests.cs diff --git a/csharp/Platform.Collections.Tests/SegmentTests.cs b/csharp/Platform.Collections.Tests/SegmentTests.cs new file mode 100644 index 00000000..c6f76c06 --- /dev/null +++ b/csharp/Platform.Collections.Tests/SegmentTests.cs @@ -0,0 +1,183 @@ +using System; +using System.Linq; +using Xunit; +using Platform.Collections.Segments; + +namespace Platform.Collections.Tests +{ + public static class SegmentTests + { + [Fact] + public static void EmptySegmentTest() + { + var empty = Segment.Empty; + Assert.Equal(0, empty.Length); + Assert.Equal(0, empty.Count); + Assert.Equal(0, empty.Offset); + Assert.NotNull(empty.Base); + } + + [Fact] + public static void ArrayConstructorTest() + { + var array = new int[] { 1, 2, 3, 4, 5 }; + var segment = new Segment(array); + + Assert.Equal(array, segment.Array); + Assert.Equal(array, segment.Base); + Assert.Equal(0, segment.Offset); + Assert.Equal(5, segment.Length); + Assert.Equal(5, segment.Count); + } + + [Fact] + public static void ArrayWithOffsetAndCountConstructorTest() + { + var array = new int[] { 1, 2, 3, 4, 5 }; + var segment = new Segment(array, 1, 3); + + Assert.Equal(array, segment.Array); + Assert.Equal(array, segment.Base); + Assert.Equal(1, segment.Offset); + Assert.Equal(3, segment.Length); + Assert.Equal(3, segment.Count); + + // Test indexing + Assert.Equal(2, segment[0]); + Assert.Equal(3, segment[1]); + Assert.Equal(4, segment[2]); + } + + [Fact] + public static void ArrayConstructorValidationTest() + { + Assert.Throws(() => new Segment((int[])null)); + Assert.Throws(() => new Segment(null, 0, 0)); + + var array = new int[] { 1, 2, 3 }; + Assert.Throws(() => new Segment(array, -1, 1)); + Assert.Throws(() => new Segment(array, 0, -1)); + Assert.Throws(() => new Segment(array, 2, 3)); // offset + count > array.Length + } + + [Fact] + public static void SliceTest() + { + var array = new int[] { 1, 2, 3, 4, 5 }; + var segment = new Segment(array, 1, 4); // [2, 3, 4, 5] + + // Slice from index 1 to end + var slice1 = segment.Slice(1); + Assert.Equal(2, slice1.Offset); // 1 + 1 + Assert.Equal(3, slice1.Length); // 4 - 1 + Assert.Equal(3, slice1[0]); // array[2] + Assert.Equal(4, slice1[1]); // array[3] + Assert.Equal(5, slice1[2]); // array[4] + + // Slice with specific count + var slice2 = segment.Slice(1, 2); + Assert.Equal(2, slice2.Offset); // 1 + 1 + Assert.Equal(2, slice2.Length); // specified count + Assert.Equal(3, slice2[0]); // array[2] + Assert.Equal(4, slice2[1]); // array[3] + } + + [Fact] + public static void SliceValidationTest() + { + var array = new int[] { 1, 2, 3, 4, 5 }; + var segment = new Segment(array, 1, 3); + + Assert.Throws(() => segment.Slice(-1)); + Assert.Throws(() => segment.Slice(4)); // index > Length + Assert.Throws(() => segment.Slice(0, -1)); + Assert.Throws(() => segment.Slice(2, 2)); // index + count > Length + } + + [Fact] + public static void ToArrayTest() + { + var array = new int[] { 1, 2, 3, 4, 5 }; + var segment = new Segment(array, 1, 3); // [2, 3, 4] + + var result = segment.ToArray(); + + Assert.Equal(3, result.Length); + Assert.Equal(2, result[0]); + Assert.Equal(3, result[1]); + Assert.Equal(4, result[2]); + + // Ensure it's a copy, not the same array + Assert.NotSame(array, result); + + // Modify original array and ensure copy is unchanged + array[2] = 99; + Assert.Equal(3, result[1]); // Should still be 3 + } + + [Fact] + public static void ArrayPropertyTest() + { + var array = new int[] { 1, 2, 3, 4, 5 }; + var segment = new Segment(array); + + Assert.Same(array, segment.Array); + + // Test with IList (not array) + var list = new System.Collections.Generic.List { 1, 2, 3 }; + var listSegment = new Segment(list, 0, 2); + Assert.Null(listSegment.Array); // Should return null for non-array IList + } + + [Fact] + public static void EnumerationTest() + { + var array = new int[] { 1, 2, 3, 4, 5 }; + var segment = new Segment(array, 1, 3); // [2, 3, 4] + + var result = segment.ToArray(); + var expected = new int[] { 2, 3, 4 }; + + Assert.True(result.SequenceEqual(expected)); + } + + [Fact] + public static void CountPropertyCompatibilityTest() + { + var array = new int[] { 1, 2, 3, 4, 5 }; + var segment = new Segment(array, 1, 3); + + // Count should be the same as Length (ArraySegment compatibility) + Assert.Equal(segment.Length, segment.Count); + Assert.Equal(3, segment.Count); + } + + [Fact] + public static void ArraySegmentSemanticCompatibilityTest() + { + var array = new int[] { 10, 20, 30, 40, 50 }; + + // Test behavior similar to ArraySegment + var segment1 = new Segment(array); // Entire array + var segment2 = new Segment(array, 2, 2); // [30, 40] + + // ArraySegment-like properties + Assert.Same(array, segment1.Array); + Assert.Same(array, segment2.Array); + Assert.Equal(0, segment1.Offset); + Assert.Equal(2, segment2.Offset); + Assert.Equal(5, segment1.Count); + Assert.Equal(2, segment2.Count); + + // ArraySegment-like methods + var slice = segment1.Slice(1, 3); // [20, 30, 40] + Assert.Equal(3, slice.Count); + Assert.Equal(20, slice[0]); + Assert.Equal(30, slice[1]); + Assert.Equal(40, slice[2]); + + var copyArray = slice.ToArray(); + Assert.Equal(new int[] { 20, 30, 40 }, copyArray); + } + } +} \ No newline at end of file diff --git a/csharp/Platform.Collections/Segments/Segment.cs b/csharp/Platform.Collections/Segments/Segment.cs index 7f62bb51..6dbc737d 100644 --- a/csharp/Platform.Collections/Segments/Segment.cs +++ b/csharp/Platform.Collections/Segments/Segment.cs @@ -16,6 +16,15 @@ namespace Platform.Collections.Segments /// The segment elements type.Π’ΠΈΠΏ элСмСнтов сСгмСнта. public class Segment : IEquatable>, IList { + /// + /// Gets an empty segment. + /// Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ пустой сСгмСнт. + /// + public static Segment Empty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => new Segment(new T[0], 0, 0); + } /// /// Gets the original list (this segment is a part of it). /// Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ исходный список (Ρ‡Π°ΡΡ‚ΡŒΡŽ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ являСтся этот сСгмСнт). @@ -44,6 +53,17 @@ public int Length get; } + /// + /// Gets the original array when the base is an array. Compatible with ArraySegment semantics. + /// Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ исходный массив, ΠΊΠΎΠ³Π΄Π° основой являСтся массив. БовмСстим с сСмантикой ArraySegment. + /// + public T[] Array + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Base as T[]; + } + + /// /// Initializes a new instance of the class, using the list, of the segment and its . /// Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ Π½ΠΎΠ²Ρ‹ΠΉ экзСмпляр класса , ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ список , сСгмСнта ΠΈ Π΅Π³ΠΎ . @@ -58,6 +78,43 @@ public Segment(IList @base, int offset, int length) Offset = offset; Length = length; } + + /// + /// Initializes a new instance of the class that delimits the entire array. Compatible with ArraySegment constructor. + /// Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ Π½ΠΎΠ²Ρ‹ΠΉ экзСмпляр класса , ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Ρ€Π°Π·Π³Ρ€Π°Π½ΠΈΡ‡ΠΈΠ²Π°Π΅Ρ‚ вСсь массив. БовмСстим с конструктором ArraySegment. + /// + /// The array to wrap in the segment.Массив для обСртывания Π² сСгмСнт. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Segment(T[] array) + { + Base = array ?? throw new ArgumentNullException(nameof(array)); + Offset = 0; + Length = array.Length; + } + + /// + /// Initializes a new instance of the class that delimits a range of elements in an array. Compatible with ArraySegment constructor. + /// Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ Π½ΠΎΠ²Ρ‹ΠΉ экзСмпляр класса , ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Ρ€Π°Π·Π³Ρ€Π°Π½ΠΈΡ‡ΠΈΠ²Π°Π΅Ρ‚ Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½ элСмСнтов Π² массивС. БовмСстим с конструктором ArraySegment. + /// + /// The array to wrap in the segment.Массив для обСртывания Π² сСгмСнт. + /// The zero-based index of the first element in the range delimited by the array segment.ΠžΡ‚ΡΡ‡ΠΈΡ‚Ρ‹Π²Π°Π΅ΠΌΡ‹ΠΉ ΠΎΡ‚ нуля индСкс ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ элСмСнта Π² Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½Π΅, Ρ€Π°Π·Π΄Π΅Π»Π΅Π½Π½ΠΎΠΌ сСгмСнтом массива. + /// The number of elements in the range delimited by the array segment.ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ элСмСнтов Π² Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½Π΅, Ρ€Π°Π·Π΄Π΅Π»Π΅Π½Π½ΠΎΠΌ сСгмСнтом массива. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Segment(T[] array, int offset, int count) + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (offset < 0) + throw new ArgumentOutOfRangeException(nameof(offset)); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count)); + if (offset + count > array.Length) + throw new ArgumentException("Offset and count exceed array bounds."); + + Base = array; + Offset = offset; + Length = count; + } /// /// Gets the hash code of the current instance. @@ -96,6 +153,50 @@ public Segment(IList @base, int offset, int length) [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) => obj is Segment other ? Equals(other) : false; + /// + /// Forms a slice out of the current segment that begins at a specified index. Compatible with ArraySegment semantics. + /// Π€ΠΎΡ€ΠΌΠΈΡ€ΡƒΠ΅Ρ‚ срСз ΠΈΠ· Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ сСгмСнта, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ начинаСтся с ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠ³ΠΎ индСкса. БовмСстим с сСмантикой ArraySegment. + /// + /// The index at which to begin the slice.ИндСкс, с ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ начинаСтся срСз. + /// A segment that consists of all elements of the current segment from to the end.Π‘Π΅Π³ΠΌΠ΅Π½Ρ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ состоит ΠΈΠ· всСх элСмСнтов Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ сСгмСнта ΠΎΡ‚ Π΄ΠΎ ΠΊΠΎΠ½Ρ†Π°. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Segment Slice(int index) + { + if (index < 0 || index > Length) + throw new ArgumentOutOfRangeException(nameof(index)); + return new Segment(Base, Offset + index, Length - index); + } + + /// + /// Forms a slice out of the current segment starting at a specified index for a specified length. Compatible with ArraySegment semantics. + /// Π€ΠΎΡ€ΠΌΠΈΡ€ΡƒΠ΅Ρ‚ срСз ΠΈΠ· Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ сСгмСнта, начиная с ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠ³ΠΎ индСкса для ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠΉ Π΄Π»ΠΈΠ½Ρ‹. БовмСстим с сСмантикой ArraySegment. + /// + /// The index at which to begin the slice.ИндСкс, с ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ начинаСтся срСз. + /// The desired length for the slice.ЖСлаСмая Π΄Π»ΠΈΠ½Π° срСза. + /// A segment that consists of elements from the current segment starting at .Π‘Π΅Π³ΠΌΠ΅Π½Ρ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ состоит ΠΈΠ· элСмСнтов Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ сСгмСнта, начиная с . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Segment Slice(int index, int count) + { + if (index < 0 || index > Length) + throw new ArgumentOutOfRangeException(nameof(index)); + if (count < 0 || index + count > Length) + throw new ArgumentOutOfRangeException(nameof(count)); + return new Segment(Base, Offset + index, count); + } + + /// + /// Copies the contents of this segment into a new array. Compatible with ArraySegment semantics. + /// ΠšΠΎΠΏΠΈΡ€ΡƒΠ΅Ρ‚ содСрТимоС этого сСгмСнта Π² Π½ΠΎΠ²Ρ‹ΠΉ массив. БовмСстим с сСмантикой ArraySegment. + /// + /// An array containing copies of the elements of the current segment.Массив, содСрТащий ΠΊΠΎΠΏΠΈΠΈ элСмСнтов Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ сСгмСнта. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T[] ToArray() + { + var result = new T[Length]; + CopyTo(result, 0); + return result; + } + #region IList /// From d355600c1a3e7dae45fe8da513f8fdaff84d89ba Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 07:40:41 +0300 Subject: [PATCH 3/3] 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 6e8a890b..00000000 --- a/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -Issue to solve: https://github.com/linksplatform/Collections/issues/55 -Your prepared branch: issue-55-9b5e30ca -Your prepared working directory: /tmp/gh-issue-solver-1757824215460 - -Proceed. \ No newline at end of file