Page 1 of 1
Get if element is valid from pointer?
Posted: Sat Aug 03, 2019 9:37 am
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)
Re: Get if element is valid from pointer?
Posted: Sat Aug 03, 2019 11:06 am
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.
Re: Get if element is valid from pointer?
Posted: Sat Aug 03, 2019 11:35 am
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.
Re: Get if element is valid from pointer?
Posted: Sat Aug 03, 2019 11:51 am
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().
Re: Get if element is valid from pointer?
Posted: Sat Aug 03, 2019 11:59 am
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

Re: Get if element is valid from pointer?
Posted: Sat Aug 03, 2019 12:29 pm
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.
Re: Get if element is valid from pointer?
Posted: Sat Aug 03, 2019 12:38 pm
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).
Re: Get if element is valid from pointer?
Posted: Sat Aug 03, 2019 12:58 pm
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.
Re: Get if element is valid from pointer?
Posted: Sat Aug 03, 2019 1:01 pm
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