如何将Memory <t>转换为另一个

时间:2019-02-04 06:52:10

标签: c#

我们可以使用MemoryMarshal.Cast方法重载将local lpeg = require 'lpeg' lpeg.locale(lpeg) local function is_at_beginning(_, pos) return pos == 1 end function find_reduplicated_word(str, word) local type, _ENV = type, math local B, C, Cmt, P, V = lpeg.B, lpeg.C, lpeg.Cmt, lpeg.P, lpeg.V local non_word = lpeg.space + lpeg.punct local patt = P { (V 'repeated' + 1)^1, repeated = (B(non_word) + Cmt(true, is_at_beginning)) * C(P(word)^1) * #(non_word + P(-1)) } return type(patt:match(str)) == 'string' end for _, test in ipairs { { 'tvtv', true }, { ' tvtv', true }, { ' !tv', true }, { 'atv', false }, { 'tva', false }, { 'gun tv', true }, { '!tv', true }, } do local str, expected = table.unpack(test) local result = find_reduplicated_word(str, 'tv') if result ~= expected then print(result) print(('"%s" should%s match but did%s') :format(str, expected and "" or "n't", expected and "n't" or "")) end end Span<T>转换为另一个。喜欢:

ReadOnlySpan<T>

但是有什么方法可以将Span<byte> span = stackalloc byte[4]; var singleIntSpan = MemoryMarshal.Cast<byte, int>(span); 投射到另一个?例如将Memory<T>强制转换为Memory<byte>

2 个答案:

答案 0 :(得分:6)

您不能直接 这样做;但是,如果您确实需要,则可以创建自定义MemoryManager<T>(大概是一个MyMemoryManager<TFrom, TTo> : MemoryManager<TTo>,它作为GetSpan()覆盖的一部分执行转换。这是有点不平凡,并且需要另一种分配-与Span<T>强制转换不同,后者是无分配的。

如果您需要一个具体的例子,我可以举个例子(实际上我已经在一些现有代码中做到了这一点),但是:老实说,您可能想重新考虑这种情况。

编辑:类似以下内容:

using System;
using System.Buffers;
using System.Runtime.InteropServices;

class Program
{
    static void Main()
    {
        Memory<byte> bytes = new byte[1024];

        Memory<ushort> typed = Utils.Cast<byte, ushort>(bytes);
        Console.WriteLine(typed.Length); // 512

        // note CPU endianness matters re the layout
        typed.Span[0] = 0x5432;
        Console.WriteLine(bytes.Span[0]); // 50 = 0x32
        Console.WriteLine(bytes.Span[1]); // 84 = 0x54
    }
}

static class Utils
{
    public static Memory<TTo> Cast<TFrom, TTo>(Memory<TFrom> from)
        where TFrom : unmanaged
        where TTo : unmanaged
    {
        // avoid the extra allocation/indirection, at the cost of a gen-0 box
        if (typeof(TFrom) == typeof(TTo)) return (Memory<TTo>)(object)from;

        return new CastMemoryManager<TFrom, TTo>(from).Memory;
    }
    private sealed class CastMemoryManager<TFrom, TTo> : MemoryManager<TTo>
        where TFrom : unmanaged
        where TTo : unmanaged
    {
        private readonly Memory<TFrom> _from;

        public CastMemoryManager(Memory<TFrom> from) => _from = from;

        public override Span<TTo> GetSpan()
            => MemoryMarshal.Cast<TFrom, TTo>(_from.Span);

        protected override void Dispose(bool disposing) { }
        public override MemoryHandle Pin(int elementIndex = 0)
            => throw new NotSupportedException();
        public override void Unpin()
            => throw new NotSupportedException();
    }
}

如果您确实想支持固定/取消固定,则应该可以-您只需要计算竞争TFrom / TTo的相对范围和偏移量-大概使用{ {1}}等,并使用Unsafe.SizeOf<T>获取基础的内存管理器(如果使用-请注意,裸数组没有内存管理器)。除非您要广泛测试该选项,否则抛出错误可能比弄错它更安全。

答案 1 :(得分:2)

我认为您不能,但是我想您可以从中返回一个跨度,尽管我怀疑这会有所帮助

Memory.Span Property

  

返回当前实例的跨度。

angular
相关问题