Get if element is valid from pointer?

Just starting out? Need help? Post your questions and find answers here.
Joubarbe
Enthusiast
Enthusiast
Posts: 703
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Get if element is valid from pointer?

Post by Joubarbe »

Hi,

It's probably been asked before but anyway... I'd like to verify the validity of a list element from its pointer, without going into a ForEach loop, for performance reasons.

Code: Select all

NewList lst.i()

AddElement(lst())
lst() = 12
AddElement(lst())
lst() = 15
*a = @lst()
DeleteElement(lst())

ChangeCurrentElement(lst(), *a)
DeleteElement(lst())
Will obviously gives a memory address error on the last line.

Code: Select all

If IsValidElement(lst(), *a)
  ChangeCurrentElement(lst(), *a)
  DeleteElement(lst())
EndIf
Would be nice.
I'd like to avoid putting my pointer at 0 after removing it the first time (and do a If *a = 0 check), because on a big source code, it can be a pain to do that everywhere. My Delete() function should ensure that the thing I want it to delete actually exists.

(too bad ChangeCurrentElement() doesn't return anything)
User avatar
mk-soft
Always Here
Always Here
Posts: 6207
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Get if element is valid from pointer?

Post by mk-soft »

It's not gonna work that way. With ChangeCurrentElement you always had to work very carefully.
If the order of the elements is not so important, I always work with "maps" and then also not with pointers.

Another way is to add a lock variable to the elements (refCount) and only delete the element when it is set to zero.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
mestnyi
Addict
Addict
Posts: 1098
Joined: Mon Nov 25, 2013 6:41 am

Re: Get if element is valid from pointer?

Post by mestnyi »

Obviously you need to delete the pointer yourself.

Code: Select all

NewList lst.i () 

AddElement (lst ()) 
lst () = 12 
AddElement (lst ()) 
lst () = 15 

*a = @lst () 
DeleteElement (lst ()) 
*a = 0

If *a
  ChangeCurrentElement (lst (), *a) 
  DeleteElement (LST ())
  *a = 0
EndIf
or check

Code: Select all

NewList lst.i () 

AddElement (lst ()) 
lst () = 12 
AddElement (lst ()) 
lst () = 15 

*a = @lst () 
DeleteElement (lst ()) 

Procedure IsValidElement(List Lst.i(), *a) 
  ForEach Lst()
    If Lst() = *a
      ProcedureReturn 1
    EndIf
  Next
EndProcedure

If IsValidElement(lst (), *a)
  ChangeCurrentElement (lst (), *a) 
  DeleteElement (LST ())
EndIf
What does it look like?
mk-soft wrote:Another way is to add a lock variable to the elements (refCount) and only delete the element when it is set to zero.
Little John
Addict
Addict
Posts: 4777
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Get if element is valid from pointer?

Post by Little John »

Joubarbe wrote:I'd like to avoid putting my pointer at 0 after removing it the first time (and do a If *a = 0 check)
Well, at least currently, while PureBasic does not have an IsValidElement() function or something similar, doing so is actually a good idea.
Joubarbe wrote:(too bad ChangeCurrentElement() doesn't return anything)
I agree. A proper return value of ChangeCurrentElement() would probably be sufficient for solving problems like the one you encountered. I made a corresponding feature request.

When playing with your above code, I also discovered a related bug in ChangeCurrentElement().
Joubarbe
Enthusiast
Enthusiast
Posts: 703
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Re: Get if element is valid from pointer?

Post by Joubarbe »

Yes, when writing the code above, I wondered if that was not a bug that ChangeCurrentElement() did not return an error. I'm not entirely sure of the answer; maybe some people want this behavior.

Anyway, thank you all. I'll reset my pointer to 0 I guess :)
Little John
Addict
Addict
Posts: 4777
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Get if element is valid from pointer?

Post by Little John »

Joubarbe wrote:Yes, when writing the code above, I wondered if that was not a bug that ChangeCurrentElement() did not return an error. I'm not entirely sure of the answer; maybe some people want this behavior.
As I already wrote, ChangeCurrentElement() should return 0 on error, and non-zero on success. That won't hurt anyone, and everyone then can decide her/himself what s/he is going to do with that information.
Joubarbe
Enthusiast
Enthusiast
Posts: 703
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Re: Get if element is valid from pointer?

Post by Joubarbe »

But what is success then? If the pointer points to an address that is not overwritten by the system, there will be a valid output:

Code: Select all

NewList lst.i()

AddElement(lst())
lst() = 12
AddElement(lst())
lst() = 15
*a = @lst()
DeleteElement(lst())

ChangeCurrentElement(lst(), *a)
Debug lst() ;DeleteElement(lst())
Still outputs 15. I'm afraid that checking the validity of the new element would mean to go through all the list. If not, that means that there's some way to know if a given address is "out of range" (and that would answer my original question).
freak
PureBasic Team
PureBasic Team
Posts: 5940
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Re: Get if element is valid from pointer?

Post by freak »

Keep in mind that the Memory for List items is reused:

Code: Select all

NewList lst.i()

AddElement(lst())
lst() = 123
*a = @lst()
Debug @lst()

DeleteElement(lst())

AddElement(lst())
lst() = 999
Debug @lst()                     ; oops, same value!


ChangeCurrentElement(lst(), *a)  ; this points to a valid element so the result would be "success" (if there was a return value)
Debug lst()                      ; ... but its not the element you want!
Once you call DeleteElement(), the element pointer becomes invalid. It no longer belongs to you. It can be reused for anything (new memory allocations). Remembering it past the DeleteElement() and trying to use it again is a programming error.
quidquid Latine dictum sit altum videtur
User avatar
mk-soft
Always Here
Always Here
Posts: 6207
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Get if element is valid from pointer?

Post by mk-soft »

Managed over RefCounter...

Update v0.6
- Added DeleteListElement
- Save List Position

Code: Select all

;-TOP

EnableExplicit

Structure udtMyList
  refCount.i
  iVal.i
EndStructure

Global MutexMyList = CreateMutex()

Procedure GetListElement(List MyList.udtMyList())
  LockMutex(MutexMyList)
  MyList()\refCount + 1
  UnlockMutex(MutexMyList)
  ProcedureReturn @MyList()
EndProcedure

Procedure FreeListElement(List Mylist.udtMyList(), *ppMyList.Integer, Delete = #True)
  Protected *pMyList.udtMyList
  LockMutex(MutexMyList)
  If *ppMyList\i
    *pMyList.udtMyList = *ppMyList\i
    If *pMyList\refCount > 0
      *pMyList\refCount - 1
      If *pMyList\refCount = 0 And Delete = #True
        If @Mylist() = *pMyList
          DeleteElement(Mylist())
        Else
          PushListPosition(MyList())
          ChangeCurrentElement(Mylist(), *pMyList)
          DeleteElement(Mylist())
          PopListPosition(Mylist())
        EndIf
      EndIf
    EndIf
    *ppMyList\i = 0
  EndIf
  UnlockMutex(MutexMyList)
EndProcedure

Procedure DeleteListElement(List MyList.udtMyList())
  LockMutex(MutexMyList)
  If MyList()\refCount = 0
    DeleteElement(MyList())
  EndIf
  UnlockMutex(MutexMyList)
EndProcedure

Global NewList MyData.udtMyList()

AddElement(MyData())
MyData()\iVal = 1
AddElement(MyData())
MyData()\iVal = 2
AddElement(MyData())
MyData()\iVal = 3
AddElement(MyData())
MyData()\iVal = 4


SelectElement(MyData(), 2)
Debug "Get Pointer A"
Define *a.udtMyList = GetListElement(MyData())
Debug "Get Pointer B"
Define *b.udtMyList = GetListElement(MyData())
Debug "Get Pointer C"
SelectElement(MyData(), 1)
Define *c.udtMyList = GetListElement(MyData())

ForEach MyData()
  Debug "refCount = " + MyData()\refCount + " | Value = " + MyData()\iVal
Next

Debug "Free Pointer A"
FreeListElement(MyData(), @*a)
ForEach MyData()
  Debug "refCount = " + MyData()\refCount + " | Value = " + MyData()\iVal
Next

Debug "Free Pointer B"
FreeListElement(MyData(), @*b)
ForEach MyData()
  Debug "refCount = " + MyData()\refCount + " | Value = " + MyData()\iVal
Next

Debug "Free all unused ListElements"
ForEach MyData()
  DeleteListElement(MyData())
Next
ForEach MyData()
  Debug "refCount = " + MyData()\refCount + " | Value = " + MyData()\iVal
Next

Debug "Free Pointer C"
FreeListElement(MyData(), @*c)
ForEach MyData()
  Debug "refCount = " + MyData()\refCount + " | Value = " + MyData()\iVal
Next
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Post Reply