JUCE containers need some loving


#1

Right now we have Array, OwnedArray, ReferenceCountedArray. But they don’t share any code. And besides the required difference in features, some of them have useful features that the others don’t have. For example ReferenceCountedArray has no clearQuick(). There are other differences too, like the sorting.

There’s a bunch of duplicated code. We desperately need to refactor these classes to have some common stuff like the sorting, the ensure allocated, and what not. I think it could be done by having a GenericArray class that takes a Policy template parameter. Array, OwnedArray, and ReferenceCountedArray would provide a suitable Policy object and then they could share all the code.

Comprehensive list of JUCE array containers that need a generic shared implementation

Array
OwnedArray
ReferenceCountedArray
StringArray
StringPairArray

If I forgot anything, please let me know!


#2

I’m going to throw in a request for ensureAllocated() in the StringArray class, 'cos I just happened to miss that feature earlier this week.


#3

LOL…I forgot about that one. There’s a lot of duplicated code!

StringPairArray too. I will update the original post.


#4

Yes, there’s a lot of duplication, but annoyingly, there are minor differences all through it that would make refactoring it quite complicated, and it’d involve some fiddly use of policy classes to handle all the idiosyncrasies.

Although duplicated code is one of the programming sins that I hate the most, in the case of these particular classes, there are actually some good arguments in favour of it… Being such common classes, there’s actually a lot to be said for keeping their structure very simple, because it means that the documentation will be generated better, with each class getting more customised comments. And most importantly, when you step through the code in the debugger, everything is really straightforward. If they were all refactored into a set of core classes + policy classes, everything would become much more of a mess when debugging. It’s like a lot of the std library - one of my pet hates is whenever I have to step into classes like std::map or std::vector, and even with their simplest methods, you just get bogged-down stepping through a jungle of interconnected template classes, making it very hard to see what’s actually going on.

Gotcha - consider it done!


#5

Sorry but I have to agree with Jules on this one. My main reason for using the JUCE data collections is that they’re not the stl and all that comes with it - yet I’m happy that still have the stl to fall back on when the big generic guns are needed. A lot of the JUCE collection code will be inlined, so I suspect that any benefits to code size by finding common code between collections will be minimal. Most people want to step through the minimum number of lines of code when debugging and have half sensible template error messages from the compiler than achieve code factorisation nirvana.


#6

Yeah those are good points Jules. I hate stepping into standard container code!


#7

We’re missing OwnedArray::clearQuick


#8

Ok, will add that…


#9

RefCountedObjectArray::clearQuick() also missing


#10

If you’re going to have clear() take a bool deleteObjects that defaults to true then clearQuick() should also have its parameter default to true.


#11

StringArray and StringPairArray are missing clearQuick


#12

Gotcha.

I deliberately avoided giving OwnedArray::clearQuick a default parameter, because I don’t think that “true” would be the most common use-case for it. If you’re choosing to delete all the objects, then the operation certainly won’t be quick, and avoiding one extra deallocation is unlikely to make much difference.


#13

When you’re writing a server that stays up for long periods, you want to memory allocation / reallocation as much as possible. In many cases I use OwnedArray<> to hold a temporary set of objects that gets passed around. I keep the OwnedArray around and re-use it. It’s true that the child objects are deleted.

But it’s nice that once the amount of storage for the reused OwnedArray grows to its high water mark it no longer needs a reallocation.


#14

I stumbled across this thread looking for a clearQuick() method in ReferenceCountedArray. As far as I can tell it's still missing. Could it be added to JUCE? I made my own by just copying the clear() method and removing the data.setAllocatedSize (0); line at the end.



 


#15

Sure, I guess I could add that. To some extent my comments above about OwnedArray also apply to ReferenceCountedArray, but to a lesser extent.


#16

Thanks a lot for adding the method. I read the thread and I totally agree about keeping the containers separate code. This helps a lot when debugging/profiling. 

In my case this clearQuick makes a big difference because I know for sure that reaching a refCount of 0 for an array member happens only in extremely rare cases, so this does help me avoid many deallocations. 

I only knew that clear() does free memory when it showed up in the profiler :) . Coming from STL I assumed clear() would not free memory and used it in a performance-critical section, but that was a wrong assumption and clearQuick() solves the problem for me so thanks heaps!