From eb2e4ff25d9cf45eb091365aa142f2d352eec28a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 18 Dec 2021 20:55:18 +0100 Subject: [PATCH] SceneTools: make orderClusterParents() use one allocation instead of 4. Mmm. I wonder how much will future mosra hate me for making this code so obfuscated. --- src/Magnum/SceneTools/OrderClusterParents.cpp | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/Magnum/SceneTools/OrderClusterParents.cpp b/src/Magnum/SceneTools/OrderClusterParents.cpp index ff94eb610..9787e1369 100644 --- a/src/Magnum/SceneTools/OrderClusterParents.cpp +++ b/src/Magnum/SceneTools/OrderClusterParents.cpp @@ -26,6 +26,7 @@ #include "OrderClusterParents.h" #include +#include #include #include @@ -45,7 +46,6 @@ Containers::Array> orderClusterParents(const } void orderClusterParentsInto(const Trade::SceneData& scene, const Containers::StridedArrayView1D& mappingDestination, const Containers::StridedArrayView1D& parentDestination) { - #ifndef CORRADE_NO_ASSERT const Containers::Optional parentFieldId = scene.findFieldId(Trade::SceneField::Parent); CORRADE_ASSERT(parentFieldId, "SceneTools::orderClusterParentsInto(): the scene has no hierarchy", ); @@ -54,15 +54,34 @@ void orderClusterParentsInto(const Trade::SceneData& scene, const Containers::St "SceneTools::orderClusterParentsInto(): expected mapping destination view with" << parentFieldSize << "elements but got" << mappingDestination.size(), ); CORRADE_ASSERT(parentDestination.size() == scene.fieldSize(*parentFieldId), "SceneTools::orderClusterParentsInto(): expected parent destination view with" << parentFieldSize << "elements but got" << parentDestination.size(), ); - #endif - /* Convert the parent list to a child list to sort them toplogically */ - const Containers::Array> parents = scene.parentsAsArray(); + /* Allocate a single storage for all temporary data */ + Containers::ArrayView> parents; + Containers::ArrayView childrenOffsets; + Containers::ArrayView children; + Containers::ArrayView parentsToProcess; + Containers::ArrayTuple storage{ + /* Output of scene.parentsInto() */ + {NoInit, parentFieldSize, parents}, + /* Running children offset (+1) for each node including root (+1), plus + one more element when we shift the array by one below */ + {ValueInit, std::size_t(scene.mappingBound() + 3), childrenOffsets}, + {NoInit, parentFieldSize, children}, + /* List of parents to process. Can't reuse mappingDestination because + this includes one more element for root objects. */ + {NoInit, parentFieldSize + 1, parentsToProcess} + }; + + /* Convert the parent list to a child list to sort them toplogically. + Explicit slice() template parameters needed by GCC 4.8 and MSVC 2015 */ + scene.parentsInto( + stridedArrayView(parents).slice(&Containers::Pair::first), + stridedArrayView(parents).slice(&Containers::Pair::second) + ); /* Children offset for each node including root. First calculate the count of children for each, skipping the first element (parent.second() can be -1, accounting for that as well)... */ - Containers::Array childrenOffsets{DirectInit, scene.mappingBound() + 3, 0u}; for(const Containers::Pair& parent: parents) { CORRADE_INTERNAL_ASSERT(parent.first() < scene.mappingBound() && (parent.second() == -1 || UnsignedInt(parent.second()) < scene.mappingBound())); ++childrenOffsets[parent.second() + 2]; @@ -84,7 +103,6 @@ void orderClusterParentsInto(const Trade::SceneData& scene, const Containers::St now `[childrenOffsets[i + 1], childrenOffsets[i + 2])` contains a range in which the `children` array below contains a list of children for `i`. */ - Containers::Array children{NoInit, parents.size()}; for(const Containers::Pair& parent: parents) children[childrenOffsets[parent.second() + 2]++] = parent.first(); @@ -92,7 +110,6 @@ void orderClusterParentsInto(const Trade::SceneData& scene, const Containers::St other) and build a list of (id, parent id) where a parent is always before its children */ std::size_t outputOffset = 0; - Containers::Array parentsToProcess{NoInit, parents.size() + 1}; parentsToProcess[0] = -1; for(std::size_t i = 0; i != outputOffset + 1; ++i) { const Int objectId = parentsToProcess[i];