Commit 52b36f84 authored by Mark Olesen's avatar Mark Olesen
Browse files

ENH: cleanup tmp class (issue #639)

Improve alignment of its behaviour with std::shared_ptr

  - element_type typedef
  - swap, reset methods

* additional reference access methods:

cref()
    returns a const reference, synonymous with operator().
    This provides a more verbose alternative to using the '()' operator
    when that is desired.

        Mnemonic: a const form of 'ref()'

constCast()
    returns a non-const reference, regardless if the underlying object
    itself is a managed pointer or a const object.
    This is similar to ref(), but more permissive.

        Mnemonic: const_cast<>

    Using the constCast() method greatly reduces the amount of typing
    and reading. And since the data type is already defined via the tmp
    template parameter, the type deduction is automatically known.

    Previously,

        const tmp<volScalarField>& tfld;

        const_cast<volScalarField&>(tfld()).rename("name");
        volScalarField& fld = const_cast<volScalarField&>(tfld());

    Now,

        tfld.constCast().rename("name");
        auto& fld = tfld.constCast();

--

BUG: attempts to move tmp value that may still be shared.

- old code simply checked isTmp() to decide if the contents could be
  transfered. However, this means that the content of a shared tmp
  would be removed, leaving other instances without content.

* movable() method checks that for a non-null temporary that is
  unique (not shared).
parent 660f3e54
Test-tmp.C
EXE = $(FOAM_USER_APPBIN)/Test-tmp
......@@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2018 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -22,10 +22,10 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Application
tmpFieldTest
Test-tmp
Description
Tests for possible memory leaks in the tmp<Field> algebra.
Tests for possible memory leaks in the tmp (and tmp<Field> algebra).
\*---------------------------------------------------------------------------*/
......@@ -33,19 +33,50 @@ Description
using namespace Foam;
struct myScalarField : public scalarField
{
using scalarField::scalarField;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main()
{
scalarField f1(1000000, 1.0), f2(1000000, 2.0), f3(1000000, 3.0);
{
scalarField f1(1000000, 1.0), f2(1000000, 2.0), f3(1000000, 3.0);
for (int iter=0; iter < 50; ++iter)
{
f1 = f2 + f3 + f2 + f3;
}
Info<<"f1 = " << f1 << nl;
}
{
tmp<scalarField> tfld1 = tmp<scalarField>::New(20, Zero);
Info<< "tmp refCount = " << tfld1->count() << nl;
if (tfld1.valid())
{
Info<<"tmp: " << tfld1() << nl;
}
}
for (;;)
{
f1 = f2 + f3 + f2 + f3;
tmp<scalarField> tfld2 =
tmp<scalarField>::NewFrom<myScalarField>(20, Zero);
Info<< "tmp refCount = " << tfld2->count() << nl;
if (tfld2.valid())
{
Info<<"tmp: " << tfld2() << nl;
}
}
Info<< "end" << endl;
Info<< "\nEnd" << endl;
}
......
Test-tmpField.C
EXE = $(FOAM_USER_APPBIN)/Test-tmpField
......@@ -217,12 +217,8 @@ DimensionedField<Type, GeoMesh>::DimensionedField
const tmp<DimensionedField<Type, GeoMesh>>& tdf
)
:
regIOobject(tdf(), tdf.isTmp()),
Field<Type>
(
const_cast<DimensionedField<Type, GeoMesh>&>(tdf()),
tdf.isTmp()
),
regIOobject(tdf.constCast(), tdf.movable()),
Field<Type>(tdf.constCast(), tdf.movable()),
mesh_(tdf().mesh_),
dimensions_(tdf().dimensions_),
oriented_(tdf().oriented_)
......@@ -318,11 +314,7 @@ DimensionedField<Type, GeoMesh>::DimensionedField
)
:
regIOobject(newName, tdf(), true),
Field<Type>
(
const_cast<DimensionedField<Type, GeoMesh>&>(tdf()),
tdf.isTmp()
),
Field<Type>(tdf.constCast(), tdf.movable()),
mesh_(tdf().mesh_),
dimensions_(tdf().dimensions_),
oriented_(tdf().oriented_)
......@@ -511,7 +503,7 @@ void DimensionedField<Type, GeoMesh>::operator=
const tmp<DimensionedField<Type, GeoMesh>>& tdf
)
{
const DimensionedField<Type, GeoMesh>& df = tdf();
auto& df = tdf.constCast();
// Check for assignment to self
if (this == &df)
......@@ -525,7 +517,7 @@ void DimensionedField<Type, GeoMesh>::operator=
dimensions_ = df.dimensions();
oriented_ = df.oriented();
this->transfer(const_cast<DimensionedField<Type, GeoMesh>&>(df));
this->transfer(df);
tdf.clear();
}
......
......@@ -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) 2018 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -41,32 +41,31 @@ tmp<DimensionedField<TypeR, GeoMesh>> New
const dimensionSet& dimensions
)
{
DimensionedField<TypeR, GeoMesh>& df1 =
const_cast<DimensionedField<TypeR, GeoMesh>&>(tdf1());
if (tdf1.isTmp())
{
auto& df1 = tdf1.constCast();
df1.rename(name);
df1.dimensions().reset(dimensions);
return tdf1;
}
else
{
return tmp<DimensionedField<TypeR, GeoMesh>>
const auto& df1 = tdf1();
return tmp<DimensionedField<TypeR, GeoMesh>>
(
new DimensionedField<TypeR, GeoMesh>
(
new DimensionedField<TypeR, GeoMesh>
IOobject
(
IOobject
(
name,
df1.instance(),
df1.db()
),
df1.mesh(),
dimensions
)
);
}
name,
df1.instance(),
df1.db()
),
df1.mesh(),
dimensions
)
);
}
......@@ -82,7 +81,7 @@ public:
const dimensionSet& dimensions
)
{
const DimensionedField<Type1, GeoMesh>& df1 = tdf1();
const auto& df1 = tdf1();
return tmp<DimensionedField<TypeR, GeoMesh>>
(
......@@ -114,32 +113,31 @@ public:
const dimensionSet& dimensions
)
{
DimensionedField<TypeR, GeoMesh>& df1 =
const_cast<DimensionedField<TypeR, GeoMesh>&>(tdf1());
if (tdf1.isTmp())
{
auto& df1 = tdf1.constCast();
df1.rename(name);
df1.dimensions().reset(dimensions);
return tdf1;
}
else
{
return tmp<DimensionedField<TypeR, GeoMesh>>
const auto& df1 = tdf1();
return tmp<DimensionedField<TypeR, GeoMesh>>
(
new DimensionedField<TypeR, GeoMesh>
(
new DimensionedField<TypeR, GeoMesh>
IOobject
(
IOobject
(
name,
df1.instance(),
df1.db()
),
df1.mesh(),
dimensions
)
);
}
name,
df1.instance(),
df1.db()
),
df1.mesh(),
dimensions
)
);
}
};
......@@ -157,7 +155,7 @@ public:
const dimensionSet& dimensions
)
{
const DimensionedField<Type1, GeoMesh>& df1 = tdf1();
const auto& df1 = tdf1();
return tmp<DimensionedField<TypeR, GeoMesh>>
(
......@@ -190,33 +188,31 @@ public:
const dimensionSet& dimensions
)
{
const DimensionedField<Type1, GeoMesh>& df1 = tdf1();
DimensionedField<TypeR, GeoMesh>& df2 =
const_cast<DimensionedField<TypeR, GeoMesh>&>(tdf2());
if (tdf2.isTmp())
{
auto& df2 = tdf2.constCast();
df2.rename(name);
df2.dimensions().reset(dimensions);
return tdf2;
}
else
{
return tmp<DimensionedField<TypeR, GeoMesh>>
const auto& df1 = tdf1();
return tmp<DimensionedField<TypeR, GeoMesh>>
(
new DimensionedField<TypeR, GeoMesh>
(
new DimensionedField<TypeR, GeoMesh>
IOobject
(
IOobject
(
name,
df1.instance(),
df1.db()
),
df1.mesh(),
dimensions
)
);
}
name,
df1.instance(),
df1.db()
),
df1.mesh(),
dimensions
)
);
}
};
......@@ -234,32 +230,31 @@ public:
const dimensionSet& dimensions
)
{
DimensionedField<TypeR, GeoMesh>& df1 =
const_cast<DimensionedField<TypeR, GeoMesh>&>(tdf1());
if (tdf1.isTmp())
{
auto& df1 = tdf1.constCast();
df1.rename(name);
df1.dimensions().reset(dimensions);
return tdf1;
}
else
{
return tmp<DimensionedField<TypeR, GeoMesh>>
const auto& df1 = tdf1();
return tmp<DimensionedField<TypeR, GeoMesh>>
(
new DimensionedField<TypeR, GeoMesh>
(
new DimensionedField<TypeR, GeoMesh>
IOobject
(
IOobject
(
name,
df1.instance(),
df1.db()
),
df1.mesh(),
dimensions
)
);
}
name,
df1.instance(),
df1.db()
),
df1.mesh(),
dimensions
)
);
}
};
......@@ -277,40 +272,39 @@ public:
const dimensionSet& dimensions
)
{
DimensionedField<TypeR, GeoMesh>& df1 =
const_cast<DimensionedField<TypeR, GeoMesh>&>(tdf1());
DimensionedField<TypeR, GeoMesh>& df2 =
const_cast<DimensionedField<TypeR, GeoMesh>&>(tdf2());
if (tdf1.isTmp())
{
auto& df1 = tdf1.constCast();
df1.rename(name);
df1.dimensions().reset(dimensions);
return tdf1;
}
else if (tdf2.isTmp())
{
auto& df2 = tdf2.constCast();
df2.rename(name);
df2.dimensions().reset(dimensions);
return tdf2;
}
else
{
return tmp<DimensionedField<TypeR, GeoMesh>>
const auto& df1 = tdf1();
return tmp<DimensionedField<TypeR, GeoMesh>>
(
new DimensionedField<TypeR, GeoMesh>
(
new DimensionedField<TypeR, GeoMesh>
IOobject
(
IOobject
(
name,
df1.instance(),
df1.db()
),
df1.mesh(),
dimensions
)
);
}
name,
df1.instance(),
df1.db()
),
df1.mesh(),
dimensions
)
);
}
};
......
......@@ -160,11 +160,7 @@ FieldField<Field, Type>::FieldField(const PtrList<Field<Type>>& tl)
template<template<class> class Field, class Type>
FieldField<Field, Type>::FieldField(const tmp<FieldField<Field, Type>>& tf)
:
PtrList<Field<Type>>
(
const_cast<FieldField<Field, Type>&>(tf()),
tf.isTmp()
)
PtrList<Field<Type>>(tf.constCast(), tf.movable())
{
tf.clear();
}
......
......@@ -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) 2018 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -44,20 +44,18 @@ tmp<FieldField<Field, TypeR>> New
{
return tf1;
}
else
{
tmp<FieldField<Field, TypeR>> rtf
(
FieldField<Field, TypeR>::NewCalculatedType(tf1())
);
if (initRet)
{
rtf.ref() = tf1();
}
tmp<FieldField<Field, TypeR>> rtf
(
FieldField<Field, TypeR>::NewCalculatedType(tf1())
);
return rtf;
if (initRet)
{
rtf.ref() = tf1();
}
return rtf;
}
......@@ -93,13 +91,11 @@ public:
{
return tf1;
}
else
{
return tmp<FieldField<Field, TypeR>>
(
FieldField<Field, TypeR>::NewCalculatedType(tf1())
);
}
return tmp<FieldField<Field, TypeR>>
(
FieldField<Field, TypeR>::NewCalculatedType(tf1())
);
}
};
......@@ -145,13 +141,11 @@ public:
{
return tf2;
}
else
{
return tmp<FieldField<Field, TypeR>>
(
FieldField<Field, TypeR>::NewCalculatedType(tf1())
);
}
return tmp<FieldField<Field, TypeR>>
(
FieldField<Field, TypeR>::NewCalculatedType(tf1())
);
}
};
......@@ -171,13 +165,11 @@ public:
{
return tf1;
}
else
{
return tmp<FieldField<Field, TypeR>>
(
FieldField<Field, TypeR>::NewCalculatedType(tf1())
);
}
return tmp<FieldField<Field, TypeR>>
(
FieldField<Field, TypeR>::NewCalculatedType(tf1())
);
}
};
......@@ -201,13 +193,11 @@ public:
{
return tf2;
}
else
{
return tmp<FieldField<Field, TypeR>>
(
FieldField<Field, TypeR>::NewCalculatedType(tf1())
);
}
return tmp<FieldField<Field, TypeR>>
(
FieldField<Field, TypeR>::NewCalculatedType(tf1())
);
}
};
......
......@@ -256,7 +256,7 @@ Foam::Field<Type>::Field(const UIndirectList<Type>& list)
template<class Type>
Foam::Field<Type>::Field(const tmp<Field<Type>>& tf)
:
List<Type>(const_cast<Field<Type>&>(tf()), tf.isTmp())
List<Type>(tf.constCast(), tf.movable())
{
tf.clear();
}
......
......@@ -44,17 +44,15 @@ tmp<Field<TypeR>> New
{
return tf1;
}
else
{
tmp<Field<TypeR>> rtf(new Field<TypeR>(tf1().size()));
if (initRet)
{
rtf.ref() = tf1();
}
tmp<Field<TypeR>> rtf(new Field<TypeR>(tf1().size()));
return rtf;
if (initRet)
{
rtf.ref() = tf1();
}
return rtf;
}
......@@ -81,10 +79,8 @@ public:
{
return tf1;
}
else
{
return tmp<Field<TypeR>>(new Field<TypeR>(tf1().size()));
}
return tmp<Field<TypeR>>(new Field<TypeR>(tf1().size()));
}
};
......@@ -120,10 +116,8 @@ public:
{
return tf2;
}