我们可以使用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>
。
答案 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)