Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions csharp/Platform.Data.Doublets/ILinkTree.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Numerics;

#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member

namespace Platform.Data.Doublets
{
/// <summary>
/// <para>
/// Defines a tree-like interface for representing links in hierarchical structure
/// instead of flat IList&lt;TLinkAddress&gt; representation.
/// </para>
/// </summary>
/// <typeparam name="TLinkAddress">The type of the link address.</typeparam>
public interface ILinkTree<TLinkAddress> where TLinkAddress : IUnsignedNumber<TLinkAddress>
{
/// <summary>
/// Gets the index (identifier) of this link.
/// </summary>
TLinkAddress Index { get; }

/// <summary>
/// Gets the source of this link.
/// </summary>
TLinkAddress Source { get; }

/// <summary>
/// Gets the target of this link.
/// </summary>
TLinkAddress Target { get; }

/// <summary>
/// Gets the parent link in the tree structure, if any.
/// </summary>
ILinkTree<TLinkAddress>? Parent { get; }

/// <summary>
/// Gets the children of this link in the tree structure.
/// </summary>
IEnumerable<ILinkTree<TLinkAddress>> Children { get; }

/// <summary>
/// Gets the number of children in this tree node.
/// </summary>
int ChildrenCount { get; }

/// <summary>
/// Gets the child at the specified index.
/// </summary>
/// <param name="index">The zero-based index of the child.</param>
/// <returns>The child at the specified index, or null if index is out of range.</returns>
ILinkTree<TLinkAddress>? GetChild(int index);

/// <summary>
/// Gets the source as a tree node, if it represents a link.
/// </summary>
/// <returns>The source as a tree node, or null if source is not a link.</returns>
ILinkTree<TLinkAddress>? GetSourceAsTree();

/// <summary>
/// Gets the target as a tree node, if it represents a link.
/// </summary>
/// <returns>The target as a tree node, or null if target is not a link.</returns>
ILinkTree<TLinkAddress>? GetTargetAsTree();

/// <summary>
/// Determines whether this tree represents a null/empty link.
/// </summary>
/// <returns>True if this is a null link, false otherwise.</returns>
bool IsNull();

/// <summary>
/// Converts this tree structure to a flat array representation for compatibility.
/// </summary>
/// <returns>An array containing [Index, Source, Target].</returns>
TLinkAddress[] ToArray();
}
}
120 changes: 120 additions & 0 deletions csharp/Platform.Data.Doublets/ILinksExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1599,5 +1599,125 @@ public static void ClearGarbage<TLinkAddress>(this ILinks<TLinkAddress> links, T
}

#endregion

#region Tree-Compatible Extensions

/// <summary>
/// Gets a single link matching the tree query, or null if none or multiple links exist.
/// </summary>
/// <param name="links">The links storage.</param>
/// <param name="query">The tree query to search for.</param>
/// <returns>A single matching link as a tree, or null.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ILinkTree<TLinkAddress>? SingleOrDefaultTree<TLinkAddress>(this ILinks<TLinkAddress> links, ILinkTree<TLinkAddress>? query) where TLinkAddress : IUnsignedNumber<TLinkAddress>
{
// Convert tree query to list format for compatibility with existing infrastructure
var listQuery = query?.ToArray();
var result = links.SingleOrDefault(listQuery);
return result != null ? new LinkTree<TLinkAddress>(result) : null;
}

/// <summary>
/// Gets the index (identifier) of a tree-structured link.
/// </summary>
/// <param name="links">The links storage.</param>
/// <param name="tree">The tree-structured link.</param>
/// <returns>The index of the link.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TLinkAddress GetTreeIndex<TLinkAddress>(this ILinks<TLinkAddress> links, ILinkTree<TLinkAddress>? tree) where TLinkAddress : IUnsignedNumber<TLinkAddress>
{
return tree != null ? tree.Index : links.Constants.Null;
}

/// <summary>
/// Gets the source of a tree-structured link.
/// </summary>
/// <param name="links">The links storage.</param>
/// <param name="tree">The tree-structured link.</param>
/// <returns>The source of the link.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TLinkAddress GetTreeSource<TLinkAddress>(this ILinks<TLinkAddress> links, ILinkTree<TLinkAddress>? tree) where TLinkAddress : IUnsignedNumber<TLinkAddress>
{
return tree != null ? tree.Source : links.Constants.Null;
}

/// <summary>
/// Gets the target of a tree-structured link.
/// </summary>
/// <param name="links">The links storage.</param>
/// <param name="tree">The tree-structured link.</param>
/// <returns>The target of the link.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TLinkAddress GetTreeTarget<TLinkAddress>(this ILinks<TLinkAddress> links, ILinkTree<TLinkAddress>? tree) where TLinkAddress : IUnsignedNumber<TLinkAddress>
{
return tree != null ? tree.Target : links.Constants.Null;
}

/// <summary>
/// Gets all links matching the tree query.
/// </summary>
/// <param name="links">The links storage.</param>
/// <param name="restriction">The tree-based restriction to search for.</param>
/// <returns>All matching links as trees.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IList<ILinkTree<TLinkAddress>?> AllTrees<TLinkAddress>(this ILinks<TLinkAddress> links, ILinkTree<TLinkAddress>? restriction) where TLinkAddress : IUnsignedNumber<TLinkAddress>
{
var listRestriction = restriction?.ToArray();
var results = links.All(listRestriction);
return results.Select(list => list != null ? (ILinkTree<TLinkAddress>?)new LinkTree<TLinkAddress>(list) : null).ToList();
}

/// <summary>
/// Ensures a link exists based on tree structure restriction.
/// </summary>
/// <param name="links">The links storage.</param>
/// <param name="restriction">The tree-structured restriction.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void EnsureTreeLinkExists<TLinkAddress>(this ILinks<TLinkAddress> links, ILinkTree<TLinkAddress>? restriction) where TLinkAddress : IUnsignedNumber<TLinkAddress>
{
var listRestriction = restriction?.ToArray();
links.EnsureLinkExists(listRestriction);
}

/// <summary>
/// Formats a tree-structured link for display.
/// </summary>
/// <param name="links">The links storage.</param>
/// <param name="tree">The tree-structured link.</param>
/// <returns>A formatted string representation of the link.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string FormatTree<TLinkAddress>(this ILinks<TLinkAddress> links, ILinkTree<TLinkAddress>? tree) where TLinkAddress : IUnsignedNumber<TLinkAddress>
{
if (tree == null) return "null";
var listRepresentation = tree.ToArray();
return links.Format(listRepresentation);
}

/// <summary>
/// Converts a list-based link to tree structure.
/// </summary>
/// <param name="links">The links storage.</param>
/// <param name="list">The list-based link.</param>
/// <returns>The tree-structured representation.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ILinkTree<TLinkAddress>? AsTree<TLinkAddress>(this ILinks<TLinkAddress> links, IList<TLinkAddress>? list) where TLinkAddress : IUnsignedNumber<TLinkAddress>
{
return list != null ? new LinkTree<TLinkAddress>(list) : null;
}

/// <summary>
/// Converts a tree-structured link to list format for backward compatibility.
/// </summary>
/// <param name="links">The links storage.</param>
/// <param name="tree">The tree-structured link.</param>
/// <returns>The list representation.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IList<TLinkAddress>? AsList<TLinkAddress>(this ILinks<TLinkAddress> links, ILinkTree<TLinkAddress>? tree) where TLinkAddress : IUnsignedNumber<TLinkAddress>
{
return tree?.ToArray();
}

#endregion

}
}
98 changes: 97 additions & 1 deletion csharp/Platform.Data.Doublets/Link.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Platform.Data.Doublets
/// <summary>
/// Структура описывающая уникальную связь.
/// </summary>
public struct Link<TLinkAddress> : IEquatable<Link<TLinkAddress>>, IReadOnlyList<TLinkAddress>, IList<TLinkAddress> where TLinkAddress : IUnsignedNumber<TLinkAddress>
public struct Link<TLinkAddress> : IEquatable<Link<TLinkAddress>>, IReadOnlyList<TLinkAddress>, IList<TLinkAddress>, ILinkTree<TLinkAddress> where TLinkAddress : IUnsignedNumber<TLinkAddress>
{
/// <summary>
/// <para>
Expand Down Expand Up @@ -96,6 +96,12 @@ public Link(object other)
{
SetValues(ref otherLink, out Index, out Source, out Target);
}
else if(other is ILinkTree<TLinkAddress> otherTree)
{
Index = otherTree.Index;
Source = otherTree.Source;
Target = otherTree.Target;
}
else if(other is IList<TLinkAddress> otherList)
{
SetValues(otherList, out Index, out Source, out Target);
Expand Down Expand Up @@ -144,6 +150,33 @@ public Link(TLinkAddress index, TLinkAddress source, TLinkAddress target)
Source = source;
Target = target;
}

/// <summary>
/// <para>
/// Initializes a new <see cref="Link"/> instance from a tree structure.
/// </para>
/// <para></para>
/// </summary>
/// <param name="tree">
/// <para>A tree structure.</para>
/// <para></para>
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Link(ILinkTree<TLinkAddress>? tree)
{
if (tree == null)
{
Index = default;
Source = default;
Target = default;
}
else
{
Index = tree.Index;
Source = tree.Source;
Target = tree.Target;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void SetValues(ref Link<TLinkAddress> other, out TLinkAddress index, out TLinkAddress source, out TLinkAddress target)
{
Expand Down Expand Up @@ -559,5 +592,68 @@ public int IndexOf(TLinkAddress item)
public static bool operator !=(Link<TLinkAddress> left, Link<TLinkAddress> right) { return !(left == right);}

#endregion

#region ILinkTree

/// <summary>
/// Gets the index (identifier) of this link.
/// </summary>
TLinkAddress ILinkTree<TLinkAddress>.Index => Index;

/// <summary>
/// Gets the source of this link.
/// </summary>
TLinkAddress ILinkTree<TLinkAddress>.Source => Source;

/// <summary>
/// Gets the target of this link.
/// </summary>
TLinkAddress ILinkTree<TLinkAddress>.Target => Target;

/// <summary>
/// Gets the parent link in the tree structure (always null for Link struct).
/// </summary>
public ILinkTree<TLinkAddress>? Parent => null;

/// <summary>
/// Gets the children of this link in the tree structure (always empty for Link struct).
/// </summary>
public IEnumerable<ILinkTree<TLinkAddress>> Children => System.Linq.Enumerable.Empty<ILinkTree<TLinkAddress>>();

/// <summary>
/// Gets the number of children in this tree node (always 0 for Link struct).
/// </summary>
public int ChildrenCount => 0;

/// <summary>
/// Gets the child at the specified index (always returns null for Link struct).
/// </summary>
/// <param name="index">The zero-based index of the child.</param>
/// <returns>Always null for Link struct.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ILinkTree<TLinkAddress>? GetChild(int index) => null;

/// <summary>
/// Gets the source as a tree node, if it represents a link (returns null for primitive values).
/// </summary>
/// <returns>Null, indicating source is a primitive value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ILinkTree<TLinkAddress>? GetSourceAsTree() => null;

/// <summary>
/// Gets the target as a tree node, if it represents a link (returns null for primitive values).
/// </summary>
/// <returns>Null, indicating target is a primitive value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ILinkTree<TLinkAddress>? GetTargetAsTree() => null;

/// <summary>
/// Converts this tree structure to a flat array representation for compatibility.
/// </summary>
/// <returns>An array containing [Index, Source, Target].</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TLinkAddress[] ToArray() => new[] { Index, Source, Target };

#endregion
}
}
Loading
Loading