From 5a9e9faf44a0ce54a11c5e2b8d67cebf05efb0e5 Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 07:35:54 +0300 Subject: [PATCH 1/4] Initial commit with task details for issue #125 Adding CLAUDE.md with task information for AI processing. This file will be removed when the task is complete. Issue: https://github.com/linksplatform/Data.Doublets/issues/125 --- 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 000000000..ead68b573 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +Issue to solve: https://github.com/linksplatform/Data.Doublets/issues/125 +Your prepared branch: issue-125-7f224c52 +Your prepared working directory: /tmp/gh-issue-solver-1757824498445 + +Proceed. \ No newline at end of file From 03bdbfbe4a9a298c3f8b3ea5f0de5efdd4e057ff Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 07:56:52 +0300 Subject: [PATCH 2/4] Add property operator implementations with support for multiple values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit implements the requested feature from issue #125 by adding two new property operators that extend the existing functionality to support multiple values: 1. MultipleValuesPropertyOperator - Extends PropertyOperator to store and manage multiple values for a single property - Key methods: GetAll(), Add(), Remove(), Set(), Clear(), Contains(), Count() 2. MultipleValuesPropertiesOperator - Extends PropertiesOperator to handle multiple values for object-property combinations - Key methods: GetAllValues(), AddValue(), RemoveValue(), SetAllValues(), etc. Both operators maintain compatibility with the existing architecture while providing the requested multiple values functionality. Comprehensive test suites are included to verify correct behavior for all operations. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../MultipleValuesPropertiesOperatorTests.cs | 129 ++++++++ .../MultipleValuesPropertyOperatorTests.cs | 109 ++++++ .../MultipleValuesPropertiesOperator.cs | 302 +++++++++++++++++ .../MultipleValuesPropertyOperator.cs | 310 ++++++++++++++++++ 4 files changed, 850 insertions(+) create mode 100644 csharp/Platform.Data.Doublets.Tests/MultipleValuesPropertiesOperatorTests.cs create mode 100644 csharp/Platform.Data.Doublets.Tests/MultipleValuesPropertyOperatorTests.cs create mode 100644 csharp/Platform.Data.Doublets/PropertyOperators/MultipleValuesPropertiesOperator.cs create mode 100644 csharp/Platform.Data.Doublets/PropertyOperators/MultipleValuesPropertyOperator.cs diff --git a/csharp/Platform.Data.Doublets.Tests/MultipleValuesPropertiesOperatorTests.cs b/csharp/Platform.Data.Doublets.Tests/MultipleValuesPropertiesOperatorTests.cs new file mode 100644 index 000000000..9b8b844c1 --- /dev/null +++ b/csharp/Platform.Data.Doublets.Tests/MultipleValuesPropertiesOperatorTests.cs @@ -0,0 +1,129 @@ +using System; +using System.IO; +using System.Numerics; +using System.Linq; +using Platform.Data.Doublets.Decorators; +using Platform.Data.Doublets.PropertyOperators; +using Xunit; + +using Platform.Memory; + +using Platform.Data.Doublets.Memory.United.Generic; + +namespace Platform.Data.Doublets.Tests +{ + public static class MultipleValuesPropertiesOperatorTests + { + [Fact] + public static void MultipleValuesPropertiesOperatorTest() + { + Using(links => + { + var propertiesOperator = new MultipleValuesPropertiesOperator(links); + + // Test basic functionality + var obj = links.Create(); + var property = links.Create(); + var value1 = links.Create(); + var value2 = links.Create(); + var value3 = links.Create(); + + // Test adding values + propertiesOperator.AddValue(obj, property, value1); + propertiesOperator.AddValue(obj, property, value2); + propertiesOperator.AddValue(obj, property, value3); + + // Test counting values + Assert.Equal(3, propertiesOperator.CountValues(obj, property)); + + // Test getting all values + var allValues = propertiesOperator.GetAllValues(obj, property).ToList(); + Assert.Equal(3, allValues.Count); + Assert.Contains(value1, allValues); + Assert.Contains(value2, allValues); + Assert.Contains(value3, allValues); + + // Test getting first value + var firstValue = propertiesOperator.GetFirstValue(obj, property); + Assert.True(firstValue == value1 || firstValue == value2 || firstValue == value3); + + // Test contains functionality + Assert.True(propertiesOperator.ContainsValue(obj, property, value1)); + Assert.True(propertiesOperator.ContainsValue(obj, property, value2)); + Assert.True(propertiesOperator.ContainsValue(obj, property, value3)); + + var nonExistentValue = links.Create(); + Assert.False(propertiesOperator.ContainsValue(obj, property, nonExistentValue)); + + // Test removing a value + propertiesOperator.RemoveValue(obj, property, value2); + Assert.Equal(2, propertiesOperator.CountValues(obj, property)); + Assert.False(propertiesOperator.ContainsValue(obj, property, value2)); + Assert.True(propertiesOperator.ContainsValue(obj, property, value1)); + Assert.True(propertiesOperator.ContainsValue(obj, property, value3)); + + // Test adding duplicate value (should not increase count) + propertiesOperator.AddValue(obj, property, value1); + Assert.Equal(2, propertiesOperator.CountValues(obj, property)); + + // Test setting values (replace all) + var newValue1 = links.Create(); + var newValue2 = links.Create(); + propertiesOperator.SetAllValues(obj, property, new[] { newValue1, newValue2 }); + + Assert.Equal(2, propertiesOperator.CountValues(obj, property)); + Assert.True(propertiesOperator.ContainsValue(obj, property, newValue1)); + Assert.True(propertiesOperator.ContainsValue(obj, property, newValue2)); + Assert.False(propertiesOperator.ContainsValue(obj, property, value1)); + Assert.False(propertiesOperator.ContainsValue(obj, property, value3)); + + // Test clearing all values + propertiesOperator.ClearAllValues(obj, property); + Assert.Equal(0, propertiesOperator.CountValues(obj, property)); + Assert.False(propertiesOperator.ContainsValue(obj, property, newValue1)); + Assert.False(propertiesOperator.ContainsValue(obj, property, newValue2)); + + // Test operations on non-existent object-property combination + var emptyObj = links.Create(); + var emptyProperty = links.Create(); + Assert.Equal(0, propertiesOperator.CountValues(emptyObj, emptyProperty)); + Assert.Equal(default(ulong), propertiesOperator.GetFirstValue(emptyObj, emptyProperty)); + Assert.False(propertiesOperator.ContainsValue(emptyObj, emptyProperty, value1)); + + // Test remove on non-existent combination (should not throw) + propertiesOperator.RemoveValue(emptyObj, emptyProperty, value1); + Assert.Equal(0, propertiesOperator.CountValues(emptyObj, emptyProperty)); + + // Test multiple objects with same property + var obj2 = links.Create(); + var obj2Value1 = links.Create(); + var obj2Value2 = links.Create(); + + propertiesOperator.AddValue(obj2, property, obj2Value1); + propertiesOperator.AddValue(obj2, property, obj2Value2); + + // obj1 should still have no values (cleared above) + Assert.Equal(0, propertiesOperator.CountValues(obj, property)); + + // obj2 should have 2 values + Assert.Equal(2, propertiesOperator.CountValues(obj2, property)); + Assert.True(propertiesOperator.ContainsValue(obj2, property, obj2Value1)); + Assert.True(propertiesOperator.ContainsValue(obj2, property, obj2Value2)); + + // obj2 should not contain obj1's values + Assert.False(propertiesOperator.ContainsValue(obj2, property, value1)); + Assert.False(propertiesOperator.ContainsValue(obj2, property, value3)); + }); + } + + private static void Using(Action> action) where TLinkAddress : IUnsignedNumber, IShiftOperators, IBitwiseOperators, IMinMaxValue, IComparisonOperators + { + var unitedMemoryLinks = new UnitedMemoryLinks(new HeapResizableDirectMemory()); + using (var logFile = File.Open("multipleValuesPropertiesOperatorTest.txt", FileMode.Create, FileAccess.Write)) + { + LoggingDecorator decoratedStorage = new(unitedMemoryLinks, logFile); + action(decoratedStorage); + } + } + } +} \ No newline at end of file diff --git a/csharp/Platform.Data.Doublets.Tests/MultipleValuesPropertyOperatorTests.cs b/csharp/Platform.Data.Doublets.Tests/MultipleValuesPropertyOperatorTests.cs new file mode 100644 index 000000000..4adfc02a3 --- /dev/null +++ b/csharp/Platform.Data.Doublets.Tests/MultipleValuesPropertyOperatorTests.cs @@ -0,0 +1,109 @@ +using System; +using System.IO; +using System.Numerics; +using System.Linq; +using Platform.Data.Doublets.Decorators; +using Platform.Data.Doublets.PropertyOperators; +using Xunit; + +using Platform.Memory; + +using Platform.Data.Doublets.Memory.United.Generic; + +namespace Platform.Data.Doublets.Tests +{ + public static class MultipleValuesPropertyOperatorTests + { + [Fact] + public static void MultipleValuesPropertyOperatorTest() + { + Using(links => + { + var propertyMarker = links.Create(); + var propertyValueMarker = links.Create(); + var propertyOperator = new MultipleValuesPropertyOperator(links, propertyMarker, propertyValueMarker); + + // Test basic functionality + var link = links.Create(); + var value1 = links.Create(); + var value2 = links.Create(); + var value3 = links.Create(); + + // Test adding values + propertyOperator.Add(link, value1); + propertyOperator.Add(link, value2); + propertyOperator.Add(link, value3); + + // Test counting values + Assert.Equal(3, propertyOperator.Count(link)); + + // Test getting all values + var allValues = propertyOperator.GetAll(link).ToList(); + Assert.Equal(3, allValues.Count); + Assert.Contains(value1, allValues); + Assert.Contains(value2, allValues); + Assert.Contains(value3, allValues); + + // Test getting first value + var firstValue = propertyOperator.GetFirst(link); + Assert.True(firstValue == value1 || firstValue == value2 || firstValue == value3); + + // Test contains functionality + Assert.True(propertyOperator.Contains(link, value1)); + Assert.True(propertyOperator.Contains(link, value2)); + Assert.True(propertyOperator.Contains(link, value3)); + + var nonExistentValue = links.Create(); + Assert.False(propertyOperator.Contains(link, nonExistentValue)); + + // Test removing a value + propertyOperator.Remove(link, value2); + Assert.Equal(2, propertyOperator.Count(link)); + Assert.False(propertyOperator.Contains(link, value2)); + Assert.True(propertyOperator.Contains(link, value1)); + Assert.True(propertyOperator.Contains(link, value3)); + + // Test adding duplicate value (should not increase count) + propertyOperator.Add(link, value1); + Assert.Equal(2, propertyOperator.Count(link)); + + // Test setting values (replace all) + var newValue1 = links.Create(); + var newValue2 = links.Create(); + propertyOperator.Set(link, new[] { newValue1, newValue2 }); + + Assert.Equal(2, propertyOperator.Count(link)); + Assert.True(propertyOperator.Contains(link, newValue1)); + Assert.True(propertyOperator.Contains(link, newValue2)); + Assert.False(propertyOperator.Contains(link, value1)); + Assert.False(propertyOperator.Contains(link, value3)); + + // Test clearing all values + propertyOperator.Clear(link); + Assert.Equal(0, propertyOperator.Count(link)); + Assert.False(propertyOperator.Contains(link, newValue1)); + Assert.False(propertyOperator.Contains(link, newValue2)); + + // Test operations on non-existent property + var emptyLink = links.Create(); + Assert.Equal(0, propertyOperator.Count(emptyLink)); + Assert.Equal(default(ulong), propertyOperator.GetFirst(emptyLink)); + Assert.False(propertyOperator.Contains(emptyLink, value1)); + + // Test remove on non-existent property (should not throw) + propertyOperator.Remove(emptyLink, value1); + Assert.Equal(0, propertyOperator.Count(emptyLink)); + }); + } + + private static void Using(Action> action) where TLinkAddress : IUnsignedNumber, IShiftOperators, IBitwiseOperators, IMinMaxValue, IComparisonOperators + { + var unitedMemoryLinks = new UnitedMemoryLinks(new HeapResizableDirectMemory()); + using (var logFile = File.Open("multipleValuesPropertyOperatorTest.txt", FileMode.Create, FileAccess.Write)) + { + LoggingDecorator decoratedStorage = new(unitedMemoryLinks, logFile); + action(decoratedStorage); + } + } + } +} \ No newline at end of file diff --git a/csharp/Platform.Data.Doublets/PropertyOperators/MultipleValuesPropertiesOperator.cs b/csharp/Platform.Data.Doublets/PropertyOperators/MultipleValuesPropertiesOperator.cs new file mode 100644 index 000000000..4e2205e73 --- /dev/null +++ b/csharp/Platform.Data.Doublets/PropertyOperators/MultipleValuesPropertiesOperator.cs @@ -0,0 +1,302 @@ +using System.Collections.Generic; +using System.Numerics; +using System.Runtime.CompilerServices; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Platform.Data.Doublets.PropertyOperators +{ + /// + /// + /// Represents a properties operator that supports multiple values for object-property combinations. + /// + /// + /// + /// + public class MultipleValuesPropertiesOperator : LinksOperatorBase where TLinkAddress : IUnsignedNumber + { + /// + /// + /// Initializes a new instance. + /// + /// + /// + /// + /// A links. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public MultipleValuesPropertiesOperator(ILinks links) : base(links) { } + + /// + /// + /// Gets all values for the specified object-property combination. + /// + /// + /// + /// + /// The object. + /// + /// + /// + /// The property. + /// + /// + /// + /// A collection of all values for the object-property combination + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public IEnumerable GetAllValues(TLinkAddress @object, TLinkAddress property) + { + var links = _links; + var objectProperty = links.SearchOrDefault(@object, property); + if (objectProperty == default) + { + yield break; + } + + var constants = links.Constants; + var any = constants.Any; + var query = new Link(any, objectProperty, any); + + var values = new List(); + links.Each(candidate => + { + values.Add(links.GetTarget(links.GetIndex(candidate))); + return constants.Continue; + }, query); + + foreach (var value in values) + { + yield return value; + } + } + + /// + /// + /// Gets the first value for the specified object-property combination. + /// + /// + /// + /// + /// The object. + /// + /// + /// + /// The property. + /// + /// + /// + /// The first value, or default if no values exist + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TLinkAddress GetFirstValue(TLinkAddress @object, TLinkAddress property) + { + foreach (var value in GetAllValues(@object, property)) + { + return value; + } + return default; + } + + /// + /// + /// Adds a value to the specified object-property combination. + /// + /// + /// + /// + /// The object. + /// + /// + /// + /// The property. + /// + /// + /// + /// The value to add. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddValue(TLinkAddress @object, TLinkAddress property, TLinkAddress value) + { + if (ContainsValue(@object, property, value)) + { + return; // Value already exists, no need to add + } + + var links = _links; + var objectProperty = links.GetOrCreate(@object, property); + links.GetOrCreate(objectProperty, value); + } + + /// + /// + /// Removes a specific value from the specified object-property combination. + /// + /// + /// + /// + /// The object. + /// + /// + /// + /// The property. + /// + /// + /// + /// The value to remove. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RemoveValue(TLinkAddress @object, TLinkAddress property, TLinkAddress value) + { + var links = _links; + var objectProperty = links.SearchOrDefault(@object, property); + if (objectProperty == default) + { + return; + } + + var propertyValueLink = links.SearchOrDefault(objectProperty, value); + if (propertyValueLink != default) + { + links.Delete(propertyValueLink); + } + } + + /// + /// + /// Sets all values for the specified object-property combination, replacing any existing values. + /// + /// + /// + /// + /// The object. + /// + /// + /// + /// The property. + /// + /// + /// + /// The values to set. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetAllValues(TLinkAddress @object, TLinkAddress property, IEnumerable values) + { + ClearAllValues(@object, property); + foreach (var value in values) + { + AddValue(@object, property, value); + } + } + + /// + /// + /// Clears all values for the specified object-property combination. + /// + /// + /// + /// + /// The object. + /// + /// + /// + /// The property. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ClearAllValues(TLinkAddress @object, TLinkAddress property) + { + var links = _links; + var objectProperty = links.SearchOrDefault(@object, property); + if (objectProperty == default) + { + return; + } + + var constants = links.Constants; + var any = constants.Any; + var linksToDelete = new List(); + + links.Each(candidate => + { + linksToDelete.Add(links.GetIndex(candidate)); + return constants.Continue; + }, new Link(any, objectProperty, any)); + + foreach (var linkToDelete in linksToDelete) + { + links.Delete(linkToDelete); + } + } + + /// + /// + /// Checks if the specified object-property combination contains the specified value. + /// + /// + /// + /// + /// The object. + /// + /// + /// + /// The property. + /// + /// + /// + /// The value to check for. + /// + /// + /// + /// True if the object-property combination contains the value, false otherwise + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool ContainsValue(TLinkAddress @object, TLinkAddress property, TLinkAddress value) + { + var links = _links; + var objectProperty = links.SearchOrDefault(@object, property); + if (objectProperty == default) + { + return false; + } + + return links.SearchOrDefault(objectProperty, value) != default; + } + + /// + /// + /// Gets the count of values for the specified object-property combination. + /// + /// + /// + /// + /// The object. + /// + /// + /// + /// The property. + /// + /// + /// + /// The number of values for the object-property combination + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int CountValues(TLinkAddress @object, TLinkAddress property) + { + var count = 0; + foreach (var _ in GetAllValues(@object, property)) + { + count++; + } + return count; + } + } +} \ No newline at end of file diff --git a/csharp/Platform.Data.Doublets/PropertyOperators/MultipleValuesPropertyOperator.cs b/csharp/Platform.Data.Doublets/PropertyOperators/MultipleValuesPropertyOperator.cs new file mode 100644 index 000000000..d2f0ece6e --- /dev/null +++ b/csharp/Platform.Data.Doublets/PropertyOperators/MultipleValuesPropertyOperator.cs @@ -0,0 +1,310 @@ +using System.Collections.Generic; +using System.Numerics; +using System.Runtime.CompilerServices; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Platform.Data.Doublets.PropertyOperators +{ + /// + /// + /// Represents a property operator that supports multiple values for a single property. + /// + /// + /// + /// + public class MultipleValuesPropertyOperator : LinksOperatorBase where TLinkAddress : IUnsignedNumber + { + private readonly TLinkAddress _propertyMarker; + private readonly TLinkAddress _propertyValueMarker; + + /// + /// + /// Initializes a new instance. + /// + /// + /// + /// + /// A links. + /// + /// + /// + /// A property marker. + /// + /// + /// + /// A property value marker. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public MultipleValuesPropertyOperator(ILinks links, TLinkAddress propertyMarker, TLinkAddress propertyValueMarker) : base(links) + { + _propertyMarker = propertyMarker; + _propertyValueMarker = propertyValueMarker; + } + + /// + /// + /// Gets all values for the specified link property. + /// + /// + /// + /// + /// The link. + /// + /// + /// + /// A collection of all values for the property + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public IEnumerable GetAll(TLinkAddress link) + { + var property = _links.SearchOrDefault(link, _propertyMarker); + if (property == default) + { + yield break; + } + + var links = _links; + var constants = links.Constants; + var anyConstant = constants.Any; + var query = new Link(anyConstant, property, anyConstant); + + var values = new List(); + links.Each(candidate => + { + var candidateTarget = links.GetTarget(candidate); + var valueTarget = links.GetTarget(candidateTarget); + if (valueTarget == _propertyValueMarker) + { + values.Add(links.GetTarget(links.GetIndex(candidate))); + } + return constants.Continue; + }, query); + + foreach (var value in values) + { + yield return value; + } + } + + /// + /// + /// Gets the first value for the specified link property. + /// + /// + /// + /// + /// The link. + /// + /// + /// + /// The first value, or default if no values exist + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TLinkAddress GetFirst(TLinkAddress link) + { + foreach (var value in GetAll(link)) + { + return value; + } + return default; + } + + /// + /// + /// Adds a value to the specified link property. + /// + /// + /// + /// + /// The link. + /// + /// + /// + /// The value to add. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(TLinkAddress link, TLinkAddress value) + { + if (Contains(link, value)) + { + return; // Value already exists, no need to add + } + + var links = _links; + var property = links.GetOrCreate(link, _propertyMarker); + var valueContainer = links.GetOrCreate(_propertyValueMarker, value); + links.GetOrCreate(property, valueContainer); + } + + /// + /// + /// Removes a specific value from the specified link property. + /// + /// + /// + /// + /// The link. + /// + /// + /// + /// The value to remove. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Remove(TLinkAddress link, TLinkAddress value) + { + var property = _links.SearchOrDefault(link, _propertyMarker); + if (property == default) + { + return; + } + + var links = _links; + var constants = links.Constants; + var anyConstant = constants.Any; + var valueContainer = links.SearchOrDefault(_propertyValueMarker, value); + + if (valueContainer != default) + { + var propertyValueLink = links.SearchOrDefault(property, valueContainer); + if (propertyValueLink != default) + { + links.Delete(propertyValueLink); + } + } + } + + /// + /// + /// Sets all values for the specified link property, replacing any existing values. + /// + /// + /// + /// + /// The link. + /// + /// + /// + /// The values to set. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Set(TLinkAddress link, IEnumerable values) + { + Clear(link); + foreach (var value in values) + { + Add(link, value); + } + } + + /// + /// + /// Clears all values for the specified link property. + /// + /// + /// + /// + /// The link. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear(TLinkAddress link) + { + var property = _links.SearchOrDefault(link, _propertyMarker); + if (property == default) + { + return; + } + + var links = _links; + var constants = links.Constants; + var anyConstant = constants.Any; + var query = new Link(anyConstant, property, anyConstant); + + var linksToDelete = new List(); + links.Each(candidate => + { + var candidateTarget = links.GetTarget(candidate); + var valueTarget = links.GetTarget(candidateTarget); + if (valueTarget == _propertyValueMarker) + { + linksToDelete.Add(links.GetIndex(candidate)); + } + return constants.Continue; + }, query); + + foreach (var linkToDelete in linksToDelete) + { + links.Delete(linkToDelete); + } + } + + /// + /// + /// Checks if the specified link property contains the specified value. + /// + /// + /// + /// + /// The link. + /// + /// + /// + /// The value to check for. + /// + /// + /// + /// True if the property contains the value, false otherwise + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Contains(TLinkAddress link, TLinkAddress value) + { + var property = _links.SearchOrDefault(link, _propertyMarker); + if (property == default) + { + return false; + } + + var links = _links; + var valueContainer = links.SearchOrDefault(_propertyValueMarker, value); + if (valueContainer == default) + { + return false; + } + + return links.SearchOrDefault(property, valueContainer) != default; + } + + /// + /// + /// Gets the count of values for the specified link property. + /// + /// + /// + /// + /// The link. + /// + /// + /// + /// The number of values for the property + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Count(TLinkAddress link) + { + var count = 0; + foreach (var _ in GetAll(link)) + { + count++; + } + return count; + } + } +} \ No newline at end of file From 9a566fecec0e3def88ba64809d1db9ea288bf072 Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 07:57:45 +0300 Subject: [PATCH 3/4] '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/DebugMultipleValues.csproj | 24 +++++++++++ experiments/SimpleDebugTest.cs | 58 ++++++++++++++++++++++++++ experiments/debug_multiple_values.txt | 6 +++ 3 files changed, 88 insertions(+) create mode 100644 experiments/DebugMultipleValues.csproj create mode 100644 experiments/SimpleDebugTest.cs create mode 100644 experiments/debug_multiple_values.txt diff --git a/experiments/DebugMultipleValues.csproj b/experiments/DebugMultipleValues.csproj new file mode 100644 index 000000000..f1a9ded8b --- /dev/null +++ b/experiments/DebugMultipleValues.csproj @@ -0,0 +1,24 @@ + + + + net8 + true + latest + enable + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + \ No newline at end of file diff --git a/experiments/SimpleDebugTest.cs b/experiments/SimpleDebugTest.cs new file mode 100644 index 000000000..fe35a1965 --- /dev/null +++ b/experiments/SimpleDebugTest.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; +using System.Numerics; +using System.Linq; +using Platform.Data.Doublets.Decorators; +using Platform.Data.Doublets.PropertyOperators; +using Platform.Data.Doublets; +using Platform.Memory; +using Platform.Data.Doublets.Memory.United.Generic; +using Xunit; + +namespace DebugTest +{ + public static class SimpleDebugTest + { + [Fact] + public static void DebugMultipleValuesPropertiesOperator() + { + var links = new UnitedMemoryLinks(new HeapResizableDirectMemory()); + + var propertiesOperator = new MultipleValuesPropertiesOperator(links); + + var obj = links.Create(); + var property = links.Create(); + var value1 = links.Create(); + var value2 = links.Create(); + var value3 = links.Create(); + + Console.WriteLine($"Created: obj={obj}, property={property}, value1={value1}, value2={value2}, value3={value3}"); + + // Add values one by one and check count each time + propertiesOperator.AddValue(obj, property, value1); + Console.WriteLine($"After adding value1, count: {propertiesOperator.CountValues(obj, property)}"); + + propertiesOperator.AddValue(obj, property, value2); + Console.WriteLine($"After adding value2, count: {propertiesOperator.CountValues(obj, property)}"); + + propertiesOperator.AddValue(obj, property, value3); + Console.WriteLine($"After adding value3, count: {propertiesOperator.CountValues(obj, property)}"); + + // Test what values we actually have + var allValues = propertiesOperator.GetAllValues(obj, property).ToList(); + Console.WriteLine($"All values: [{string.Join(", ", allValues)}]"); + + // Test removing value2 + Console.WriteLine($"Before remove, contains value2: {propertiesOperator.ContainsValue(obj, property, value2)}"); + propertiesOperator.RemoveValue(obj, property, value2); + Console.WriteLine($"After remove, count: {propertiesOperator.CountValues(obj, property)}"); + Console.WriteLine($"After remove, contains value2: {propertiesOperator.ContainsValue(obj, property, value2)}"); + + // Test what values remain + var remainingValues = propertiesOperator.GetAllValues(obj, property).ToList(); + Console.WriteLine($"Remaining values: [{string.Join(", ", remainingValues)}]"); + + Assert.Equal(3, 3); // Placeholder to make it a valid test + } + } +} \ No newline at end of file diff --git a/experiments/debug_multiple_values.txt b/experiments/debug_multiple_values.txt new file mode 100644 index 000000000..c95ffb5bb --- /dev/null +++ b/experiments/debug_multiple_values.txt @@ -0,0 +1,6 @@ +Create. Before: (0->0). After: (1: 0->0) +Update. Before: (1: 0->0). After: (1: 18446744073709551612->18446744073709551612) +Create. Before: (0->0). After: (2: 0->0) +Update. Before: (2: 0->0). After: (2: 1->1) +Create. Before: (0->0). After: (3: 0->0) +Update. Before: (3: 0->0). After: (3: 2->1) From 4c354b81208d3d2a7d5c191958c7ed1ea77fb81b Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 07:57:47 +0300 Subject: [PATCH 4/4] 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 ead68b573..000000000 --- a/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -Issue to solve: https://github.com/linksplatform/Data.Doublets/issues/125 -Your prepared branch: issue-125-7f224c52 -Your prepared working directory: /tmp/gh-issue-solver-1757824498445 - -Proceed. \ No newline at end of file