Чтение одного байта из PipeReader - PullRequest
0 голосов
/ 10 апреля 2020

Как я могу улучшить этот метод для чтения одного байта из PipeReader? Я стремлюсь написать наиболее эффективный из возможных кодов, сохраняя при этом его удобочитаемостью и краткостью.

Как я могу: а) сделать его более эффективным (меньше циклов ЦП, меньше выделений) б) сделать его меньше verbose

/// <summary>
/// Reads a single byte from the given <paramref name="reader"/> and returns true if the byte is non-zero.
/// </summary>
public static async ValueTask<bool> ReadBool(this PipeReader reader) {
    var readResult = await reader.ReadAsync(default).ConfigureAwait(false);
    if (readResult.IsCanceled) throw new OperationCanceledException();
    var buffer = readResult.Buffer;
    if (buffer.Length == 0) throw new Exception("Buffer was empty.");
    var result = buffer.First.Span[0] == 0 ? false : true;
    reader.AdvanceTo(buffer.GetPosition(1));
    return result;
}

Одна из попыток, которые я предпринял, чтобы создать решение, которое работает быстрее всего при минимальных распределениях, заключалась в следующем, но это ужасно многословно и выглядит как огромная попытка просто прочитать один байт. Вы можете помочь сделать это лучше?

public static ValueTask<bool> ReadBool(this PipeReader reader) {

    var readTask = reader.ReadAsync(default);
    if (readTask.IsCompleted) {
        return new ValueTask<bool>(GetBool(reader, readTask.Result));
    }
    return ReadBoolAsync(reader, readTask);

    static async ValueTask<bool> ReadBoolAsync(PipeReader reader, ValueTask<ReadResult> readTask) {
        var readResult = await readTask.ConfigureAwait(false);
        return GetBool(reader, readResult);
    }

    static bool GetBool(PipeReader reader, ReadResult readResult) {
        if (readResult.IsCanceled) throw new OperationCanceledException();
        var buffer = readResult.Buffer;
        if (buffer.Length == 0) throw new IOException("Buffer was empty.");
        var result = buffer.First.Span[0] != 0;
        reader.AdvanceTo(buffer.GetPosition(1));
        return result;
    }
}
...