@@ -19,6 +19,75 @@ class MessageListener {
1919 JUCE_DECLARE_WEAK_REFERENCEABLE (MessageListener)
2020};
2121
22+ // A simple memory block structure to manage free list.
23+ struct MemoryBlock {
24+ void * ptr;
25+ size_t size;
26+ };
27+
28+ // A custom allocator that doesn't deallocate memory, but reuses it.
29+ template <typename T>
30+ class ReuseAllocator {
31+ public:
32+ using value_type = T;
33+
34+ ReuseAllocator () noexcept {}
35+
36+ template <typename U>
37+ ReuseAllocator (const ReuseAllocator<U>&) noexcept {}
38+
39+ T* allocate (size_t n) {
40+ size_t bytes = n * sizeof (T);
41+
42+ // Check free list for a suitable block
43+ for (auto it = freeList.begin (); it != freeList.end (); ++it) {
44+ if (it->size >= bytes) {
45+ T* result = static_cast <T*>(it->ptr );
46+ freeList.erase (it);
47+ return result;
48+ }
49+ }
50+
51+ // Allocate new memory if no suitable block is found
52+ T* newBlock = static_cast <T*>(std::malloc (bytes));
53+ if (!newBlock) {
54+ throw std::bad_alloc ();
55+ }
56+
57+ return newBlock;
58+ }
59+
60+ void reserve (size_t n)
61+ {
62+ for (int i = 0 ; i < n; i++)
63+ {
64+ // populate the freeList with n addresses
65+ deallocate (allocate (1 ), 1 );
66+ }
67+ }
68+
69+ void deallocate (T* p, size_t n) noexcept {
70+ size_t bytes = n * sizeof (T);
71+
72+ // Push the memory back into the free list
73+ freeList.push_back ({p, bytes});
74+ }
75+
76+ template <typename U>
77+ bool operator ==(const ReuseAllocator<U>&) const noexcept {
78+ return true ;
79+ }
80+
81+ template <typename U>
82+ bool operator !=(const ReuseAllocator<U>&) const noexcept {
83+ return false ;
84+ }
85+
86+ private:
87+ // A simple free list to hold reusable memory blocks
88+ static inline std::vector<MemoryBlock> freeList;
89+ };
90+
2291// MessageDispatcher handles the organising of messages from Pd to the plugdata GUI
2392// It provides an optimised way to listen to messages within pd from the message thread,
2493// without performing and memory allocation or locking
@@ -33,13 +102,16 @@ class MessageDispatcher {
33102 };
34103
35104 static constexpr int StackSize = 1 << 20 ;
36- using MessageStack = plf::stack<Message>;
37- using AtomStack = plf::stack<t_atom>;
105+ using MessageStack = plf::stack<Message, ReuseAllocator<Message> >;
106+ using AtomStack = plf::stack<t_atom, ReuseAllocator<t_atom> >;
38107
108+ static inline ReuseAllocator<Message> messageAllocator = ReuseAllocator<Message>();
109+ static inline ReuseAllocator<t_atom> atomAllocator = ReuseAllocator<t_atom>();
110+
39111 struct MessageBuffer
40112 {
41- MessageStack messages;
42- AtomStack atoms;
113+ MessageStack messages = MessageStack(messageAllocator) ;
114+ AtomStack atoms = AtomStack(atomAllocator) ;
43115 };
44116
45117public:
@@ -48,11 +120,8 @@ class MessageDispatcher {
48120 usedHashes.reserve (StackSize);
49121 nullListeners.reserve (StackSize);
50122
51- for (auto & buffer : buffers)
52- {
53- buffer.messages .reserve (StackSize);
54- buffer.atoms .reserve (StackSize);
55- }
123+ messageAllocator.reserve (StackSize);
124+ atomAllocator.reserve (StackSize);
56125 }
57126
58127 static void enqueueMessage (void * instance, void * target, t_symbol* symbol, int argc, t_atom* argv) noexcept
0 commit comments