From f1296a628ce13595da85cca8cdb5b685d2af9b6e Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 12:55:38 +0300 Subject: [PATCH 1/3] Initial commit with task details for issue #10 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/10 --- 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..70d1219ac --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +Issue to solve: https://github.com/linksplatform/Data.Doublets/issues/10 +Your prepared branch: issue-10-dc9e2253 +Your prepared working directory: /tmp/gh-issue-solver-1757843647980 + +Proceed. \ No newline at end of file From 2c5a8745a747d5bf9d751835d13e9861316617a8 Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 13:08:25 +0300 Subject: [PATCH 2/3] Implement non-cached UnaryNumberToAddressAddOperationConverter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Created UnaryNumberToAddressAddOperationConverter class that creates links on-demand only - Implements power-of-two validation as mentioned in issue #10 line 55 - Provides non-cached alternative to the original cached converter - Includes comprehensive tests for basic conversion, unary one, power-of-two validation, and multiple types - All tests pass successfully 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- ...mberToAddressAddOperationConverterTests.cs | 127 +++++++++++++ ...aryNumberToAddressAddOperationConverter.cs | 179 ++++++++++++++++++ 2 files changed, 306 insertions(+) create mode 100644 csharp/Platform.Data.Doublets.Tests/UnaryNumberToAddressAddOperationConverterTests.cs create mode 100644 csharp/Platform.Data.Doublets/Converters/UnaryNumberToAddressAddOperationConverter.cs diff --git a/csharp/Platform.Data.Doublets.Tests/UnaryNumberToAddressAddOperationConverterTests.cs b/csharp/Platform.Data.Doublets.Tests/UnaryNumberToAddressAddOperationConverterTests.cs new file mode 100644 index 000000000..9d13f0424 --- /dev/null +++ b/csharp/Platform.Data.Doublets.Tests/UnaryNumberToAddressAddOperationConverterTests.cs @@ -0,0 +1,127 @@ +using System; +using System.IO; +using System.Numerics; +using Platform.Data.Doublets.Converters; +using Platform.Data.Doublets.Decorators; +using Platform.Data.Doublets.Memory.United.Generic; +using Platform.Memory; +using Xunit; + +namespace Platform.Data.Doublets.Tests +{ + public static class UnaryNumberToAddressAddOperationConverterTests + { + [Fact] + public static void BasicConversionTest() + { + Using(links => + { + var converter = new UnaryNumberToAddressAddOperationConverter(links); + + // Test null/default conversion + var result = converter.Convert(links.Constants.Null); + Assert.Equal(0UL, result); + }); + } + + [Fact] + public static void UnaryOneConversionTest() + { + Using(links => + { + var converter = new UnaryNumberToAddressAddOperationConverter(links); + + // Create unary "one" (self-referencing link) + var unaryOne = links.GetOrCreate(links.Constants.Itself, links.Constants.Itself); + var result = converter.Convert(unaryOne); + + Assert.Equal(1UL, result); + }); + } + + [Fact] + public static void PowerOfTwoValidationTest() + { + Using(links => + { + var converter = new UnaryNumberToAddressAddOperationConverter(links); + + // Create a more complex unary number structure that would trigger traversal + var unaryOne = links.GetOrCreate(links.Constants.Itself, links.Constants.Itself); + var two = links.GetOrCreate(unaryOne, unaryOne); + + // Create an invalid link structure where source != target + // and target is not a power of two (using an odd number) + var oddTarget = links.GetOrCreate(links.Constants.Itself, two); // Create link 3 + var invalidUnaryNumber = links.GetOrCreate(unaryOne, oddTarget); + + // This should throw an InvalidOperationException due to power-of-two check + Assert.Throws(() => converter.Convert(invalidUnaryNumber)); + }); + } + + [Fact] + public static void NonCachedBehaviorTest() + { + Using(links => + { + var converter = new UnaryNumberToAddressAddOperationConverter(links); + + // Verify that converter creates links on-demand + var initialCount = links.Count(); + + // Create unary "one" should create a new link + var unaryOne = links.GetOrCreate(links.Constants.Itself, links.Constants.Itself); + var result = converter.Convert(unaryOne); + + // Verify no additional links were pre-created by the converter itself + var finalCount = links.Count(); + + Assert.Equal(1UL, result); + // The count should only increase by the links we explicitly created + Assert.True(finalCount >= initialCount); + }); + } + + [Fact] + public static void MultipleTypeTest() + { + // Test with different numeric types + Using(links => + { + var converter = new UnaryNumberToAddressAddOperationConverter(links); + var result = converter.Convert(links.Constants.Null); + Assert.Equal((byte)0, result); + }); + + Using(links => + { + var converter = new UnaryNumberToAddressAddOperationConverter(links); + var result = converter.Convert(links.Constants.Null); + Assert.Equal((ushort)0, result); + }); + + Using(links => + { + var converter = new UnaryNumberToAddressAddOperationConverter(links); + var result = converter.Convert(links.Constants.Null); + Assert.Equal(0U, result); + }); + } + + private static void Using(Action> action) + where TLinkAddress : IUnsignedNumber, + IShiftOperators, + IBitwiseOperators, + IMinMaxValue, + IComparisonOperators + { + var unitedMemoryLinks = new UnitedMemoryLinks(new HeapResizableDirectMemory()); + using (var logFile = File.Open($"converterTest_{typeof(TLinkAddress).Name}.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/Converters/UnaryNumberToAddressAddOperationConverter.cs b/csharp/Platform.Data.Doublets/Converters/UnaryNumberToAddressAddOperationConverter.cs new file mode 100644 index 000000000..4be1bdc95 --- /dev/null +++ b/csharp/Platform.Data.Doublets/Converters/UnaryNumberToAddressAddOperationConverter.cs @@ -0,0 +1,179 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using Platform.Delegates; +using Platform.Numbers; +using Platform.Converters; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Platform.Data.Doublets.Converters; + +/// +/// +/// Represents a converter that transforms unary numbers to address add operations without caching. +/// This implementation creates links on-demand only, without precreation. +/// +/// +/// +/// +/// The link address type. +/// +/// +public class UnaryNumberToAddressAddOperationConverter : IConverter + where TLinkAddress : IUnsignedNumber, IComparisonOperators +{ + /// + /// + /// The links storage. + /// + /// + /// + protected readonly ILinks _links; + + /// + /// + /// The constants. + /// + /// + /// + protected readonly LinksConstants _constants; + + /// + /// + /// Initializes a new instance. + /// + /// + /// + /// + /// The links storage. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public UnaryNumberToAddressAddOperationConverter(ILinks links) + { + _links = links; + _constants = links.Constants; + } + + /// + /// + /// Converts a unary number to its address representation without using a cache. + /// Creates links on-demand only. + /// + /// + /// + /// + /// The unary number representation to convert. + /// + /// + /// + /// The address representation of the unary number. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TLinkAddress Convert(TLinkAddress unaryNumber) + { + // Handle null/default case + if (unaryNumber == _constants.Null) + { + return TLinkAddress.Zero; + } + + // Create the unary "one" (self-referencing link) on-demand + var unaryOne = _links.GetOrCreate(_constants.Itself, _constants.Itself); + if (unaryNumber == unaryOne) + { + return TLinkAddress.One; + } + + // Get the source and target of the unary number + var source = _links.GetSource(unaryNumber); + var target = _links.GetTarget(unaryNumber); + + // If source equals target, this is a simple power of two case + if (source == target) + { + // Calculate the power of two value on-demand instead of using cache + return CalculatePowerOfTwoValue(unaryNumber, unaryOne); + } + else + { + // More complex case: accumulate result by traversing the structure + var result = CalculatePowerOfTwoValue(source, unaryOne); + + // Traverse the target structure and accumulate values + while (target != unaryOne && target != _constants.Null) + { + // Check if target is a power of two (as mentioned in the issue) + if (!Platform.Numbers.Math.IsPowerOfTwo(ulong.CreateTruncating(target))) + { + throw new InvalidOperationException($"Target {target} is not a power of two."); + } + + source = _links.GetSource(target); + result = result + CalculatePowerOfTwoValue(source, unaryOne); + target = _links.GetTarget(target); + } + + return result; + } + } + + /// + /// + /// Calculates the power of two value for a unary number without using cache. + /// + /// + /// + /// + /// The unary number. + /// + /// + /// + /// The unary "one" value. + /// + /// + /// + /// The power of two value. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private TLinkAddress CalculatePowerOfTwoValue(TLinkAddress unary, TLinkAddress unaryOne) + { + if (unary == unaryOne) + { + return TLinkAddress.One; + } + + // Count the depth to determine the power of two + var depth = 0; + var current = unary; + + while (current != unaryOne && current != _constants.Null) + { + var source = _links.GetSource(current); + var target = _links.GetTarget(current); + + if (source == target) // This means it's a power-of-two link + { + depth++; + current = source; + } + else + { + break; + } + } + + // Calculate 2^depth + var result = TLinkAddress.One; + for (int i = 0; i < depth; i++) + { + result += result; // Double the value (multiply by 2) + } + + return result; + } + +} \ No newline at end of file From 648ea8fe8339842e917f1b71b356e4decfb0ac51 Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 13:09:28 +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 70d1219ac..000000000 --- a/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -Issue to solve: https://github.com/linksplatform/Data.Doublets/issues/10 -Your prepared branch: issue-10-dc9e2253 -Your prepared working directory: /tmp/gh-issue-solver-1757843647980 - -Proceed. \ No newline at end of file