Std::sort on juce::ValueTree

Hi,
is it possible to perform a std::sort on a ValueTree?
I got std::find_if to work with a Valuetree, but not std::sort. Is this possible? would be really cool, if not, are there any easy examples for juce::ValueTree::sort ?

Best,
equinox

ValueTree features a sort function.

Since ValueTree has begin() and end() iterators I quickly threw a std::sort at it, but the Iterators seemed not to work with std::sort. But could have been my fault)

int main (int argc, char* argv[])
{
    juce::ValueTree tree {"Parent", {},
        {
            {"Node",{{"text", "Ape"}}},
            {"Node",{{"text", "Zebra"}}},
            {"Node",{{"text", "Elephant"}}}
        }};
    
    DBG (tree.toXmlString());

    struct Sorter
    {
        int compareElements (const juce::ValueTree& first, const juce::ValueTree& second)
        {
            return first.getProperty ("text").toString().compare (second.getProperty ("text").toString());
        }
    };
    Sorter sorter;
    tree.sort (sorter, nullptr, false);

// but this didn't compile here:
//    std::sort (tree.begin(), tree.end(), [](const auto& first, const auto& second)
//    {
//        return first.getProperty ("text").toString().compare (second.getProperty ("text").toString());
//    });

    DBG ("sorted:");
    DBG (tree.toXmlString());

    return 0;
}

But the sorter approach did the job

std::sort requires that the iterator type is a ‘legacy random-access iterator’, but ValueTree::Iterator is only a ‘legacy forward iterator’. Therefore, std::sort should not be expected to work with ValueTree iterators.

1 Like

Thanks for the example!

    Sorter sorter;
    tree.sort (sorter, nullptr, false);

Could also be

    tree.sort (Sorter(), nullptr, false);

But still longer than some modern std::sort stuff

Thanks for the info! Ok, is there any chance that the iterator will be updated (if this is possible at all?).
Otherwise it would be also cool, if juce::ValueTree::sort() would just take some lamdba function.

I don’t think we have any plans in this area at the moment.

Ok, sad to hear.

would be really cool if it would be possible to shortn up those ~8 lines above to:

	tree.sort([](const juce::ValueTree& first, const juce::ValueTree& second) 
		{ return first.getProperty("text").toString().compare(second.getProperty("text").toString()); }, nullptr, false);

But anyway I’m glad that there is also a solution right now.

It is possible, with a little helper:

template<typename T>
struct LambdaSorter
{
    LambdaSorter (std::function<int(const T&, const T&)> s) : sortFunc (s) {}
    int compareElements (const T& first, const T& second)
    {
        return sortFunc (first, second);
    }
private:
    std::function<int(const T&, const T&)> sortFunc;
};

int main (int argc, char* argv[])
{
    juce::ValueTree tree {"Parent", {},
        {
            {"Node",{{"text", "Ape"}}},
            {"Node",{{"text", "Zebra"}}},
            {"Node",{{"text", "Elephant"}}}
        }};

    LambdaSorter<juce::ValueTree> sorter ([](const auto& first, const auto& second)
    {
        return first.getProperty ("text").toString().compare (second.getProperty ("text").toString());
    });
    tree.sort (sorter, nullptr, false);
    
    DBG ("sorted:");
    DBG (tree.toXmlString());

    return 0;
}

Your idea to build in place doesn’t compile btw, because the ElementComparator is taken by reference…

Since the sort function is bespoke to the ValueTree you might save the hassle of templating as well…

Might be a trivial addition to the ValueTree as well, if the juce team wants to add that

Cool thanks for your help! With your helper I was able to produce a compiling one-liner :smile:
Helper:

struct LambdaSorter
{
	using Vt = juce::ValueTree;

	LambdaSorter(std::function<int(const Vt&, const Vt&)> s) : sortFunc(s) {}

	int compareElements(const Vt& a, const Vt& b)
	{
		return sortFunc(a, b);
	}
private:
	std::function<int(const Vt&, const Vt&)> sortFunc;
};

Example with one-liner:

	juce::ValueTree tree{ "Parent",
					  {},
					  { { "Node", { { "text", "Ape" } } },
						{ "Node", { { "text", "Zebra" } } },
						{ "Node", { { "text", "Elephant" } } } } };

	DBG(tree.toXmlString());

	tree.sort(LambdaSorter ([](const auto& first, const auto& second) {
		return first.getProperty("text").toString().compare(second.getProperty("text").toString()); }),
		nullptr, false);

	DBG("sorted:");
	DBG(tree.toXmlString());

The Sorted() compiled also on my machine

I just cleaned it up a bit and send it to JUCE:

Let’s see where it ends up

3 Likes

cool! :slight_smile:

Little bump, now that the ADC dust has settled…

2 Likes