From 9149b3579a2205d496378c5a9e37f2005a8fa228 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Wed, 13 Mar 2019 10:53:28 +0100 Subject: [PATCH] ENH: PtrList and PtrListOps improvements - PtrDynList support for move append list: can be used to concatenate pointer lists into a single one - include resize in PtrDynList squeezeNull as being a natural combination - support sorting operations for pointer lists (PtrListOps) --- applications/test/PtrList/Test-PtrList.C | 36 ++++- .../containers/Lists/ListOps/ListOps.C | 9 +- .../containers/Lists/ListOps/ListOps.H | 5 + .../Lists/ListOps/ListOpsTemplates.C | 5 +- .../PtrLists/PtrDynList/PtrDynList.H | 16 +- .../PtrLists/PtrDynList/PtrDynListI.H | 51 +++++- .../PtrLists/PtrListDetail/PtrListDetail.C | 21 ++- .../PtrLists/PtrListDetail/PtrListDetail.H | 5 +- .../PtrLists/PtrListOps/PtrListOps.H | 149 ++++++++++++++++++ .../PtrLists/PtrListOps/PtrListOpsTemplates.C | 92 +++++++++++ .../containers/PtrLists/UPtrList/UPtrList.C | 75 ++++++++- .../containers/PtrLists/UPtrList/UPtrList.H | 13 +- 12 files changed, 458 insertions(+), 19 deletions(-) create mode 100644 src/OpenFOAM/containers/PtrLists/PtrListOps/PtrListOps.H create mode 100644 src/OpenFOAM/containers/PtrLists/PtrListOps/PtrListOpsTemplates.C diff --git a/applications/test/PtrList/Test-PtrList.C b/applications/test/PtrList/Test-PtrList.C index e09cde98168..2d7edcf8280 100644 --- a/applications/test/PtrList/Test-PtrList.C +++ b/applications/test/PtrList/Test-PtrList.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2018-2019 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- | Copyright (C) 2011 OpenFOAM Foundation @@ -36,6 +36,7 @@ Description #include "SLPtrList.H" #include "plane.H" #include "DynamicList.H" +#include "PtrListOps.H" using namespace Foam; @@ -598,6 +599,39 @@ int main(int argc, char *argv[]) Info<<"After pruning nullptr entries" << endl; report(Info, dynPlanes, true); + + { + PtrDynList<plane> dynPlanes2; + + dynPlanes2.append(new plane(vector::one, vector::one)); + dynPlanes2.append(new plane(vector(1,2,3), vector::one)); + dynPlanes2.append(nullptr); + + dynPlanes2.set(6, new plane(vector(2,2,1), vector::one)); + dynPlanes2.set(10, new plane(Zero, vector::one)); + + labelList order; + sortedOrder(dynPlanes2, order); + Info<< "sorted order: " << flatOutput(order) << nl; + + sortedOrder(dynPlanes2, order, PtrListOps::greater<plane>(dynPlanes2)); + Info<< "sorted order: " << flatOutput(order) << nl; + + sort(dynPlanes2); + // dynPlanes2.squeezeNull(); + + Info<<"Append" << endl; + report(Info, dynPlanes2, false); + + dynPlanes.append(std::move(dynPlanes2)); + + Info<<"Result" << endl; + report(Info, dynPlanes, false); + + Info<<"From" << endl; + report(Info, dynPlanes2, false); + } + Info<<"free()" << endl; dynPlanes.free(); diff --git a/src/OpenFOAM/containers/Lists/ListOps/ListOps.C b/src/OpenFOAM/containers/Lists/ListOps/ListOps.C index f13c69d7b05..fc78d43f1a9 100644 --- a/src/OpenFOAM/containers/Lists/ListOps/ListOps.C +++ b/src/OpenFOAM/containers/Lists/ListOps/ListOps.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2018-2019 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- | Copyright (C) 2011-2015 OpenFOAM Foundation @@ -26,6 +26,7 @@ License \*---------------------------------------------------------------------------*/ #include "ListOps.H" +#include <numeric> // * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // @@ -159,4 +160,10 @@ void Foam::inplaceReorder } +void Foam::ListOps::identity(labelList& map, label start) +{ + std::iota(map.begin(), map.end(), start); +} + + // ************************************************************************* // diff --git a/src/OpenFOAM/containers/Lists/ListOps/ListOps.H b/src/OpenFOAM/containers/Lists/ListOps/ListOps.H index 8f8159094d1..8fd5b87bc67 100644 --- a/src/OpenFOAM/containers/Lists/ListOps/ListOps.H +++ b/src/OpenFOAM/containers/Lists/ListOps/ListOps.H @@ -584,6 +584,11 @@ struct greater }; +//- Set identity map with (map[i] == i) +// Optionally with an alternative start index, so that (map[i] == i+start) +void identity(labelList& map, label start=0); + + //- Find index of the first occurrence that satisfies the predicate. // When start is specified, any occurrences before start are ignored. // Linear search. diff --git a/src/OpenFOAM/containers/Lists/ListOps/ListOpsTemplates.C b/src/OpenFOAM/containers/Lists/ListOps/ListOpsTemplates.C index 577d63a555e..a7ebc7b2e09 100644 --- a/src/OpenFOAM/containers/Lists/ListOps/ListOpsTemplates.C +++ b/src/OpenFOAM/containers/Lists/ListOps/ListOpsTemplates.C @@ -349,10 +349,7 @@ void Foam::sortedOrder order.resize(len); } - for (label i=0; i < len; ++i) - { - order[i] = i; // identity - } + ListOps::identity(order); Foam::stableSort(order, comp); } diff --git a/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynList.H b/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynList.H index 39b1a27fe88..beef999e1fd 100644 --- a/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynList.H +++ b/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynList.H @@ -137,15 +137,27 @@ public: //- Shrink the allocated space to the number of elements used. inline void shrink(); + //- Squeeze out intermediate nullptr entries in the list of pointers + //- and adjust the addressable size accordingly. + // \return the number of non-null entries + inline label squeezeNull(); + //- Append an element to the end of the list inline void append(T* ptr); - //- Append an element to the end of the list + //- Move append an element to the end of the list inline void append(const autoPtr<T>& aptr); - //- Append an element to the end of the list + //- Move or clone append a tmp to the end of the list inline void append(const tmp<T>& tptr); + //- Move append another list to the end of this list. + inline void append(PtrList<T>&& other); + + //- Move append another list to the end of this list. + template<int AnySizeMin> + inline void append(PtrDynList<T, AnySizeMin>&& other); + //- Remove and return the top element inline autoPtr<T> remove(); diff --git a/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynListI.H b/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynListI.H index d31a69a8504..2b7a45f9173 100644 --- a/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynListI.H +++ b/src/OpenFOAM/containers/PtrLists/PtrDynList/PtrDynListI.H @@ -216,6 +216,15 @@ inline void Foam::PtrDynList<T, SizeMin>::shrink() } +template<class T, int SizeMin> +inline Foam::label Foam::PtrDynList<T, SizeMin>::squeezeNull() +{ + const label newLen = UPtrList<T>::squeezeNull(); + resize(newLen); + return newLen; +} + + template<class T, int SizeMin> inline void Foam::PtrDynList<T, SizeMin>::append(T* ptr) { @@ -228,14 +237,52 @@ inline void Foam::PtrDynList<T, SizeMin>::append(T* ptr) template<class T, int SizeMin> inline void Foam::PtrDynList<T, SizeMin>::append(const autoPtr<T>& aptr) { - return this->append(const_cast<autoPtr<T>&>(aptr).release()); + this->append(const_cast<autoPtr<T>&>(aptr).release()); } template<class T, int SizeMin> inline void Foam::PtrDynList<T, SizeMin>::append(const tmp<T>& tptr) { - return this->append(tptr.ptr()); + this->append(tptr.ptr()); +} + + +template<class T, int SizeMin> +inline void Foam::PtrDynList<T, SizeMin>::append(PtrList<T>&& other) +{ + const label idx = this->size(); + const label len = other.size(); + + resize(idx + len); + + for (label i=0; i < len; ++i) + { + set(idx + i, other.release(i)); // moves pointer + } + + other.clear(); +} + + +template<class T, int SizeMin> +template<int AnySizeMin> +inline void Foam::PtrDynList<T, SizeMin>::append +( + PtrDynList<T, AnySizeMin>&& other +) +{ + const label idx = this->size(); + const label len = other.size(); + + resize(idx + len); + + for (label i=0; i < len; ++i) + { + set(idx + i, other.release(i)); // moves pointer + } + + other.clearStorage(); // Ensure capacity=0 } diff --git a/src/OpenFOAM/containers/PtrLists/PtrListDetail/PtrListDetail.C b/src/OpenFOAM/containers/PtrLists/PtrListDetail/PtrListDetail.C index 96d2a9aaf83..c43d4801ef9 100644 --- a/src/OpenFOAM/containers/PtrLists/PtrListDetail/PtrListDetail.C +++ b/src/OpenFOAM/containers/PtrLists/PtrListDetail/PtrListDetail.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2018-2019 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -45,6 +45,25 @@ Foam::label Foam::Detail::PtrListDetail<T>::count() const } +template<class T> +Foam::label Foam::Detail::PtrListDetail<T>::findNull() const +{ + label idx = 0; + + for (const T* ptr : *this) + { + if (!ptr) + { + return idx; + } + + ++idx; + } + + return -1; +} + + template<class T> void Foam::Detail::PtrListDetail<T>::free() { diff --git a/src/OpenFOAM/containers/PtrLists/PtrListDetail/PtrListDetail.H b/src/OpenFOAM/containers/PtrLists/PtrListDetail/PtrListDetail.H index 5405699d034..77da6ebd48b 100644 --- a/src/OpenFOAM/containers/PtrLists/PtrListDetail/PtrListDetail.H +++ b/src/OpenFOAM/containers/PtrLists/PtrListDetail/PtrListDetail.H @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2018-2019 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -86,6 +86,9 @@ public: //- Return the count of non-nullptr entries label count() const; + //- Locate the first null entry, -1 if there are not any + label findNull() const; + //- Delete the allocated entries, but retain the list size. void free(); diff --git a/src/OpenFOAM/containers/PtrLists/PtrListOps/PtrListOps.H b/src/OpenFOAM/containers/PtrLists/PtrListOps/PtrListOps.H new file mode 100644 index 00000000000..a7324a9a949 --- /dev/null +++ b/src/OpenFOAM/containers/PtrLists/PtrListOps/PtrListOps.H @@ -0,0 +1,149 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2019 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +InNamespace + Foam + +Description + Functions to operate on Pointer Lists. + +Namespace + Foam::PtrListOps + +Description + Various utility functions to operate on Pointer Lists. + +SourceFiles + PtrListOpsTemplates.C + +\*---------------------------------------------------------------------------*/ + +#ifndef PtrListOps_H +#define PtrListOps_H + +#include "PtrList.H" +#include "ListOps.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +//- Generate (stable) sort order for the list +template<class T> +void sortedOrder(const UPtrList<T>& input, labelList& order); + +//- Generate (stable) sort order for the list, +//- using the specified list compare predicate +template<class T, class ListComparePredicate> +void sortedOrder +( + const UPtrList<T>& input, + labelList& order, + const ListComparePredicate& comp +); + + +//- Inplace (stable) sorting of pointer list. +template<class T> +void sort(UPtrList<T>& list); + +//- Inplace (stable) sorting of pointer list. +template<class T, class Compare> +void sort(UPtrList<T>& list, const Compare& comp); + +//- Inplace shuffle of pointer list. +template<class T> +void shuffle(UPtrList<T>& list); + + +/*---------------------------------------------------------------------------*\ + Namespace PtrListOps Declaration +\*---------------------------------------------------------------------------*/ + +namespace PtrListOps +{ + +// Public Classes + +//- A UPtrList compare binary predicate for normal sort. +// Null entries sort to the end +template<class T> +struct less +{ + const UPtrList<T>& values; + + less(const UPtrList<T>& list) + : + values(list) + {} + + bool operator()(const label a, const label b) const + { + const T* const ptr1 = values(a); + const T* const ptr2 = values(b); + + return (ptr1 && ptr2) ? (*ptr1 < *ptr2) : !ptr2; + } +}; + + +//- A UPtrList compare binary predicate for reverse sort. +// Null entries sort to the end +template<class T> +struct greater +{ + const UPtrList<T>& values; + + greater(const UPtrList<T>& list) + : + values(list) + {} + + bool operator()(const label a, const label b) const + { + const T* const ptr1 = values(a); + const T* const ptr2 = values(b); + + return (ptr1 && ptr2) ? (*ptr2 < *ptr1) : !ptr2; + } +}; + + +} // End namespace ListOps + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository + #include "PtrListOpsTemplates.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/OpenFOAM/containers/PtrLists/PtrListOps/PtrListOpsTemplates.C b/src/OpenFOAM/containers/PtrLists/PtrListOps/PtrListOpsTemplates.C new file mode 100644 index 00000000000..86a129e87b5 --- /dev/null +++ b/src/OpenFOAM/containers/PtrLists/PtrListOps/PtrListOpsTemplates.C @@ -0,0 +1,92 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2019 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "PtrListOps.H" + +// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // + +template<class T> +void Foam::sortedOrder +( + const UPtrList<T>& input, + labelList& order +) +{ + sortedOrder(input, order, typename PtrListOps::less<T>(input)); +} + + +template<class T, class ListComparePredicate> +void Foam::sortedOrder +( + const UPtrList<T>& input, + labelList& order, + const ListComparePredicate& comp +) +{ + const label len = input.size(); + + // List lengths must be identical + if (order.size() != len) + { + // Avoid copying elements, they are overwritten anyhow + order.clear(); + order.resize(len); + } + + ListOps::identity(order); + + Foam::stableSort(order, comp); +} + + +template<class T> +void Foam::sort(UPtrList<T>& list) +{ + labelList order; + sortedOrder(list, order); + list.sortOrder(order, false); // false = allow nullptr +} + + +template<class T, class Compare> +void Foam::sort(UPtrList<T>& list, const Compare& comp) +{ + labelList order; + sortedOrder(list, order, comp); + list.sortOrder(order, false); // false = allow nullptr +} + + +template<class T> +void Foam::shuffle(UPtrList<T>& list) +{ + labelList order = identity(list.size()); + Foam::shuffle(order); + list.sortOrder(order, false); // false = allow nullptr +} + + +// ************************************************************************* // diff --git a/src/OpenFOAM/containers/PtrLists/UPtrList/UPtrList.C b/src/OpenFOAM/containers/PtrLists/UPtrList/UPtrList.C index 2e5d1887ac6..78bdddee7f3 100644 --- a/src/OpenFOAM/containers/PtrLists/UPtrList/UPtrList.C +++ b/src/OpenFOAM/containers/PtrLists/UPtrList/UPtrList.C @@ -65,7 +65,11 @@ Foam::label Foam::UPtrList<T>::squeezeNull() template<class T> -void Foam::UPtrList<T>::reorder(const labelUList& oldToNew) +void Foam::UPtrList<T>::reorder +( + const labelUList& oldToNew, + const bool testNull +) { const label len = this->size(); @@ -97,19 +101,82 @@ void Foam::UPtrList<T>::reorder(const labelUList& oldToNew) { FatalErrorInFunction << "reorder map is not unique; element " << idx - << " already set for type " << typeid(T).name() + << " already used for type " << typeid(T).name() << abort(FatalError); } newList[idx] = ptrs_[i]; } // Verify that all pointers were indeed set + if (testNull) + { + const label idx = newList.findNull(); + if (idx >= 0) + { + FatalErrorInFunction + << "Element " << idx << " not set after reordering." << nl + << abort(FatalError); + } + } + + ptrs_.transfer(newList); +} + + +template<class T> +void Foam::UPtrList<T>::sortOrder +( + const labelUList& order, + const bool testNull +) +{ + const label len = this->size(); + + if (order.size() != len) + { + FatalErrorInFunction + << "Size of map (" << order.size() + << ") not equal to list size (" << len + << ") for type " << typeid(T).name() << nl + << abort(FatalError); + } + + Detail::PtrListDetail<T> newList(len); + Detail::PtrListDetail<T> guard(len); + for (label i=0; i<len; ++i) { - if (!newList[i]) + const label idx = order[i]; + + if (idx < 0 || idx >= len) + { + FatalErrorInFunction + << "Illegal index " << idx << nl + << "Valid indices are [0," << len << ") for type " + << typeid(T).name() << nl + << abort(FatalError); + } + + if (guard[idx]) + { + FatalErrorInFunction + << "order map is not unique; element " << idx + << " already used for type " << typeid(T).name() + << abort(FatalError); + } + + guard[idx] = ptrs_[idx]; + newList[i] = ptrs_[idx]; + } + + // Verify that all pointers were indeed set + if (testNull) + { + const label idx = newList.findNull(); + if (idx >= 0) { FatalErrorInFunction - << "Element " << i << " not set after reordering." << nl + << "Element " << idx << " not set after reordering." << nl << abort(FatalError); } } diff --git a/src/OpenFOAM/containers/PtrLists/UPtrList/UPtrList.H b/src/OpenFOAM/containers/PtrLists/UPtrList/UPtrList.H index a18177fbc57..c97167eedfc 100644 --- a/src/OpenFOAM/containers/PtrLists/UPtrList/UPtrList.H +++ b/src/OpenFOAM/containers/PtrLists/UPtrList/UPtrList.H @@ -57,7 +57,7 @@ SourceFiles namespace Foam { -// Forward declarations +// Forward Declarations template<class T> class PtrList; template<class T> class UPtrList; @@ -191,8 +191,15 @@ public: // No-op if the new pointer value is identical to the current content. inline T* set(const label i, T* ptr); - //- Reorder elements. Reordering must be unique (ie, shuffle). - void reorder(const labelUList& oldToNew); + //- Reorder elements. + //- Reordering must be unique (ie, shuffle). + // Optionally verify that all pointers have been set. + void reorder(const labelUList& oldToNew, const bool testNull = true); + + //- Reorder elements according to new order mapping (newToOld). + //- Reordering must be unique (ie, shuffle). + // Optionally verify that all pointers have been set. + void sortOrder(const labelUList& order, const bool testNull = true); // Member Operators -- GitLab