Skip to content

Commit c02ccac

Browse files
committed
Support nested lists of the value in process representation
Further expand support for lazy evaluation and materialization to reduce costs around short-lived compositions.
1 parent d34e572 commit c02ccac

File tree

3 files changed

+329
-116
lines changed

3 files changed

+329
-116
lines changed

implement/Pine.Core/Internal/PineValueInProcess.cs

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Pine.Core.PineVM;
33
using Pine.Core.PopularEncodings;
44
using System.Collections.Generic;
5+
using System.Linq;
56
using System.Numerics;
67

78
namespace Pine.Core.Internal;
@@ -30,12 +31,21 @@ public class PineValueInProcess
3031
/// <summary>
3132
/// Track a list without involving the general <see cref="PineValue.ListValue"/> system.
3233
/// </summary>
33-
private IReadOnlyList<PineValue>? _list;
34+
private IReadOnlyList<PineValueInProcess>? _list;
3435

36+
/// <summary>
37+
/// The value of the empty list, <see cref="PineValue.EmptyList"/>.
38+
/// </summary>
3539
public static readonly PineValueInProcess EmptyList = Create(PineValue.EmptyList);
3640

41+
/// <summary>
42+
/// The kernel boolean true value, <see cref="PineKernelValues.TrueValue"/>.
43+
/// </summary>
3744
public static readonly PineValueInProcess KernelTrueValue = Create(PineKernelValues.TrueValue);
3845

46+
/// <summary>
47+
/// The kernel boolean false value, <see cref="PineKernelValues.FalseValue"/>.
48+
/// </summary>
3949
public static readonly PineValueInProcess KernelFalseValue = Create(PineKernelValues.FalseValue);
4050

4151

@@ -81,7 +91,7 @@ public static PineValueInProcess Create(PineValue evaluated)
8191
/// This avoids computing aggregate derivations (hash codes, counts, etc.) until they are actually needed via <see cref="Evaluate"/>.
8292
/// </remarks>
8393
/// <returns>A new <see cref="PineValueInProcess"/> representing the list.</returns>
84-
public static PineValueInProcess CreateList(IReadOnlyList<PineValue> list)
94+
public static PineValueInProcess CreateList(IReadOnlyList<PineValueInProcess> list)
8595
{
8696
return new PineValueInProcess
8797
{
@@ -150,7 +160,7 @@ public PineValue Evaluate()
150160

151161
if (_list is not null)
152162
{
153-
_evaluated = PineValue.List([.. _list]);
163+
_evaluated = PineValue.List([.. _list.Select(item => item.Evaluate())]);
154164
return _evaluated;
155165
}
156166

@@ -396,27 +406,28 @@ public static PineValueInProcess ConcatBinary(
396406
/// </summary>
397407
/// <param name="index">The zero-based index of the element to retrieve.</param>
398408
/// <returns>
399-
/// For list values: the element at the specified index, or <see cref="PineValue.EmptyList"/> if index is out of bounds.
400-
/// For blob values: a single-byte blob containing the byte at the specified index, or <see cref="PineValue.EmptyBlob"/> if index is out of bounds.
409+
/// For list values: the element at the specified index, or <see cref="EmptyList"/> if index is out of bounds.
410+
/// For blob values: a single-byte blob containing the byte at the specified index, or <see cref="PineValueInProcess"/> wrapping <see cref="PineValue.EmptyBlob"/> if index is out of bounds.
401411
/// </returns>
402412
/// <remarks>
403-
/// This method is optimized to avoid fully evaluating the value when possible, especially for slice builders.
413+
/// This method is optimized to avoid fully evaluating the value when possible, especially for lists and slice builders.
414+
/// Returns a <see cref="PineValueInProcess"/> to defer evaluation until needed.
404415
/// </remarks>
405-
public PineValue GetElementAt(int index)
416+
public PineValueInProcess GetElementAt(int index)
406417
{
407418
index =
408419
index < 0 ? 0 : index;
409420

410421
if (_sliceBuilder is { } sliceBuilder)
411422
{
412-
return sliceBuilder.GetElementAt(index);
423+
return Create(sliceBuilder.GetElementAt(index));
413424
}
414425

415426
if (_list is { } list)
416427
{
417428
if (list.Count <= index)
418429
{
419-
return PineValue.EmptyList;
430+
return EmptyList;
420431
}
421432

422433
return list[index];
@@ -428,19 +439,19 @@ public PineValue GetElementAt(int index)
428439
{
429440
if (listValue.Items.Length <= index)
430441
{
431-
return PineValue.EmptyList;
442+
return EmptyList;
432443
}
433444

434-
return listValue.Items.Span[index];
445+
return Create(listValue.Items.Span[index]);
435446
}
436447

437448
if (evaluated is PineValue.BlobValue blobValue)
438449
{
439450
if (blobValue.Bytes.Length <= index)
440451
{
441-
return PineValue.EmptyBlob;
452+
return Create(PineValue.EmptyBlob);
442453
}
443-
return PineValue.BlobSingleByte(blobValue.Bytes.Span[index]);
454+
return Create(PineValue.BlobSingleByte(blobValue.Bytes.Span[index]));
444455
}
445456

446457
throw new System.InvalidOperationException(
@@ -573,6 +584,29 @@ public static bool AreEqual(PineValueInProcess inProcess, PineValue pineValue)
573584
return eval.Equals(pineValue);
574585
}
575586

587+
private static bool AreListItemsEqual(IReadOnlyList<PineValueInProcess> left, IReadOnlyList<PineValueInProcess> right)
588+
{
589+
if (ReferenceEquals(left, right))
590+
{
591+
return true;
592+
}
593+
594+
if (left.Count != right.Count)
595+
{
596+
return false;
597+
}
598+
599+
for (var i = 0; i < left.Count; i++)
600+
{
601+
if (!AreEqual(left[i], right[i]))
602+
{
603+
return false;
604+
}
605+
}
606+
607+
return true;
608+
}
609+
576610
private static bool AreListItemsEqual(IReadOnlyList<PineValue> left, IReadOnlyList<PineValue> right)
577611
{
578612
if (ReferenceEquals(left, right))
@@ -596,7 +630,7 @@ private static bool AreListItemsEqual(IReadOnlyList<PineValue> left, IReadOnlyLi
596630
return true;
597631
}
598632

599-
private static bool AreListItemsEqual(IReadOnlyList<PineValue> left, PineValue.ListValue right)
633+
private static bool AreListItemsEqual(IReadOnlyList<PineValueInProcess> left, PineValue.ListValue right)
600634
{
601635
var rightSpan = right.Items.Span;
602636

@@ -607,7 +641,7 @@ private static bool AreListItemsEqual(IReadOnlyList<PineValue> left, PineValue.L
607641

608642
for (var i = 0; i < rightSpan.Length; i++)
609643
{
610-
if (!left[i].Equals(rightSpan[i]))
644+
if (!AreEqual(left[i], rightSpan[i]))
611645
{
612646
return false;
613647
}
@@ -627,7 +661,7 @@ private static bool AreListItemsEqual(IReadOnlyList<PineValue> left, PineValue.L
627661

628662
var first = root.GetElementAt(path[0]);
629663

630-
return PineValueExtension.ValueFromPathOrNull(first, path[1..]);
664+
return PineValueExtension.ValueFromPathOrNull(first.Evaluate(), path[1..]);
631665
}
632666

633667
/// <summary>

0 commit comments

Comments
 (0)