• Dear Cerberus X User!

    As we prepare to transition the forum ownership from Mike to Phil (TripleHead GmbH), we need your explicit consent to transfer your user data in accordance with our amended Terms and Rules in order to be compliant with data protection laws.

    Important: If you accept the amended Terms and Rules, you agree to the transfer of your user data to the future forum owner!

    Please read the new Terms and Rules below, check the box to agree, and click "Accept" to continue enjoying your Cerberus X Forum experience. The deadline for consent is April 5, 2024.

    Do not accept the amended Terms and Rules if you do not wish your personal data to be transferred to the future forum owner!

    Accepting ensures:

    - Continued access to your account with a short break for the actual transfer.

    - Retention of your data under the same terms.

    Without consent:

    - You don't have further access to your forum user account.

    - Your account and personal data will be deleted after April 5, 2024.

    - Public posts remain, but usernames indicating real identity will be anonymized. If you disagree with a fictitious name you have the option to contact us so we can find a name that is acceptable to you.

    We hope to keep you in our community and see you on the forum soon!

    All the best

    Your Cerberus X Team

Implemented Enhanced Pools

PixelPaladin

New member
CX Code Contributor
3rd Party Module Dev
Joined
Aug 27, 2017
Messages
110
Hello,

I had an idea how pools could be enhanced. Here is my concept:
Code:
Class Pool<T>
   
    Private
   
    Field _pool := New Stack<T>
   
    Global _HasOnPoolAllocate:Int = Pool<T>.UNKNOWN
    Global _HasOnPoolFree:Int     = Pool<T>.UNKNOWN
   
    Const UNKNOWN:Int = 0
    Const YES:Int     = 1
    Const NO:Int      = 2
   
    Public
   
    Method New(initialCapacity:Int = 10)
        For Local i:Int = 0 Until initialCapacity
            _pool.Push New T
        Next
    End
   
    Method Allocate:T()
        Local o:T
        If _pool.IsEmpty() Then
            o = New T
        Else
            o = _pool.Pop()
        End
       
        Select _HasOnPoolAllocate
        Case YES
            IOnPoolAllocate(o).OnPoolAllocate()
        Case UNKNOWN
            _HasOnPoolAllocate = NO
            If IOnPoolAllocate(o) Then
                _HasOnPoolAllocate = YES
                IOnPoolAllocate(o).OnPoolAllocate()
            End
        End
       
        Return o
    End
   
    Method Free:Void(o:T)
        Select _HasOnPoolFree
        Case YES
            IOnPoolFree(o).OnPoolFree()
        Case UNKNOWN
            _HasOnPoolFree = NO
            If IOnPoolFree(o) Then
                _HasOnPoolFree = YES
                IOnPoolFree(o).OnPoolFree()
            End
        End
       
        _pool.Push(o)
    End
End

Interface IOnPoolAllocate
    Method OnPoolAllocate:Void()
End

Interface IOnPoolFree
    Method OnPoolFree:Void()
End
My pool class is still compatible with the current brl pools. The difference is that if a class implements the IOnPoolAllocate interface an initialization method will automatically be called when Pool.Allocate() will be called (same goes for IOnPoolFree when Pool.Free() will be called).
So like constructors/destructors this can be used to initialize and clean up objects automatically.

Here is how it can be used:
Code:
Class Foo Implements IOnPoolAllocate, IOnPoolFree
    Method OnPoolAllocate:Void()
        Print "init stuff"
    End
   
    Method OnPoolFree:Void()
        Print "clean up stuff"
    End
End

Function Main:Int()
    Local FooPool := New Pool<Foo>
    Local bar := FooPool.Allocate() ' => prints "init stuff"
    FooPool.Free(bar)               ' => prints "clean up stuff"
    Return 0
End
 
Does your version have an impact on performance?
Not really. When the first element gets allocated/freed it looks if IonPoolAllocate/IOnPoolFree is implemented and remembers this in two globals for each generic pool class (2 integers for class Pool<Int> Pool<Foo>, 2 for class Pool<String> Pool<Bar>, …). Because this information gets stored, this check (and with it the slow casting operation) only happens once. When allocating/freeing more objects it just looks at these globals. That means the overhead for storing the additional information is minimal as well as the performance impact.
It also should not interfere with any existing code.
 
Last edited:
Cool. Then get to work. It would be cool to provide an example and extend the docs.
 
Last edited:
Still waiting for your push request :)
The Pool library is nothing more than what I posted. I still need to add the documentation and write examples.
I am not sure if it is right to change the brl libraries since code from the community is not really related to brl. Maybe we should provide a module with all the functionality added by the community. So instead of importing brl.pool people would import whatever.pool. This would also prevent conflicts with existing code (maybe there is something we did not think of at the moment).
 
I understand your concerns. But what if brl.pool is used by some other modules, and then, when you import mywhatever.pool, you have the pool features imported twice (OK, for simple stuff, this won't really increase file size). Or you have conflicts because both brl's and mywhatever's pool class is just named Pool. Or they're named differently and therefore you lose a bit of compatibility. Best would probably be if mywhatever's pool extends brl's pool - but following this mentality, you will almost for sure encounter the case where SOMEONE was overly generous with Private and Final and stuff and you have to modify the brl sources anyway to make the base class extensible.

Just some thoughts.

I think I never used pools so far, so I don't really have an opinion about if the extra functionality is worth the tiny bit of impact on performance. My guess is it is.
 
The Pool library is nothing more than what I posted. I still need to add the documentation and write examples.
I am not sure if it is right to change the brl libraries since code from the community is not really related to brl. Maybe we should provide a module with all the functionality added by the community. So instead of importing brl.pool people would import whatever.pool. This would also prevent conflicts with existing code (maybe there is something we did not think of at the moment).

Ahh ok. As it was posted in the suggestion section to improve Cx I thought you want to add it to the repro. but I understand you concerns, even I don't share them. BRL is just a name.
Then just release it on your own as an external module. I glady will add it to the modules page if you want me to.
 
Last edited:
Adding to this, shipping Cx with 2 versions of a Pool make no sense imho. I hate it already that we have 2 versions of mojo.
 
Seems like I cannot work with the cerberus git repo. I even tried to clone it again. Whenever I try to pull from the upstream repo it tells me that I should commit my changes first or stash them. When I stash them git keeps telling me the same stuff. The problem has something to do with how git handles the line endings. The problem file is this one:
Code:
targets/winrt_winphone8/template/MainPage.xaml.cs
This is the message I get:
Code:
error: Your local changes to the following files would be overwritten by merge:
   targets/winrt_winphone8/template/MainPage.xaml.cs
Please, commit your changes or stash them before you can merge.
Aborting
EDIT: nevermind - works now ...
 
Last edited:
I always felt "brl" was a odd choice of name for what were supposed to be standard modules. Obviously it stands for Blitz Research - but it's still just a acronymic library name. If people don't want to change it and everything in it, best just use it as a codename that was chosen that might not be up to date with stuff that happened since.
 
Back
Top Bottom