Skip to content

Commit

Permalink
使用MemoryBufferWriter优化AddQuery(string,string)方法
Browse files Browse the repository at this point in the history
  • Loading branch information
xljiulang committed Jan 17, 2021
1 parent 1971eaf commit b14e6d7
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 16 deletions.
6 changes: 3 additions & 3 deletions App/Clients/IUserApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace App.Clients
public interface IUserApi : IHttpApi
{
[HttpGet("api/users/{account}")]
ITask<HttpResponseMessage> GetAsync([Required] string account);
ITask<HttpResponseMessage> GetAsync([Required] string account, string a = "我");

[HttpGet("api/users/{account}")]
ITask<string> GetAsStringAsync([Required] string account, CancellationToken token = default);
Expand All @@ -30,15 +30,15 @@ public interface IUserApi : IHttpApi


[HttpGet("api/users/{account}")]
[XmlReturn]
[XmlReturn]
ITask<string> GetExpectXmlAsync([Required] string account, CancellationToken token = default);



[HttpGet("api/users/{account}")]
ITask<byte[]> GetAsByteArrayAsync([Required] string account, CancellationToken token = default);

[HttpGet("api/users/{account}")]
[HttpGet("api/users/{account}")]
ITask<Stream> GetAsStreamAsync([Required] string account, CancellationToken token = default);

[HttpGet("api/users/{account}")]
Expand Down
101 changes: 101 additions & 0 deletions WebApiClientCore/BuildinBuffers/MemoryBufferWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using System;
using System.Buffers;
using System.Diagnostics;

namespace WebApiClientCore
{
/// <summary>
/// 将Memory包装为BufferWriter
/// </summary>
/// <typeparam name="T"></typeparam>
[DebuggerDisplay("WrittenCount = {WrittenCount}")]
sealed class MemoryBufferWriter<T> : IBufferWriter<T>
{
private int index;
private Memory<T> memory;

/// <summary>
/// 获取已数入的数据长度
/// </summary>
public int WrittenCount => this.index;

/// <summary>
/// 获取剩余容量
/// </summary>
public int FreeCapacity => this.memory.Length;

/// <summary>
/// Memory包装为BufferWriter
/// </summary>
/// <param name="memory"></param>
public MemoryBufferWriter(Memory<T> memory)
{
this.index = 0;
this.memory = memory;
}

/// <summary>
/// 设置向前推进
/// </summary>
/// <param name="count"></param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public void Advance(int count)
{
if (count < 0 || count > this.memory.Length)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
this.memory = this.memory.Slice(count);
this.index += count;
}

/// <summary>
/// 返回用于写入数据的Span
/// </summary>
/// <param name="sizeHint">意图大小</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
/// <returns></returns>
public Span<T> GetSpan(int sizeHint = 0)
{
return this.GetMemory(sizeHint).Span;
}

/// <summary>
/// 返回用于写入数据的Memory
/// </summary>
/// <param name="sizeHint">意图大小</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
/// <returns></returns>
public Memory<T> GetMemory(int sizeHint = 0)
{
if (sizeHint > this.memory.Length)
{
throw new ArgumentOutOfRangeException(nameof(sizeHint));
}
return this.memory;
}

/// <summary>
/// 写入数据
/// </summary>
/// <param name="value"></param>
public void Write(T value)
{
this.GetSpan(1)[0] = value;
this.Advance(1);
}

/// <summary>
/// 写入数据
/// </summary>
/// <param name="value">值</param>
public void Write(ReadOnlySpan<T> value)
{
if (value.IsEmpty == false)
{
value.CopyTo(this.GetSpan(value.Length));
this.Advance(value.Length);
}
}
}
}
25 changes: 12 additions & 13 deletions WebApiClientCore/BuildinUtils/UriEditor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics;

namespace WebApiClientCore
{
Expand Down Expand Up @@ -62,27 +63,25 @@ public bool Replace(string name, string? value)
/// <param name="value">参数的值</param>
public void AddQuery(string name, string? value)
{
name = Uri.EscapeDataString(name);
if (!string.IsNullOrEmpty(value))
{
value = Uri.EscapeDataString(value);
}

var uriSpan = this.Uri.OriginalString.AsSpan();
var fragmentSpan = this.Uri.Fragment.AsSpan();
uriSpan = uriSpan.Slice(0, uriSpan.Length - fragmentSpan.Length).TrimEnd('?').TrimEnd('&');
var baseSpan = uriSpan.Slice(0, uriSpan.Length - fragmentSpan.Length).TrimEnd('?').TrimEnd('&');
var concat = uriSpan.IndexOf('?') < 0 ? '?' : '&';
var nameSpan = Uri.EscapeDataString(name);
var valueSpan = string.IsNullOrEmpty(value) ? ReadOnlySpan<char>.Empty : Uri.EscapeDataString(value).AsSpan();

var writer = new ResizableBufferWriter<char>(256);
writer.Write(uriSpan);
var length = baseSpan.Length + 1 + nameSpan.Length + 1 + valueSpan.Length + fragmentSpan.Length;
var array = new char[length];
var writer = new MemoryBufferWriter<char>(array);
writer.Write(baseSpan);
writer.Write(concat);
writer.Write(name);
writer.Write(nameSpan);
writer.Write('=');
writer.Write(value);
writer.Write(valueSpan);
writer.Write(fragmentSpan);

var uri = writer.WrittenSpan.ToString();
this.Uri = new Uri(uri);
Debug.Assert(writer.WrittenCount == array.Length);
this.Uri = new Uri(new string(array));
}

/// <summary>
Expand Down

0 comments on commit b14e6d7

Please sign in to comment.