Skip to content

Commit c096d29

Browse files
authored
Merge pull request #4 from pairbit/RedisValueSequence
Redis value sequence
1 parent 8f47bf6 commit c096d29

6 files changed

Lines changed: 321 additions & 6 deletions

File tree

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#if NET461 || NET472 || NETSTANDARD2_0
2+
using System;
3+
using System.Buffers;
4+
using System.Text;
5+
6+
namespace StackExchange.Redis;
7+
8+
internal static class EncodingExtensions
9+
{
10+
public static int GetChars(this Encoding encoding, in ReadOnlySequence<byte> bytes, Span<char> chars)
11+
{
12+
if (encoding == null) throw new ArgumentNullException(nameof(encoding));
13+
14+
if (bytes.IsSingleSegment)
15+
{
16+
return encoding.GetChars(bytes.First.Span, chars);
17+
}
18+
else
19+
{
20+
throw new NotImplementedException();
21+
}
22+
}
23+
}
24+
#endif

src/StackExchange.Redis/MessageWriter.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Buffers;
33
using System.Diagnostics;
44
using System.Runtime.CompilerServices;
@@ -102,6 +102,9 @@ internal static void WriteBulkString(in RedisValue value, IBufferWriter<byte> wr
102102
case RedisValue.StorageType.MemoryManager or RedisValue.StorageType.ByteArray:
103103
WriteUnifiedSpan(writer, value.RawSpan());
104104
break;
105+
case RedisValue.StorageType.Sequence:
106+
WriteUnifiedSequence(writer, value.RawSequence());
107+
break;
105108
default:
106109
throw new InvalidOperationException($"Unexpected {value.Type} value: '{value}'");
107110
}
@@ -571,6 +574,28 @@ private static void WriteUnifiedSpan(IBufferWriter<byte> writer, ReadOnlySpan<by
571574
}
572575
}
573576

577+
private static void WriteUnifiedSequence(IBufferWriter<byte> writer, in ReadOnlySequence<byte> value)
578+
{
579+
if (value.IsSingleSegment)
580+
{
581+
WriteUnifiedSpan(writer, value.First.Span);
582+
}
583+
else
584+
{
585+
var span = writer.GetSpan(3 + Format.MaxInt32TextLen);
586+
span[0] = (byte)'$';
587+
int bytes = WriteRaw(span, value.Length, offset: 1);
588+
writer.Advance(bytes);
589+
590+
foreach (var memory in value)
591+
{
592+
writer.Write(memory.Span);
593+
}
594+
595+
WriteCrlf(writer);
596+
}
597+
}
598+
574599
private static int AppendToSpan(Span<byte> span, ReadOnlySpan<byte> value, int offset = 0)
575600
{
576601
offset = WriteRaw(span, value.Length, offset: offset);

src/StackExchange.Redis/PublicAPI/PublicAPI.Unshipped.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ StackExchange.Redis.ConfigurationOptions.RequestBufferPool.set -> void
44
StackExchange.Redis.ConfigurationOptions.ResponseBufferPool.get -> System.Buffers.MemoryPool<byte>?
55
StackExchange.Redis.ConfigurationOptions.ResponseBufferPool.set -> void
66
static StackExchange.Redis.Lease<T>.Create(int length, System.Buffers.MemoryPool<T>? pool, bool clear = true) -> StackExchange.Redis.Lease<T>!
7+
static StackExchange.Redis.RedisValue.implicit operator StackExchange.Redis.RedisValue(System.Buffers.ReadOnlySequence<byte> value) -> StackExchange.Redis.RedisValue
8+
static StackExchange.Redis.RedisValue.implicit operator System.Buffers.ReadOnlySequence<byte>(StackExchange.Redis.RedisValue value) -> System.Buffers.ReadOnlySequence<byte>
9+
[SER002]static StackExchange.Redis.ValueCondition.CalculateDigest(in System.Buffers.ReadOnlySequence<byte> value) -> StackExchange.Redis.ValueCondition
710
[SER005]StackExchange.Redis.TestHarness
811
[SER005]StackExchange.Redis.TestHarness.BufferValidator
912
[SER005]StackExchange.Redis.TestHarness.ChannelPrefix.get -> StackExchange.Redis.RedisChannel
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
using System;
2+
using System.Buffers;
3+
using System.Diagnostics;
4+
5+
namespace StackExchange.Redis;
6+
7+
internal static class ReadOnlySequenceExtensions
8+
{
9+
public static bool StartsWith(this in ReadOnlySequence<byte> sequence, in ReadOnlySequence<byte> value)
10+
{
11+
throw new NotImplementedException();
12+
}
13+
14+
public static bool StartsWith(this in ReadOnlySequence<byte> sequence, ReadOnlySpan<byte> value)
15+
=> StartsWith(sequence, value, sequence.Start);
16+
17+
public static bool StartsWith(this in ReadOnlySequence<byte> sequence, ReadOnlySpan<byte> value, SequencePosition start)
18+
{
19+
var valueLength = value.Length;
20+
int valueLengthPart = 0;
21+
while (sequence.TryGet(ref start, out var memory))
22+
{
23+
var spanLength = memory.Length;
24+
if (spanLength == 0) continue;
25+
26+
var span = memory.Span;
27+
if (valueLengthPart > 0)
28+
{
29+
Debug.Assert(valueLength > valueLengthPart);
30+
31+
var remainder = valueLength - valueLengthPart;
32+
if (remainder > spanLength)
33+
{
34+
if (span.SequenceEqual(value.Slice(valueLengthPart, spanLength)))
35+
{
36+
valueLengthPart += spanLength;
37+
continue;
38+
}
39+
}
40+
else if (remainder == spanLength)
41+
{
42+
if (span.SequenceEqual(value.Slice(valueLengthPart)))
43+
{
44+
return true;
45+
}
46+
}
47+
else if (span.StartsWith(value.Slice(valueLengthPart)))
48+
{
49+
return true;
50+
}
51+
return false;
52+
}
53+
54+
if (spanLength >= valueLength)
55+
{
56+
return span.StartsWith(value);
57+
}
58+
59+
if (!value.Slice(0, spanLength).SequenceEqual(span))
60+
return false;
61+
62+
valueLengthPart = spanLength;
63+
}
64+
65+
return false;
66+
}
67+
68+
public static bool SequenceEqual(this in ReadOnlySequence<byte> first, ReadOnlySpan<byte> other)
69+
{
70+
if (first.IsSingleSegment) return first.First.Span.SequenceEqual(other);
71+
if (first.Length != other.Length) return false;
72+
73+
var position = first.Start;
74+
while (first.TryGet(ref position, out var memory))
75+
{
76+
var span = memory.Span;
77+
78+
if (!span.SequenceEqual(other.Slice(0, span.Length))) return false;
79+
80+
other = other.Slice(span.Length);
81+
}
82+
83+
return true;
84+
}
85+
86+
public static bool SequenceEqual(this in ReadOnlySequence<byte> first, in ReadOnlySequence<byte> other)
87+
{
88+
if (first.IsSingleSegment) return other.SequenceEqual(first.First.Span);
89+
if (other.IsSingleSegment) return first.SequenceEqual(other.First.Span);
90+
if (first.Length != other.Length) return false;
91+
92+
var firstPosition = first.Start;
93+
var otherPosition = other.Start;
94+
ReadOnlySpan<byte> firstSpan;
95+
ReadOnlySpan<byte> otherSpan = default;
96+
while (first.TryGet(ref firstPosition, out var firstMemory))
97+
{
98+
firstSpan = firstMemory.Span;
99+
if (firstSpan.Length == 0) continue;
100+
101+
if (otherSpan.Length > 0)
102+
{
103+
if (otherSpan.Length >= firstSpan.Length)
104+
{
105+
if (!firstSpan.SequenceEqual(otherSpan.Slice(0, firstSpan.Length))) return false;
106+
otherSpan = otherSpan.Slice(firstSpan.Length);
107+
continue;
108+
}
109+
110+
if (!firstSpan.Slice(0, otherSpan.Length).SequenceEqual(otherSpan)) return false;
111+
firstSpan = firstSpan.Slice(otherSpan.Length);
112+
}
113+
114+
while (other.TryGet(ref otherPosition, out var otherMemory))
115+
{
116+
otherSpan = otherMemory.Span;
117+
if (otherSpan.Length == 0) continue;
118+
119+
if (otherSpan.Length >= firstSpan.Length)
120+
{
121+
if (!firstSpan.SequenceEqual(otherSpan.Slice(0, firstSpan.Length))) return false;
122+
otherSpan = otherSpan.Slice(firstSpan.Length);
123+
break;
124+
}
125+
126+
if (!firstSpan.Slice(0, otherSpan.Length).SequenceEqual(otherSpan)) return false;
127+
firstSpan = firstSpan.Slice(otherSpan.Length);
128+
}
129+
}
130+
131+
return true;
132+
}
133+
134+
public static int SequenceCompareTo(this in ReadOnlySequence<byte> first, in ReadOnlySequence<byte> other)
135+
{
136+
throw new NotImplementedException();
137+
}
138+
}

0 commit comments

Comments
 (0)