Commit 1a51bc11 authored by Marc Gravell's avatar Marc Gravell

add TypedRedisValue - works a lot like RedisResult, but: value-typed; helps perf a lot

parent 40c5d21d
...@@ -110,7 +110,8 @@ protected override long Llen(int database, RedisKey key) ...@@ -110,7 +110,8 @@ protected override long Llen(int database, RedisKey key)
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
static void ThrowArgumentOutOfRangeException() => throw new ArgumentOutOfRangeException(); static void ThrowArgumentOutOfRangeException() => throw new ArgumentOutOfRangeException();
protected override void LRange(int database, RedisKey key, long start, RedisValue[] arr)
protected override void LRange(int database, RedisKey key, long start, Span<TypedRedisValue> arr)
{ {
var stack = GetStack(key, false); var stack = GetStack(key, false);
...@@ -123,7 +124,7 @@ protected override void LRange(int database, RedisKey key, long start, RedisValu ...@@ -123,7 +124,7 @@ protected override void LRange(int database, RedisKey key, long start, RedisValu
for (int i = 0; i < arr.Length; i++) for (int i = 0; i < arr.Length; i++)
{ {
if (!iter.MoveNext()) ThrowArgumentOutOfRangeException(); if (!iter.MoveNext()) ThrowArgumentOutOfRangeException();
arr[i] = iter.Current; arr[i] = TypedRedisValue.BulkString(iter.Current);
} }
} }
} }
......
...@@ -14,16 +14,13 @@ namespace StackExchange.Redis.Server ...@@ -14,16 +14,13 @@ namespace StackExchange.Redis.Server
public override string ToString() => Command; public override string ToString() => Command;
public override bool Equals(object obj) => throw new NotSupportedException(); public override bool Equals(object obj) => throw new NotSupportedException();
public RedisResult WrongArgCount() => RedisResult.Create($"ERR wrong number of arguments for '{Command}' command", ResultType.Error); public TypedRedisValue WrongArgCount() => TypedRedisValue.Error($"ERR wrong number of arguments for '{Command}' command");
public RedisResult UnknownSubcommandOrArgumentCount() => RedisResult.Create($"ERR Unknown subcommand or wrong number of arguments for '{Command}'.", ResultType.Error); public TypedRedisValue UnknownSubcommandOrArgumentCount() => TypedRedisValue.Error($"ERR Unknown subcommand or wrong number of arguments for '{Command}'.");
public string GetString(int index) public string GetString(int index)
=> _inner[index].GetString(); => _inner[index].GetString();
internal RedisResult GetResult(int index)
=> RedisResult.Create(_inner[index].AsRedisValue());
public bool IsString(int index, string value) // TODO: optimize public bool IsString(int index, string value) // TODO: optimize
=> string.Equals(value, _inner[index].GetString(), StringComparison.OrdinalIgnoreCase); => string.Equals(value, _inner[index].GetString(), StringComparison.OrdinalIgnoreCase);
......
This diff is collapsed.
This diff is collapsed.
using System;
using System.Buffers;
namespace StackExchange.Redis
{
/// <summary>
/// A RedisValue with an eplicit encoding type, which could represent an array of items
/// </summary>
public readonly struct TypedRedisValue
{
internal static TypedRedisValue Rent(int count)
=> new TypedRedisValue(ArrayPool<TypedRedisValue>.Shared.Rent(count), count);
/// <summary>
/// An invalid empty value that has no type
/// </summary>
public static TypedRedisValue Nil => default;
/// <summary>
/// Returns whether this value is an invalid empty value
/// </summary>
public bool IsNil => Type == ResultType.None;
/// <summary>
/// Returns whether this value represents a null array
/// </summary>
public bool IsNullArray => Type == ResultType.MultiBulk && _oversizedItems == null;
/// <summary>
/// The type of value being represented
/// </summary>
public ResultType Type { get; }
private readonly RedisValue _value;
private readonly TypedRedisValue[] _oversizedItems;
/// <summary>
/// Gets items from an array by index
/// </summary>
public TypedRedisValue this[int index]
{
get => _oversizedItems[index];
internal set => _oversizedItems[index] = value;
}
/// <summary>
/// Gets the length of the value as an array
/// </summary>
public int Length { get; }
/// <summary>
/// Initialize a TypedRedisValue from a value and optionally a type
/// </summary>
private TypedRedisValue(RedisValue value, ResultType? type = null)
{
Type = type ?? (value.IsInteger ? ResultType.Integer : ResultType.BulkString);
_value = value;
Length = default;
_oversizedItems = default;
}
/// <summary>
/// Initialize a TypedRedisValue that represents an error
/// </summary>
public static TypedRedisValue Error(string value)
=> new TypedRedisValue(value, ResultType.Error);
/// <summary>
/// Initialize a TypedRedisValue that represents a simple string
/// </summary>
public static TypedRedisValue SimpleString(string value)
=> new TypedRedisValue(value, ResultType.SimpleString);
/// <summary>
/// The simple string OK
/// </summary>
public static TypedRedisValue OK { get; } = SimpleString("OK");
internal static TypedRedisValue Zero { get; } = Integer(0);
internal static TypedRedisValue One { get; } = Integer(1);
internal static TypedRedisValue NullArray { get; } = MultiBulk(null);
internal static TypedRedisValue EmptyArray { get; } = MultiBulk(Array.Empty<TypedRedisValue>());
/// <summary>
/// Gets the array elements as a span
/// </summary>
public ReadOnlySpan<TypedRedisValue> Span => new ReadOnlySpan<TypedRedisValue>(_oversizedItems, 0, Length);
internal Span<TypedRedisValue> MutableSpan => new Span<TypedRedisValue>(_oversizedItems, 0, Length);
/// <summary>
/// Initialize a TypedRedisValue that represents an integer
/// </summary>
public static TypedRedisValue Integer(long value)
=> new TypedRedisValue(value, ResultType.Integer);
/// <summary>
/// Initialize a TypedRedisValue from an array
/// </summary>
public static TypedRedisValue MultiBulk(TypedRedisValue[] items)
=> new TypedRedisValue(items, items == null ? 0 : items.Length);
/// <summary>
/// Initialize a TypedRedisValue from an oversized array
/// </summary>
public static TypedRedisValue MultiBulk(TypedRedisValue[] oversizedItems, int count)
=> new TypedRedisValue(oversizedItems, count);
/// <summary>
/// Initialize a TypedRedisValue that represents a bulk string
/// </summary>
public static TypedRedisValue BulkString(RedisValue value)
=> new TypedRedisValue(value, ResultType.BulkString);
private TypedRedisValue(TypedRedisValue[] oversizedItems, int count)
{
if (oversizedItems == null)
{
if (count != 0) throw new ArgumentOutOfRangeException(nameof(count));
}
else
{
if (count < 0 || count > oversizedItems.Length) throw new ArgumentOutOfRangeException(nameof(count));
if (count == 0) oversizedItems = Array.Empty<TypedRedisValue>();
}
_value = default;
Type = ResultType.MultiBulk;
Length = count;
_oversizedItems = oversizedItems;
}
internal void Recycle(int limit = -1)
{
var arr = _oversizedItems;
if (arr != null)
{
if (limit < 0) limit = Length;
for (int i = 0; i < limit; i++)
{
arr[i].Recycle();
}
ArrayPool<TypedRedisValue>.Shared.Return(arr, clearArray: false);
}
}
/// <summary>
/// Get the underlying value assuming that it is a valid type with a meaningful value
/// </summary>
internal RedisValue AsRedisValue() => _value;
/// <summary>
/// Obtain the value as a string
/// </summary>
public override string ToString()
{
switch (Type)
{
case ResultType.BulkString:
case ResultType.SimpleString:
case ResultType.Integer:
case ResultType.Error:
return $"{Type}:{_value}";
case ResultType.MultiBulk:
return $"{Type}:[{Length}]";
default:
return Type.ToString();
}
}
/// <summary>
/// Not supported
/// </summary>
public override int GetHashCode() => throw new NotSupportedException();
/// <summary>
/// Not supported
/// </summary>
public override bool Equals(object obj) => throw new NotSupportedException();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment