4 ms·
So they added Span<T> as a big thing ... > (Span<T> is) at the heart of most performance-related improvements in .NET Core 2.1. Since it allows managing buffer
by c-smile 8y ago
So they added Span<T> as a big thing ...
> (Span<T> is) at the heart of most performance-related improvements in .NET Core 2.1. Since it allows managing buffers in a more efficient way, it can help in reducing allocations and copying. We consider Span to be a very fundamental type as it requires runtime and compiler support in order to be fully leveraged.
Small struct that is declared as
public readonly ref struct Span<T>
{
private readonly ref T _pointer;
private readonly int _length;
...
}
which is exactly what I am using in Sciter (https://sciter.com https://sciter.com) for 10+ years:
template <typename T>
struct slice {
const T* start;
unsigned int length;
...
}
https://github.com/c-smile/sciter-sdk/blob/master/include/aux-slice.h#L48 https://github.com/c-smile/sciter-sdk/blob/master/include/au...
Such small thing definitely speed ups many areas and surprisingly quite a lot, parsing in particular.
Nothing new under the Sun, eh?
- nightski 8y agoDoes your template work with memory managed by a GC and provide all the memory safety guarantees that .NET does? If so, does it work seamlessly across the stack & the heap for both managed memory and unmanaged memory at the same time? I get it, similar concepts - but let's not dismiss the value in this addition.
- c-smile 8y agoNo, this is pure C++ (non-managed) thing. It is used strictly in read-only places. It makes absolutely no sense to use things like std::string (and allocate it each time) when you need to pass string or fragment of string or array to consumers. For write-only access I also have target<T> that safely wraps all memcpy, memmove, strcpy[_s] cases.
- misnome 8y agoI didn’t read the poster as dismissing it (or claiming to have outright invented the concept) - rather pointing out that good implementations naturally keep re-arising.
- c-smile 8y agoYeah, this concept is quite old. It reincarnated quite many times: in D language by Walter Bright where arrays are just such slices. Or by Andrei Alexandrescu in its range<T> thing: http://www.informit.com/articles/article.aspx?p=1407357&seqNum=10 http://www.informit.com/articles/article.aspx?p=1407357&seqN...
- hoppelhase 8y agoAny special reason why they put the length after the pointer? Or is it just a coincidence?
- c-smile 8y agoQuestion is not clear. The Slice is just an address of memory chunk combined with the length of that chunk. That's somehow better than "C strings" - that are just pointers and so you need to do some computation if you need to get length of the string. Such C strings have too many drawbacks - in particular strtok function that modifies input string (that shall be read only all times).
- hoppelhase 8y agoWell, both implementations do have a strict which has the length as last member. Is there any special reason for it? Something like struct-layout optimization?
- zamalek 8y agoYou can re-interpret the struct to a pointer (length would simply be truncated). Apart from that there wouldn't be any benefit: the pointer and length would be aligned no matter which position they take (on x86 and amd64 at the very least).
- c-smile 8y ago"re-interpret the struct to a pointer (length would simply be truncated)." Wrong. It will be pointer-to-pointer. Reinterpretation (to treat struct as a pointer to C string) is only possible if you have something like this: struct BSTR { size_t length; WCHAR chars[N]; // N is length + 1 }; and you return pointer to chars[0]. This is so called Basic string - BSTR is a WCHAR* pointer to memory location prepended by string length field.
- zamalek 8y ago
- pjmlp 8y agoWell, to be fair Modula-3 and Eiffel did it first. And I bet Sciter is younger than any of them.
- c-smile 8y agoWould you mind to provide some link that illustrates what you mean exactly?
- pjmlp 8y agoBasic examples, a big late to go diving into old documentation. Modula-3 version: GENERIC MODULE Slices(T) TYPE Slice = RECORD start : REF T; (* If you want the GC out of the way, replace with UNTRACED REF T*) length: CARDINAL; ... END; END Slices; Or one could simply use open arrays: TYPE Slice = ARRAY OF T Eiffel version: expanded class Slice[T] start: detachable T; length: INTEGER_32; ... end Naturally, one would use Array[T].slice() instead. http://smarteiffel.loria.fr/libraries/api/lib.d/storage.d/loadpath.se.d/collection.d/ARRAY/ANY.html#slice http://smarteiffel.loria.fr/libraries/api/lib.d/storage.d/lo...
- c-smile 8y agoYeah, thanks a lot. That is really it. Same as in D lang. In fact D's array is just a slice. At least it used to be so 10 years ago. GC there does the rest - as in Modula-3.
- victorNicollet 8y agoSmall struct that is declared as public readonly ref struct Span<T> { private readonly ref T _pointer; private readonly int _length; ... } But the important parts are not _pointer or _length. Most of the implementation effort went into the `ref struct` part, which was released at the same time as Span<T> and is precisely what makes Span<T> powerful. It is a big thing.