Page 2 of 2

Re: If eax = *p, then FreeMemory(*p) before ProcedureReturn?

Posted: Thu Dec 22, 2011 4:32 pm
by Demivec
@skywalk: I'm not sure what you are trying to accomplish with such a small static array with only 2 elements. This will surely cause you problems with nested calls.

Using the method I posted with an array of only 10 elements will allow calls like:

Code: Select all

cSum2(cSum2(cSum2(cSum2(cSum2(cSum2(cSum2(cSum2(A,B),B),B),B)B),B),B),cSum2(A,cSum2(A,B)))
To preserve the result that is returned just copy the structure to a structured variable like so:

Code: Select all

;with variable
C.csi
CopyStructure(cSum2(A,B), C, csi)
;or with pointers
*D.csi
CopyStructure(cSum2(csum2(B,A), B), *D, csi)
wilbert tried a variation of my approach but his required a global array of structured variables and also a search for unused variables each time the procedure was called. My approach simply used the next index.


I've used the approach that you demonstrated first where you passed the pointer in. This requires some acrobatic work to perform nested calls by using lots of single calls. The method that allocates a new structure each time requires you to free it when you're done with it. As you know that method doesn't work with nested calls without memory leaks.

Since your goal is to make nested calls and to keep the parameter count down I think the static array method would be a good choice. You only need to decide on how many indices to set aside to handle the depth of nesting that you expect. As you can see from my example above that can probably be kept under 10.


It would be great if this process was automated and made native. In the mean time it is not very difficult to implement it this way. If thread safety is needed it does get messier.

Re: If eax = *p, then FreeMemory(*p) before ProcedureReturn?

Posted: Thu Dec 22, 2011 5:58 pm
by skywalk
Hi Demivec,
Yeah it was late and I was trying lots of variations. :oops:
I will ponder this some more, but like you said, the 3 parameter approach is cleaner but ugly.

Thanks wilbert and xorc1zt for your suggestions.

Re: If eax = *p, then FreeMemory(*p) before ProcedureReturn?

Posted: Thu Dec 22, 2011 7:12 pm
by Trond
Be careful so you free all allocated memory. In your example, you allocate memory for *C, then make an assignment to it (*C = cSum2(A,B)). So the memory you allocated is lost.

I think you should go with #3 or something like this:

Code: Select all


Global SRefCounted_ObjectCounter ; Only for debugging
Structure SRefCounted ; Extend from this to allow refcounting
  RefCount.i
EndStructure

Structure cri Extends SRefCounted ; Define complex rectangular(real/imag) or polar(mag/ang)
  r.d   ; real or mag
  i.d   ; imag or ang
EndStructure

; Create support procedures for a new refcounted type
Macro New_Refcounted(Type)
  Procedure New#Type()
    SRefCounted_ObjectCounter + 1
    *M.SRefCounted =  AllocateMemory(SizeOf(Type))
    Debug "allocate " + Str(*M)
    *M\RefCount = 1
    ProcedureReturn *M
  EndProcedure
EndMacro

Procedure Get(*M.SRefCounted)
  If *M And *M\RefCount > 0
    *M\RefCount + 1
  EndIf
EndProcedure

Procedure Release(*M.SRefCounted)
  If *M
    If *M\RefCount
      If *M\RefCount = 1
        Debug "free " + Str(*M)
        SRefCounted_ObjectCounter - 1
        FreeMemory(*M)
      Else
        *M\RefCount - 1
      EndIf
    EndIf
  EndIf
EndProcedure

New_Refcounted(cri)


Procedure.i cSum4(*x.cri, *y.cri)
  ; Return complex sum of 2 complex numbers
  ; Returns Pointer to Structured memory.
  *r.cri = NewCri()
  *r\r = *x\r + *y\r
  *r\i = *x\i + *y\i
  Release(*x)
  Release(*y)
  ProcedureReturn *r
EndProcedure

;- Example

Global a.cri, b.cri, *c.cri

A\r  = 1: A\i  = 1
B\r  = 2: B\i  = 2


*C = cSum4(A, cSum4(A,B))
Debug "[1+1i] + ([1+1i] + [2+2i]) = " + StrD(*C\r,1) + " + " +StrD(*C\i,1) + "i"
Release(*c)

Debug SRefCounted_ObjectCounter ; Shouldn't be rising, else you know you're leaking memory. 0 is fine.
In addition to pointers, normal variables (not pointers) can also be passed as parameters. Because when the refcount field is 0, the variable is seen as "static", and will not be freed by Release().

Re: If eax = *p, then FreeMemory(*p) before ProcedureReturn?

Posted: Thu Dec 22, 2011 7:31 pm
by idle
is there anything wrong with this?

Code: Select all

Structure cri 
  r.d   ; real or mag
  i.d   ; imag or ang
EndStructure

Procedure.i cSum4(*x.cri, *y.cri)
  Static r.cri 
  r\r = *x\r + *y\r
  r\i = *x\i + *y\i
  ProcedureReturn @r
EndProcedure
;- Example

Global a.cri, b.cri, *c.cri

A\r  = 1: A\i  = 1
B\r  = 2: B\i  = 2

*C = cSum4(A, cSum4(A,B))
Debug "[1+1i] + ([1+1i] + [2+2i]) = " + StrD(*C\r,1) + " + " +StrD(*C\i,1) + "i"

Re: If eax = *p, then FreeMemory(*p) before ProcedureReturn?

Posted: Thu Dec 22, 2011 7:39 pm
by STARGÅTE
is there anything wrong with this?
yes ^^

Code: Select all

A\r  = 0: A\i  = 1
B\r  = 1: B\i  = 0
*C = cSum4(cSum4(A,A), cSum4(B,B))
Debug StrD(*C\r,1) + " + " +StrD(*C\i,1) + "i"
[(1+0i)+(1+0i)] + [(0+1i)+(0+1i)] = 2+2i but you get 0+4i , because A+A overwrite the result B+B (parameter evaluate from right to left), so you eval A+A+A+A

here some trick from me, to use 2 floats in one Quad to return it from a procedure:
http://www.purebasic.fr/german/viewtopi ... =8&t=24674

Re: If eax = *p, then FreeMemory(*p) before ProcedureReturn?

Posted: Thu Dec 22, 2011 7:54 pm
by STARGÅTE
here my code to work with complex values:

without allocatememory, global, staitc ... only two Floats in one Quad !

Code: Select all


Structure Complex
	StructureUnion
		Quad.q : Float.f[2]
	EndStructureUnion
EndStructure

Procedure.q Complex(Re.f, Im.f)
	Protected Object.Complex
	Object\Float[0] = Re : Object\Float[1] = Im
	ProcedureReturn Object\Quad
EndProcedure

Procedure.q ComplexPlus(A.q, B.q)
	Protected *A.Complex = @A, *B.Complex = @B
	ProcedureReturn Complex(*A\Float[0]+*B\Float[0], *A\Float[1]+*B\Float[1])
EndProcedure

Procedure.q ComplexTimes(A.q, B.q)
	Protected *A.Complex = @A, *B.Complex = @B
	ProcedureReturn Complex(*A\Float[0]**B\Float[0]+*A\Float[1]**B\Float[1], *A\Float[0]**B\Float[1]+*A\Float[1]**B\Float[0])
EndProcedure

Procedure.f ComplexAbs(A.q)
	Protected *A.Complex = @A
	ProcedureReturn Sqr(*A\Float[0]**A\Float[0]+*A\Float[1]**A\Float[1])
EndProcedure

Procedure.s ComplexStr(A.q)
	Protected *A.Complex = @A
	ProcedureReturn RTrim(StrF(*A\Float[0]),"0")+" + "+RTrim(StrF(*A\Float[1]),"0")+" i"
EndProcedure

A.q = Complex(0, 1)
B.q = Complex(1, 0)

Debug ComplexStr(ComplexPlus(A, B))
Debug ComplexStr(ComplexTimes(A, A))

Debug ComplexStr(ComplexPlus(ComplexPlus(A, A), ComplexPlus(B, B)))

Debug ComplexAbs(Complex(1, 1))