Commit 049617d0 authored by Mark Olesen's avatar Mark Olesen
Browse files

ENH: update List and DynamicList methods (issue #595)

- improve functional compatibility with DynList (remove methods)
  * eg, remove an element from any position in a DynamicList
  * reduce the number of template parameters
  * remove/subset regions of DynamicList

- propagate Swap template specializations for lists, hashtables

- move construct/assignment to various containers.

- add find/found methods for FixedList and UList for a more succinct
  (and clearer?) usage than the equivalent global findIndex() function.

- simplify List_FOR_ALL loops
parent 68e75338
......@@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -27,7 +27,10 @@ Description
#include "DynamicList.H"
#include "IOstreams.H"
#include "FlatOutput.H"
#include "ListOps.H"
#include "labelRange.H"
#include "labelIndList.H"
using namespace Foam;
......@@ -44,15 +47,15 @@ void printInfo
{
Info<< " size=\"" << lst.size() << "\"";
}
Info<< ">" << lst << "</" << tag << ">" << endl;
Info<< ">" << nl << flatOutput(lst) << nl << "</" << tag << ">" << endl;
}
template<class T, unsigned SizeInc, unsigned SizeMult, unsigned SizeDiv>
template<class T, int SizeMin>
void printInfo
(
const word& tag,
const DynamicList<T, SizeInc, SizeMult, SizeDiv>& lst,
const DynamicList<T, SizeMin>& lst,
const bool showSize = false
)
{
......@@ -62,7 +65,7 @@ void printInfo
Info<< " size=\"" << lst.size()
<< "\" capacity=\"" << lst.capacity() << "\"";
}
Info<< ">" << lst << "</" << tag << ">" << endl;
Info<< ">" << nl << flatOutput(lst) << nl << "</" << tag << ">" << endl;
}
......@@ -71,7 +74,7 @@ void printInfo
int main(int argc, char *argv[])
{
List<DynamicList<label, 1, 0>> ldl(2);
List<DynamicList<label>> ldl(2);
ldl[0](0) = 0;
ldl[0](2) = 2;
......@@ -89,7 +92,7 @@ int main(int argc, char *argv[])
ldl[1] = 3;
Info<< "<ldl>" << ldl << "</ldl>" << nl << "sizes: ";
Info<< "<ldl>" << flatOutput(ldl) << "</ldl>" << nl << "sizes: ";
forAll(ldl, i)
{
Info<< " " << ldl[i].size() << "/" << ldl[i].capacity();
......@@ -100,7 +103,7 @@ int main(int argc, char *argv[])
ll[0].transfer(ldl[0]);
ll[1].transfer(ldl[1].shrink());
Info<< "<ldl>" << ldl << "</ldl>" << nl << "sizes: ";
Info<< "<ldl>" << flatOutput(ldl) << "</ldl>" << nl << "sizes: ";
forAll(ldl, i)
{
Info<< " " << ldl[i].size() << "/" << ldl[i].capacity();
......@@ -111,18 +114,18 @@ int main(int argc, char *argv[])
// test the transfer between DynamicLists
DynamicList<label, 1, 0> dlA
DynamicList<label> dlA
{
0, 1, 2, 3, 4
};
dlA.append({ 5, 6 });
dlA = { 1, 2, 4 };
DynamicList<label, 1, 0> dlB;
DynamicList<label> dlB;
dlA.setCapacity(10);
Info<< "<dlA>" << dlA << "</dlA>" << nl << "sizes: "
Info<< "<dlA>" << flatOutput(dlA) << "</dlA>" << nl << "sizes: "
<< " " << dlA.size() << "/" << dlA.capacity() << endl;
dlB.transfer(dlA);
......@@ -132,9 +135,9 @@ int main(int argc, char *argv[])
dlB[6] = 6;
Info<< "Transferred to dlB" << endl;
Info<< "<dlA>" << dlA << "</dlA>" << nl << "sizes: "
Info<< "<dlA>" << flatOutput(dlA) << "</dlA>" << nl << "sizes: "
<< " " << dlA.size() << "/" << dlA.capacity() << endl;
Info<< "<dlB>" << dlB << "</dlB>" << nl << "sizes: "
Info<< "<dlB>" << flatOutput(dlB) << "</dlB>" << nl << "sizes: "
<< " " << dlB.size() << "/" << dlB.capacity() << endl;
// try with a normal list:
......@@ -166,7 +169,7 @@ int main(int argc, char *argv[])
// check allocation granularity
DynamicList<label, 6, 0> dlC;
DynamicList<label> dlC;
printInfo("dlC", dlC, true);
......@@ -227,15 +230,89 @@ int main(int argc, char *argv[])
dlE2[i] *= 10;
}
UIndirectList<label> uil
labelUIndList uil
(
dlE2, addr
);
Info<< "use UIndirectList " << uil << " remapped from " << dlE2 << endl;
dlE4 = uil;
printInfo("dlE4", dlE4, true);
}
}
{
Info<< nl << "Test moving:" << nl;
labelList input1 = identity(15);
labelList input2 = identity(15);
inplaceReverseList(input2);
DynamicList<label> list1(std::move(input1));
DynamicList<label> list2;
Info<< "move construct:" << nl
<< "input: " << flatOutput(input1) << nl
<< "list: " << flatOutput(list1) << endl;
list1 = std::move(input2);
Info<< "move assignment:" << nl
<< "input: " << flatOutput(input2) << nl
<< "list: " << flatOutput(list1) << endl;
list2 = std::move(list1);
Info<< "list in: " << flatOutput(list1) << nl
<< "list out: " << flatOutput(list2) << endl;
input2 = std::move(identity(15));
list2 = std::move(input2);
Info<< "list in: " << flatOutput(input2) << nl
<< "list out: " << flatOutput(list2) << endl;
input1 = identity(15);
input2 = identity(15);
inplaceReverseList(input2);
Info<< "test move-append with "
<< flatOutput(input1) << " and " << flatOutput(input2) << endl;
list2.append(std::move(list1));
list2.append(std::move(input1));
list2.append(std::move(input2));
Info<< "result: " << flatOutput(list2) << nl
<< "inputs: " << flatOutput(list1) << " / "
<< flatOutput(input1) << " / "
<< flatOutput(input2) << nl;
input1 = list2;
Info<< nl << "test subset/remove with "
<< flatOutput(input1) << endl;
for
(
const labelRange range :
{
labelRange(-10, 8), // invalid range
labelRange(40, 18), // trailing portion
labelRange(-5, 10), // leading portion
labelRange(10, 8), // mid-portion
labelRange(0, input1.size()), // everything
}
)
{
list1 = input1;
list2 = input1;
list1.remove(range);
list2.subset(range);
Info<< "input = " << flatOutput(input1) << nl
<< "remove " << range << " = " << flatOutput(list1) << nl
<< "subset " << range << " = " << flatOutput(list2) << nl;
}
}
Info<< "\nEnd\n";
......
Test-Field.C
EXE = $(FOAM_USER_APPBIN)/Test-Field
/* EXE_INC = -I$(LIB_SRC)/cfdTools/include */
/* EXE_LIBS = -lfiniteVolume */
#include "Test-Field.H"
int main()
{
Vector<double> v1(1, 2);
Vector<double> v2(2, 3);
std::cout << v1 + v2;
return 0;
}
#include <iostream>
template<class C>
class Vector;
template<class C>
Vector<C> operator+(const Vector<C>& v1, const Vector<C>& v2);
template<class C>
std::ostream& operator<<(std::ostream& os, const Vector<C>& v);
/*---------------------------------------------------------------------------*\
Class Vector Declaration
\*---------------------------------------------------------------------------*/
template<class C>
class Vector
{
double X, Y;
public:
inline Vector(const double x, const double y);
C x() const
{
return X;
}
C y() const
{
return Y;
}
friend Vector<C> operator+ <C>(const Vector<C>& v1, const Vector<C>& v2);
friend std::ostream& operator<<(std::ostream& os, const Vector<C>& v)
{
os << v.X << '\t' << v.Y << '\n';
return os;
}
};
template<class C>
inline Vector<C>::Vector(const double x, const double y)
{
X = x;
Y = y;
}
template<class C>
inline Vector<C> operator+(const Vector<C>& v1, const Vector<C>& v2)
{
return Vector<C>(v1.X+v2.X, v1.Y+v2.Y);
}
......@@ -35,6 +35,7 @@ See also
#include "argList.H"
#include "FixedList.H"
#include "Fstream.H"
#include "List.H"
#include "IPstream.H"
#include "OPstream.H"
......@@ -47,36 +48,44 @@ int main(int argc, char *argv[])
{
argList args(argc, argv);
FixedList<label, 4> list;
list[0] = 1;
list[1] = 2;
list[2] = 3;
list[3] = 4;
{
FixedList<label, 4> list1{1, 2, 3, 4};
Info<< "list:" << list
<< " hash:" << FixedList<label, 4>::Hash<>()(list) << endl;
Info<< "list1:" << list1
<< " hash:" << FixedList<label, 4>::Hash<>()(list1) << endl;
label a[4] = {0, 1, 2, 3};
FixedList<label, 4> list2(a);
label a[4] = {0, 1, 2, 3};
FixedList<label, 4> list2(a);
Info<< "list2:" << list2
<< " hash:" << FixedList<label, 4>::Hash<>()(list2) << endl;
Info<< "list2:" << list2
<< " hash:" << FixedList<label, 4>::Hash<>()(list2) << endl;
// Using FixedList for content too
{
List<FixedList<label, 4>> twolists{list, list2};
Info<<"List of FixedList: " << flatOutput(twolists) << endl;
sort(twolists);
// outer-sort only
Info<<"sorted FixedList : " << flatOutput(twolists) << endl;
}
// Using FixedList for content too
{
List<FixedList<label, 4>> twolists{list1, list2};
Info<<"List of FixedList: " << flatOutput(twolists) << endl;
sort(twolists);
// outer-sort only
Info<<"sorted FixedList : " << flatOutput(twolists) << endl;
}
Info<< "list: " << list << nl
<< "list2: " << list2 << endl;
list.swap(list2);
Info<< "Swapped via the swap() method" << endl;
Info<< "list: " << list << nl
<< "list2: " << list2 << endl;
Info<< "====" << nl
<< "Test swap" << nl;
Info<< "list1: " << list1 << nl
<< "list2: " << list2 << endl;
list1.swap(list2);
Info<< "The swap() method" << endl;
Info<< "list1: " << list1 << nl
<< "list2: " << list2 << endl;
Swap(list1, list2);
Info<< "The Swap() function" << endl;
Info<< "list1: " << list1 << nl
<< "list2: " << list2 << endl;
Info<< "====" << nl;
}
List<label> list3{0, 1, 2, 3};
FixedList<label, 4> list4(list3.begin(), list3.end());
......
Test-FixedList2.C
EXE = $(FOAM_USER_APPBIN)/Test-FixedList2
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 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/>.
Application
Test-FixedList2
Description
Test speeds, usability of some List/FixedList operations
See also
Foam::FixedList
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "FixedList.H"
#include "labelList.H"
#include "vectorList.H"
#include "ListOps.H"
#include "IFstream.H"
#include "OFstream.H"
#include "cpuTime.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
using namespace Foam;
template<class ListType>
void runSwapTest
(
const label nLoops,
ListType& list1,
ListType& list2
)
{
cpuTime timer;
Info<<"Swapping fixed lists with " << list1.size() << " elements\n";
Info<< "input 1: " << list1.first() << nl;
Info<< "input 2: " << list2.first() << nl;
// Should be zero, since this is a compile-time value
Info<< "Perform " << nLoops << " swaps..." << nl;
for (label iLoop = 0; iLoop < nLoops; ++iLoop)
{
Swap(list1, list2);
}
Info<< "output 1: " << list1.first() << nl;
Info<< "output 2: " << list2.first() << nl;
Info<< "Operation took"
<< " " << timer.cpuTimeIncrement() << " s\n\n";
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
argList::addBoolOption("label");
argList::addBoolOption("float");
argList::addBoolOption("vector");
argList::addBoolOption("labelList");
argList::addBoolOption("vectorList");
argList::addBoolOption("fixedLabel");
argList::addBoolOption("fixedLabelList");
argList args(argc, argv);
if (args.options().empty())
{
Info<< nl << "Specify an option! " << nl << endl;
}
if (args.optionFound("label"))
{
FixedList<label, 100000> list1(1);
FixedList<label, 100000> list2(0);
runSwapTest(1000001, list1, list2);
}
if (args.optionFound("float"))
{
FixedList<double, 100000> list1(1.0);
FixedList<double, 100000> list2(0.0);
runSwapTest(1000001, list1, list2);
}
if (args.optionFound("vector"))
{
FixedList<vector, 100000> list1(vector::one);
FixedList<vector, 100000> list2(vector::zero);
runSwapTest(100001, list1, list2);
}
if (args.optionFound("labelList"))
{
typedef labelList testType;
testType initVal(500);
initVal = 0;
FixedList<testType, 1000> list1(initVal);
initVal = 1;
FixedList<testType, 1000> list2(initVal);
runSwapTest(100001, list1, list2);
}
if (args.optionFound("vectorList"))
{
typedef vectorList testType;
testType initVal(500);
initVal = vector::zero;
FixedList<testType, 1000> list1(initVal);
initVal = vector::one;
FixedList<testType, 1000> list2(initVal);
runSwapTest(100001, list1, list2);
}
if (args.optionFound("fixedLabel"))
{
typedef FixedList<label,1000> testType;
testType initVal;
initVal = 0;
FixedList<testType, 1000> list1(initVal);
initVal = 1;
FixedList<testType, 1000> list2(initVal);
runSwapTest(100001, list1, list2);
}
if (args.optionFound("fixedLabelList"))
{
typedef labelList testType;
typedef FixedList<testType,10> containerType;
testType tinitVal(500);
containerType initVal;
tinitVal = 0;
initVal = tinitVal;
FixedList<containerType, 1000> list1(initVal);
tinitVal = 1;
initVal = tinitVal;
FixedList<containerType, 1000> list2(initVal);
runSwapTest(10001, list1, list2);
}
Info<< nl << "Done" << nl << endl;
return 0;
}
// ************************************************************************* //
......@@ -31,6 +31,7 @@ Description
#include "fvCFD.H"
#include "Function1.H"
#include "scalarIndList.H"
#include "IOdictionary.H"
#include "linearInterpolationWeights.H"
#include "splineInterpolationWeights.H"
......@@ -69,7 +70,7 @@ int main(int argc, char *argv[])
scalar baseSum = interpolator.weightedSum
(
weights,
UIndirectList<scalar>(values, indices)