edit: scroll down to see the results
#credits: filwit
this is the fastest way i have found to return a populated collection calling it from c# gives a fair enhancement in performance compared to the List<whateverObject>
ps. this is my first try (only to post this code block) took me some time to find how (::) so forget about highlighting(; anyways..this is the function i am using, how can i produce same thing in nim?
void __stdcall GetPacksPtr(int size, DataPackCharPnt** DpArrPnt ) { int TmpStrSize = 10; *DpArrPnt = (DataPackCharPnt*)CoTaskMemAlloc( size * sizeof( DataPackCharPnt )); DataPackCharPnt* CurPackPnt = *DpArrPnt; char dummyStringDataObject[]= "abcdefgHi"; for ( int i = 0; i < size; i++,CurPackPnt++ ) { dummyStringDataObject[9] = i+'0';//simulate string coming from say DB CurPackPnt->IntVal=i; //2 ways i have tested both seems OK CurPackPnt->buffer = (char*)malloc(sizeof(char)*TmpStrSize); //or the next is better - no need for TmpStrSize CurPackPnt->buffer = (char*)malloc(sizeof(dummyStringDataObject)); strcpy(CurPackPnt->buffer, dummyStringDataObject); } } this is the struct typedef struct _DataPackCharPnt { char* buffer; UINT IntVal;//int was the original type.. testing both } DataPackCharPnt;
Perhaps try something like this:
type
DataPacks = seq[DataPack]
DataPack = object
buffer: string
intVal: uint32
proc getPacks(packs:var DataPacks, size:int) =
packs.newSeq(size)
var dummyData = "abcdefghi"
for i, curPack in packs.mpairs:
dummyData[9] = char(i + int8'0') # simulate string coming from say DB
curPack = DataPack(buffer:dummyData, intVal:uint32 i)
Test it like this:
var testPacks: DataPacks
testPacks.getPacks(32)
for p in testPacks: echo p
This code is roughly equivalent to your C version except it uses Nim's GC/Allocator, which means you don't have worry about memory leaks or manually free the data packs (as long as you're not sharing this memory across threads). If you want to manually manage your own memory (don't assume it's slower without benchmarking!), or it's required for your project, then use something like buffer: ptr char instead of buffer: string and allocate it with create or createU.
Also, it looks like CoTaskMemAlloc is an allocator used to prevent memory leaks with COM interop on Windows.. Not sure of the details there but either way you should be able to use it with something like:
proc CoTaskMemAlloc(int cb): pointer {.importC dynlib:"ole32.dll".}
type
DataPacks = ptr DataPack
...
proc getPacks(packs:var DataPacks, ...) =
packs = cast[DataPacks](CoTaskMemAlloc(size * sizeof DataPack))
...
finally got to test the first simpler version,well relatively, and only a Day later cause i insist on braking it to parts and understand
now that i am close to comprehend , and only close, cause still there was only the issue of declare, only one way proc Name(place return here) rather proc Name(): returnT =
i will finish testing first approach then check if there's any need for 'unsafe' one
Res Total PopulateLstPackUPtrCpp: ticks 24321 ms 8 Res Total PopulateLstPackPtrNim: ticks 19221 ms 6
i was really in doubt that i will get any faster results than this (cpp)
as it was already blazing fast i comparison to .net standards (48 ms)
i am shocked ! it was totally worth 48 hours of digging in nims manual, compiler MinGW .. struggling with the correct syntax for dll creation all those settings, which would probably take 5 minutes to you..
respect nim!