<div id="__MailbirdStyleContent" style="font-size: 10pt;font-family: Arial;color: #000000;text-align: left" dir="ltr">
                                        <div>Hi all!</div><div><br></div>Sorry for the feature-mix in this commit.<div class="mb_sig"></div>
                                        <div><br></div><div>Please let me know whether those are good names:</div><div>#writer</div><div>#zeroMemory</div><div><br></div><div>I know "ZeroMemory(...)" from the win32-API. And "writer" is just small enough to squeeze it in when changing a composite struct:</div><div><span style="font-size: 13.3333px"><br></span></div><div><span style="font-size: 13.3333px">composite := FFITestSUfdUdSi2 new. "object memory / byte array"</span><br></div><div><span style="font-size: 13.3333px">composite writer udSii2 sii1 i1: 42.</span><br></div><div><br></div><div>Best,</div><div>Marcel</div><blockquote class="history_container" type="cite" style="border-left-style: solid;border-width: 1px;margin-top: 20px;margin-left: 0px;padding-left: 10px;min-width: 500px">
                        <p style="color: #AAAAAA; margin-top: 10px;">Am 03.05.2021 18:54:03 schrieb commits@source.squeak.org <commits@source.squeak.org>:</p><div style="font-family:Arial,Helvetica,sans-serif">Marcel Taeumel uploaded a new version of FFI-Kernel to project FFI:<br>http://source.squeak.org/FFI/FFI-Kernel-mt.126.mcz<br><br>==================== Summary ====================<br><br>Name: FFI-Kernel-mt.126<br>Author: mt<br>Time: 3 May 2021, 6:53:53.131479 pm<br>UUID: efa27be5-2153-1c47-b30f-b8d9ca10b1c8<br>Ancestors: FFI-Kernel-mt.125<br><br>Adds a transparent way to write into composite structures that reside in object memory: #writer. (Name is up for discussion, especially since the namespace for custom structs is limited.)<br><br>Adds #zeroMemory to remove information from internal or external memory. <br><br>Fixes regression in ExternalData >> #free.<br><br>Adds sanity checks to ExternalStructure #new and #externalNew, which both made no sense for type aliases.<br><br>=============== Diff against FFI-Kernel-mt.125 ===============<br><br>Item was added:<br>+ ----- Method: ByteArray>>zeroMemory (in category '*FFI-Kernel') -----<br>+ zeroMemory<br>+ <br>+  self atAllPut: 0.!<br><br>Item was added:<br>+ ----- Method: ByteArray>>zeroMemory: (in category '*FFI-Kernel') -----<br>+ zeroMemory: numBytes<br>+ <br>+    1  to: numBytes do: [:index |<br>+                self byteAt: index put: 0].!<br><br>Item was added:<br>+ ProtoObject subclass: #ByteArrayWriter<br>+    instanceVariableNames: 'byteOffset byteSize byteArray'<br>+       classVariableNames: ''<br>+       poolDictionaries: ''<br>+         category: 'FFI-Kernel'!<br>+ <br>+ !ByteArrayWriter commentStamp: 'mt 5/3/2021 17:44' prior: 0!<br>+ I am a transparent wrapper over byte-array handles to allow access and manipulation just like through an external address.!<br><br>Item was added:<br>+ ----- Method: ByteArrayWriter class>>on: (in category 'instance creation') -----<br>+ on: handle<br>+ <br>+    self assert: [handle isInternalMemory].<br>+      ^ self new setArray: handle!<br><br>Item was added:<br>+ ----- Method: ByteArrayWriter>>doesNotUnderstand: (in category 'system primitives') -----<br>+ doesNotUnderstand: aMessage<br>+ <br>+        | selector args |<br>+    selector := aMessage selector.<br>+       args := aMessage arguments.<br>+  args size caseOf: {<br>+          [ 1 ] -> [ (selector endsWith: 'At:') ifTrue: [ args at: 1 put: args first  + byteOffset ] ].<br>+             [ 2 ] -> [ (selector endsWith: 'length:')<br>+                         ifTrue: [<br>+                            args at: 1 put: args first + byteOffset.<br>+                             args first + args second > byteSize<br>+                                       ifTrue: [self errorSubscriptBounds: args first + args second] ]<br>+                      ifFalse: [(selector endsWith: 'put:') ifTrue: [<br>+                              args at: 1 put: args first + byteOffset ]] ].<br>+                [ 3 ] -> [ (selector endsWith: 'length:')<br>+                         ifTrue: [<br>+                            args at: 1 put: args first + byteOffset.<br>+                             args first + args third > byteSize<br>+                                        ifTrue: [self errorSubscriptBounds: args first + args third]]] <br>+              } otherwise: [].                                <br>+     ^ aMessage sendTo: byteArray!<br><br>Item was added:<br>+ ----- Method: ByteArrayWriter>>errorSubscriptBounds: (in category 'initialization') -----<br>+ errorSubscriptBounds: index<br>+ <br>+       Error signal: 'subscript is out of bounds: ' , index printString.!<br><br>Item was added:<br>+ ----- Method: ByteArrayWriter>>setArray: (in category 'initialization') -----<br>+ setArray: aByteArray<br>+ <br>+     byteArray := aByteArray.<br>+     byteOffset := 0.<br>+     byteSize := aByteArray size.!<br><br>Item was added:<br>+ ----- Method: ByteArrayWriter>>setArray:offset:size: (in category 'initialization') -----<br>+ setArray: aByteArray offset: aByteOffset size: aByteSize<br>+ <br>+  byteArray := aByteArray.<br>+     byteOffset := aByteOffset.<br>+   byteSize := aByteSize.<br>+       <br>+     (byteOffset + byteSize > byteArray size)<br>+          ifTrue: [self errorSubscriptBounds: byteOffset + byteSize].!<br><br>Item was added:<br>+ ----- Method: ByteArrayWriter>>structAt:length: (in category 'accessing') -----<br>+ structAt: newByteOffset length: newLength<br>+ <br>+    ^ ByteArrayWriter new<br>+                setArray: byteArray<br>+          offset: byteOffset + newByteOffset - 1<br>+               size: newLength!<br><br>Item was added:<br>+ ----- Method: ByteArrayWriter>>structAt:put:length: (in category 'accessing') -----<br>+ structAt: newByteOffset put: value length: newLength<br>+ <br>+         (newByteOffset + newLength > byteSize)<br>+            ifTrue: [self errorSubscriptBounds: newByteOffset + newLength].<br>+ <br>+  ^ byteArray<br>+          structAt: byteOffset + newByteOffset - 1<br>+             put: value<br>+           length: newLength!<br><br>Item was added:<br>+ ----- Method: Character class>>zero (in category '*FFI-Kernel') -----<br>+ zero<br>+         "See ExternalStructure >> #zeroMemory."<br>+      <br>+     ^ $0!<br><br>Item was added:<br>+ ----- Method: ExternalAddress>>zeroMemory (in category 'initialize-release') -----<br>+ zeroMemory<br>+   "We need length information in bytes."<br>+     self shouldNotImplement.!<br><br>Item was added:<br>+ ----- Method: ExternalData>>free (in category 'initialize-release') -----<br>+ free<br>+ <br>+  super free.<br>+  size := nil.!<br><br>Item was added:<br>+ ----- Method: ExternalData>>zeroMemory (in category 'initialize-release') -----<br>+ zeroMemory<br>+      "Remove all information but keep the memory allocated."<br>+ <br>+        self sizeCheck.<br>+ <br>+  handle isExternalAddress<br>+             ifTrue: [handle zeroMemory: self size * self contentType byteSize]<br>+           ifFalse: [ "ByteArray" handle zeroMemory].!<br><br>Item was changed:<br>  ----- Method: ExternalStructure class>>externalNew (in category 'instance creation') -----<br>  externalNew<br>         "Create an instance of the receiver on the external heap"<br>+ <br>+      ^ self fromHandle: (self externalType isTypeAliasForAtomic<br>+           ifTrue: [self error: 'This is an alias-for-atomic type. You must use #fromHandle:']<br>+          ifFalse: [<br>+                   self externalType isTypeAliasForPointer<br>+                              ifTrue: [ByteArray new: self byteSize]<br>+                               ifFalse: [ExternalAddress allocate: self byteSize]])!<br>-        ^self fromHandle: (ExternalAddress allocate: self byteSize)!<br><br>Item was changed:<br>  ----- Method: ExternalStructure class>>new (in category 'instance creation') -----<br>  new<br>+         ^self fromHandle: (self externalType isTypeAliasForAtomic<br>+            ifTrue: [self error: 'This is an alias-for-atomic type. You must use #fromHandle:']<br>+          ifFalse: [ByteArray new: self byteSize]).!<br>-   ^self fromHandle: (ByteArray new: self byteSize)!<br><br>Item was added:<br>+ ----- Method: ExternalStructure class>>newZero (in category 'instance creation') -----<br>+ newZero<br>+ <br>+  ^ self new<br>+           zeroMemory;<br>+          yourself!<br><br>Item was added:<br>+ ----- Method: ExternalStructure>>writer (in category 'accessing') -----<br>+ writer<br>+ <br>+  ^ handle isInternalMemory<br>+            "Wrap handle into helper to address offsets in the byte array."<br>+            ifTrue: [self class fromHandle: (ByteArrayWriter on: handle)]<br>+                "Either alias-to-atomic or already in external memory."<br>+            ifFalse: [self]!<br><br>Item was added:<br>+ ----- Method: ExternalStructure>>zeroMemory (in category 'initialize-release') -----<br>+ zeroMemory<br>+      "Remove all information but keep the memory allocated."<br>+ <br>+        handle isExternalAddress<br>+             ifTrue: [handle zeroMemory: self externalType byteSize]<br>+              ifFalse: [handle isInternalMemory<br>+                    ifTrue: [handle zeroMemory]<br>+                  ifFalse: [<br>+                           "Alias-to-atomic type."<br>+                            handle := handle class zero]].!<br><br><br></div></blockquote></div>