Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
amdis
amdis-core
Commits
0689eaae
Commit
0689eaae
authored
Mar 13, 2019
by
Praetorius, Simon
Browse files
Reduce errors and compiletime in tree traversal
parent
efebae43
Changes
19
Hide whitespace changes
Inline
Side-by-side
cmake/modules/AmdisCXXFeatures.cmake
View file @
0689eaae
#include(CheckIncludeFileCXX)
include
(
CheckCXXSourceCompiles
)
#include(CheckCXXSymbolExists)
# fold expressions (a + ...)
check_cxx_source_compiles
(
"
...
...
@@ -30,4 +28,16 @@ check_cxx_source_compiles("
return f<1>();
}
"
AMDIS_HAS_CXX_CONSTEXPR_IF
)
check_cxx_source_compiles
(
"
#include <iostream>
#include <tuple>
int main()
{
auto tup = std::make_tuple(0, 'a', 3.14);
for... (auto elem : tup)
std::cout << elem << std::endl;
}
"
AMDIS_HAS_EXPANSION_STATEMENTS
)
\ No newline at end of file
config.h.cmake
View file @
0689eaae
...
...
@@ -49,6 +49,7 @@
/* some detected compiler features may be used in AMDiS */
#cmakedefine AMDIS_HAS_CXX_FOLD_EXPRESSIONS 1
#cmakedefine AMDIS_HAS_CXX_CONSTEXPR_IF 1
#cmakedefine AMDIS_HAS_EXPANSION_STATEMENTS 1
/* end amdis
Everything below here will be overwritten
...
...
examples/CMakeLists.txt
View file @
0689eaae
...
...
@@ -24,4 +24,4 @@ add_dependencies(examples
stokes1.2d
stokes3.2d
navier_stokes.2d
convection_diffusion.2d
)
\ No newline at end of file
convection_diffusion.2d
)
src/amdis/BoundaryManager.hpp
View file @
0689eaae
...
...
@@ -146,9 +146,10 @@ namespace AMDiS
if
(
!
segment
.
boundary
())
continue
;
auto
index
=
segment
.
boundarySegmentIndex
();
Dune
::
Hybrid
::
ifElse
(
Dune
::
Std
::
is_detected
<
HasBoundaryId
,
Segment
>
{},
[
&
](
auto
id
)
{
boundaryIds_
[
index
]
=
id
(
segment
).
boundaryId
();
});
Dune
::
Hybrid
::
ifElse
(
Dune
::
Std
::
is_detected
<
HasBoundaryId
,
Segment
>
{},
[
&
](
auto
id
)
{
auto
index
=
segment
.
boundarySegmentIndex
();
boundaryIds_
[
index
]
=
id
(
segment
).
boundaryId
();
});
}
}
}
...
...
src/amdis/DataTransfer.inc.hpp
View file @
0689eaae
...
...
@@ -22,8 +22,8 @@
#include
<amdis/Output.hpp>
#include
<amdis/common/ConcurrentCache.hpp>
#include
<amdis/typetree/Traversal.hpp>
#include
<amdis/typetree/TreeContainer.hpp>
#include
<amdis/typetree/Visitor.hpp>
namespace
AMDiS
{
...
...
@@ -135,7 +135,7 @@ namespace AMDiS
auto
lv
=
basis_
->
localView
();
auto
const
&
idSet
=
gv
.
grid
().
localIdSet
();
for
E
ach
L
eaf
N
ode
_
(
lv
.
tree
(),
[
&
](
auto
const
&
node
,
auto
const
&
tp
)
{
for
_e
ach
_l
eaf
_n
ode
(
lv
.
tree
(),
[
&
](
auto
const
&
node
,
auto
const
&
tp
)
{
nodeDataTransfer_
[
tp
].
preAdaptInit
(
lv
,
coeff
,
node
);
});
...
...
@@ -148,7 +148,7 @@ namespace AMDiS
lv
.
bind
(
e
);
auto
&
treeContainer
=
it
.
first
->
second
;
for
E
ach
L
eaf
N
ode
_
(
lv
.
tree
(),
[
&
](
auto
const
&
node
,
auto
const
&
tp
)
{
for
_e
ach
_l
eaf
_n
ode
(
lv
.
tree
(),
[
&
](
auto
const
&
node
,
auto
const
&
tp
)
{
nodeDataTransfer_
[
tp
].
cacheLocal
(
treeContainer
[
tp
]);
});
}
...
...
@@ -201,7 +201,7 @@ namespace AMDiS
};
restrictLocalCompleted
=
true
;
for
E
ach
L
eaf
N
ode
_
(
lv
.
tree
(),
[
&
](
auto
const
&
node
,
auto
const
&
tp
)
{
for
_e
ach
_l
eaf
_n
ode
(
lv
.
tree
(),
[
&
](
auto
const
&
node
,
auto
const
&
tp
)
{
restrictLocalCompleted
&=
nodeDataTransfer_
[
tp
].
restrictLocal
(
father
,
treeContainer
[
tp
],
xInChildCached
,
childContainer
[
tp
],
init
);
...
...
@@ -224,7 +224,7 @@ namespace AMDiS
auto
gv
=
basis_
->
gridView
();
auto
lv
=
basis_
->
localView
();
auto
const
&
idSet
=
gv
.
grid
().
localIdSet
();
for
E
ach
L
eaf
N
ode
_
(
lv
.
tree
(),
[
&
](
auto
const
&
node
,
auto
const
&
tp
)
{
for
_e
ach
_l
eaf
_n
ode
(
lv
.
tree
(),
[
&
](
auto
const
&
node
,
auto
const
&
tp
)
{
nodeDataTransfer_
[
tp
].
postAdaptInit
(
lv
,
coeff
,
node
);
});
...
...
@@ -243,7 +243,7 @@ namespace AMDiS
if
(
it
!=
persistentContainer_
.
end
())
{
lv
.
bind
(
e
);
auto
const
&
treeContainer
=
it
->
second
;
for
E
ach
L
eaf
N
ode
_
(
lv
.
tree
(),
[
&
](
auto
const
&
node
,
auto
const
&
tp
)
{
for
_e
ach
_l
eaf
_n
ode
(
lv
.
tree
(),
[
&
](
auto
const
&
node
,
auto
const
&
tp
)
{
nodeDataTransfer_
[
tp
].
copyLocal
(
treeContainer
[
tp
]);
});
finished_
[
index
]
=
true
;
...
...
@@ -275,7 +275,7 @@ namespace AMDiS
return
fatherGeo
.
local
(
childGeo
.
global
(
x
));
};
for
E
ach
L
eaf
N
ode
_
(
lv
.
tree
(),
[
&
](
auto
const
&
node
,
auto
const
&
tp
)
{
for
_e
ach
_l
eaf
_n
ode
(
lv
.
tree
(),
[
&
](
auto
const
&
node
,
auto
const
&
tp
)
{
nodeDataTransfer_
[
tp
].
prolongLocal
(
father
,
treeContainer
[
tp
],
xInFather
,
init
);
});
...
...
src/amdis/DirichletBC.hpp
View file @
0689eaae
...
...
@@ -11,8 +11,8 @@
#include
<amdis/BoundaryCondition.hpp>
#include
<amdis/common/Concepts.hpp>
#include
<amdis/typetree/RangeType.hpp>
#include
<amdis/typetree/Traversal.hpp>
#include
<amdis/typetree/TreeData.hpp>
#include
<amdis/typetree/Visitor.hpp>
namespace
AMDiS
{
...
...
src/amdis/PeriodicBC.inc.hpp
View file @
0689eaae
...
...
@@ -196,7 +196,7 @@ std::vector<D> PeriodicBC<D,MI>::
coords
(
Node
const
&
tree
,
std
::
vector
<
std
::
size_t
>
const
&
localIndices
)
const
{
std
::
vector
<
D
>
dofCoords
(
localIndices
.
size
());
AMDiS
::
for
E
ach
L
eaf
N
ode
_
(
tree
,
[
&
](
auto
const
&
node
,
auto
const
&
tp
)
for
_e
ach
_l
eaf
_n
ode
(
tree
,
[
&
](
auto
const
&
node
,
auto
const
&
tp
)
{
std
::
size_t
size
=
node
.
finiteElement
().
size
();
auto
geometry
=
node
.
element
().
geometry
();
...
...
src/amdis/ProblemStat.inc.hpp
View file @
0689eaae
...
...
@@ -177,7 +177,7 @@ void ProblemStat<Traits>::createMatricesAndVectors()
rhs_
=
std
::
make_shared
<
SystemVector
>
(
*
globalBasis_
,
NO_OPERATION
);
auto
localView
=
globalBasis_
->
localView
();
AMDiS
::
for
E
ach
N
ode
_
(
localView
.
tree
(),
[
&
,
this
](
auto
const
&
node
,
auto
treePath
)
for
_e
ach
_n
ode
(
localView
.
tree
(),
[
&
,
this
](
auto
const
&
node
,
auto
treePath
)
{
std
::
string
i
=
to_string
(
treePath
);
estimates_
[
i
].
resize
(
globalBasis_
->
gridView
().
indexSet
().
size
(
0
));
...
...
@@ -205,7 +205,7 @@ void ProblemStat<Traits>::createMarker()
{
marker_
.
clear
();
auto
localView
=
globalBasis_
->
localView
();
AMDiS
::
for
E
ach
N
ode
_
(
localView
.
tree
(),
[
&
,
this
](
auto
const
&
node
,
auto
treePath
)
for
_e
ach
_n
ode
(
localView
.
tree
(),
[
&
,
this
](
auto
const
&
node
,
auto
treePath
)
{
std
::
string
componentName
=
name_
+
"->marker["
+
to_string
(
treePath
)
+
"]"
;
...
...
@@ -232,7 +232,7 @@ void ProblemStat<Traits>::createFileWriter()
{
filewriter_
.
clear
();
auto
localView
=
globalBasis_
->
localView
();
for
E
ach
N
ode
_
(
localView
.
tree
(),
[
&
,
this
](
auto
const
&
node
,
auto
treePath
)
for
_e
ach
_n
ode
(
localView
.
tree
(),
[
&
,
this
](
auto
const
&
node
,
auto
treePath
)
{
std
::
string
componentName
=
name_
+
"->output["
+
to_string
(
treePath
)
+
"]"
;
...
...
@@ -428,9 +428,9 @@ buildAfterAdapt(AdaptInfo& /*adaptInfo*/, Flag /*flag*/, bool asmMatrix, bool as
rhs_
->
init
(
asmVector
);
auto
localView
=
globalBasis_
->
localView
();
for
E
ach
N
ode
_
(
localView
.
tree
(),
[
&
,
this
](
auto
const
&
rowNode
,
auto
rowTp
)
{
for
_e
ach
_n
ode
(
localView
.
tree
(),
[
&
,
this
](
auto
const
&
rowNode
,
auto
rowTp
)
{
auto
rowBasis
=
Dune
::
Functions
::
subspaceBasis
(
*
globalBasis_
,
rowTp
);
for
E
ach
N
ode
_
(
localView
.
tree
(),
[
&
,
this
](
auto
const
&
colNode
,
auto
colTp
)
{
for
_e
ach
_n
ode
(
localView
.
tree
(),
[
&
,
this
](
auto
const
&
colNode
,
auto
colTp
)
{
auto
colBasis
=
Dune
::
Functions
::
subspaceBasis
(
*
globalBasis_
,
colTp
);
for
(
auto
bc
:
dirichletBCs_
[
rowNode
][
colNode
])
bc
->
init
(
rowBasis
,
colBasis
);
...
...
@@ -456,8 +456,8 @@ buildAfterAdapt(AdaptInfo& /*adaptInfo*/, Flag /*flag*/, bool asmMatrix, bool as
systemMatrix_
->
finish
(
asmMatrix
);
rhs_
->
finish
(
asmVector
);
for
E
ach
N
ode
_
(
localView
.
tree
(),
[
&
,
this
](
auto
const
&
rowNode
,
auto
)
{
for
E
ach
N
ode
_
(
localView
.
tree
(),
[
&
,
this
](
auto
const
&
colNode
,
auto
)
{
for
_e
ach
_n
ode
(
localView
.
tree
(),
[
&
,
this
](
auto
const
&
rowNode
,
auto
)
{
for
_e
ach
_n
ode
(
localView
.
tree
(),
[
&
,
this
](
auto
const
&
colNode
,
auto
)
{
// finish boundary condition
for
(
auto
bc
:
dirichletBCs_
[
rowNode
][
colNode
])
bc
->
fillBoundaryCondition
(
*
systemMatrix_
,
*
solution_
,
*
rhs_
,
rowNode
,
colNode
);
...
...
src/amdis/common/ForEach.hpp
View file @
0689eaae
...
...
@@ -2,7 +2,6 @@
#include
<initializer_list>
#include
<amdis/common/Apply.hpp>
#include
<amdis/common/Index.hpp>
#include
<amdis/common/Range.hpp>
...
...
@@ -16,34 +15,52 @@ namespace AMDiS
void
ignored_evaluation
(
std
::
initializer_list
<
T
>&&
)
{
/* do nothing */
}
}
template
<
std
::
size_t
...
I
,
class
Tuple
,
class
Functor
>
constexpr
void
for_each
(
std
::
index_sequence
<
I
...
>
,
Tuple
&&
tuple
,
Functor
&&
f
)
{
using
std
::
get
;
#if AMDIS_HAS_EXPANSION_STATEMENTS
for
...
(
auto
&&
t
:
tuple
)
{
f
(
FWD
(
t
));
}
#elif AMDIS_HAS_CXX_FOLD_EXPRESSIONS
(
f
(
get
<
I
>
(
tuple
)),...);
#else
Impl_
::
ignored_evaluation
<
int
>
({
0
,
(
f
(
get
<
I
>
(
tuple
)),
0
)...});
#endif
}
template
<
class
Tuple
,
class
Functor
>
constexpr
void
for_each
(
Tuple
&&
tuple
,
Functor
&&
f
)
{
#if AMDIS_HAS_CXX_FOLD_EXPRESSIONS
Tools
::
apply
([
f
=
std
::
move
(
f
)](
auto
&&
...
t
)
{
(
f
(
FWD
(
t
)),...);
},
tuple
);
#else
Tools
::
apply
([
f
=
std
::
move
(
f
)](
auto
&&
...
t
)
{
Impl_
::
ignored_evaluation
<
int
>
({
0
,
(
f
(
FWD
(
t
)),
0
)...});
},
tuple
);
#endif
Tools
::
for_each
(
std
::
make_index_sequence
<
Size_v
<
std
::
remove_reference_t
<
Tuple
>>>
{},
FWD
(
tuple
),
FWD
(
f
));
}
template
<
std
::
size_t
I0
=
0
,
std
::
size_t
...
I
,
class
Functor
>
constexpr
void
for_range
(
std
::
index_sequence
<
I
...
>
,
Functor
&&
f
)
{
#if AMDIS_HAS_CXX_FOLD_EXPRESSIONS
(
f
(
index_t
<
I0
+
I
>
{}),...);
#else
Impl_
::
ignored_evaluation
<
int
>
({
0
,
(
f
(
index_t
<
I0
+
I
>
{}),
0
)...});
#endif
}
template
<
std
::
size_t
I0
,
std
::
size_t
I1
,
class
Functor
>
constexpr
void
for_range
(
index_t
<
I0
>
i0
,
index_t
<
I1
>
i1
,
Functor
&&
f
)
{
Tools
::
for_
each
(
range
_t
<
I0
,
I1
>
{},
FWD
(
f
));
Tools
::
for_range
<
I0
>
(
std
::
make_index_sequence
<
std
::
size_t
(
I1
-
I0
)
>
{},
FWD
(
f
));
}
template
<
std
::
size_t
N
,
class
Functor
>
constexpr
void
for_range
(
index_t
<
N
>
,
Functor
&&
f
)
{
Tools
::
for_
each
(
range_t
<
0
,
N
>
{},
FWD
(
f
));
Tools
::
for_
range
(
std
::
make_index_sequence
<
N
>
{},
FWD
(
f
));
}
template
<
std
::
size_t
I0
,
std
::
size_t
I1
,
class
Functor
>
constexpr
void
for_range
(
Functor
&&
f
)
{
Tools
::
for_
each
(
range
_t
<
I0
,
I1
>
{},
FWD
(
f
));
Tools
::
for_range
<
I0
>
(
std
::
make_index_sequence
<
std
::
size_t
(
I1
-
I0
)
>
{},
FWD
(
f
));
}
}
// end namespace Tools
...
...
src/amdis/common/TypeTraits.hpp
View file @
0689eaae
...
...
@@ -65,6 +65,12 @@ namespace AMDiS
template
<
class
T
>
using
owner
=
T
;
/// A functor with no operation
struct
NoOp
{
template
<
class
...
T
>
constexpr
void
operator
()(
T
&&
...)
const
{
/* no nothing */
}
};
/// Create a unique_ptr by copy/move construction
template
<
class
Obj
>
...
...
src/amdis/gridfunctions/DiscreteFunction.inc.hpp
View file @
0689eaae
...
...
@@ -147,7 +147,7 @@ LocalFunction::operator()(Domain const& x) const
auto
&&
coefficients
=
*
globalFunction_
.
dofVector_
;
auto
&&
nodeToRangeEntry
=
globalFunction_
.
nodeToRangeEntry_
;
for
E
ach
L
eaf
N
ode
_
(
*
subTree_
,
[
&
,
this
](
auto
const
&
node
,
auto
const
&
tp
)
for
_e
ach
_l
eaf
_n
ode
(
*
subTree_
,
[
&
,
this
](
auto
const
&
node
,
auto
const
&
tp
)
{
auto
&&
fe
=
node
.
finiteElement
();
auto
&&
localBasis
=
fe
.
localBasis
();
...
...
@@ -193,7 +193,7 @@ GradientLocalFunction::operator()(Domain const& x) const
auto
&&
coefficients
=
*
globalFunction_
.
dofVector_
;
auto
&&
nodeToRangeEntry
=
globalFunction_
.
nodeToRangeEntry_
;
for
E
ach
L
eaf
N
ode
_
(
*
subTree_
,
[
&
,
this
](
auto
const
&
node
,
auto
const
&
tp
)
for
_e
ach
_l
eaf
_n
ode
(
*
subTree_
,
[
&
,
this
](
auto
const
&
node
,
auto
const
&
tp
)
{
// TODO: may DOFVectorView::Range to FieldVector type if necessary
using
LocalDerivativeTraits
...
...
src/amdis/linearalgebra/DOFMatrixBase.inc.hpp
View file @
0689eaae
...
...
@@ -2,7 +2,7 @@
#include
<amdis/Assembler.hpp>
#include
<amdis/LocalOperator.hpp>
#include
<amdis/typetree/
Visitor
.hpp>
#include
<amdis/typetree/
Traversal
.hpp>
#include
<amdis/utility/AssembleOperators.hpp>
namespace
AMDiS
{
...
...
@@ -75,8 +75,8 @@ assemble(RowLocalView const& rowLocalView, ColLocalView const& colLocalView)
auto
const
&
element
=
rowLocalView
.
element
();
auto
geometry
=
element
.
geometry
();
for
E
ach
N
ode
_
(
rowLocalView
.
tree
(),
[
&
](
auto
const
&
rowNode
,
auto
)
{
for
E
ach
N
ode
_
(
colLocalView
.
tree
(),
[
&
](
auto
const
&
colNode
,
auto
)
{
for
_e
ach
_n
ode
(
rowLocalView
.
tree
(),
[
&
](
auto
const
&
rowNode
,
auto
)
{
for
_e
ach
_n
ode
(
colLocalView
.
tree
(),
[
&
](
auto
const
&
colNode
,
auto
)
{
auto
&
matOp
=
operators_
[
rowNode
][
colNode
];
if
(
matOp
)
{
matOp
.
bind
(
element
,
geometry
);
...
...
src/amdis/linearalgebra/DOFVectorBase.inc.hpp
View file @
0689eaae
...
...
@@ -2,7 +2,7 @@
#include
<amdis/Assembler.hpp>
#include
<amdis/LocalOperator.hpp>
#include
<amdis/typetree/
Visitor
.hpp>
#include
<amdis/typetree/
Traversal
.hpp>
#include
<amdis/utility/AssembleOperators.hpp>
namespace
AMDiS
{
...
...
@@ -66,7 +66,7 @@ assemble(LocalView const& localView)
auto
const
&
element
=
localView
.
element
();
auto
geometry
=
element
.
geometry
();
for
E
ach
N
ode
_
(
localView
.
tree
(),
[
&
](
auto
const
&
node
,
auto
)
{
for
_e
ach
_n
ode
(
localView
.
tree
(),
[
&
](
auto
const
&
node
,
auto
)
{
auto
&
rhsOp
=
operators_
[
node
];
if
(
rhsOp
)
{
rhsOp
.
bind
(
element
,
geometry
);
...
...
src/amdis/typetree/CMakeLists.txt
View file @
0689eaae
...
...
@@ -7,5 +7,4 @@ install(FILES
TreeContainer.hpp
TreeData.hpp
TreePath.hpp
Visitor.hpp
DESTINATION
${
CMAKE_INSTALL_INCLUDEDIR
}
/amdis/typetree
)
src/amdis/typetree/Traversal.hpp
View file @
0689eaae
...
...
@@ -3,139 +3,257 @@
#include
<dune/common/hybridutilities.hh>
#include
<dune/common/rangeutilities.hh>
#include
<dune/typetree/childextraction.hh>
#include
<dune/typetree/nodetags.hh>
#include
<dune/typetree/treepath.hh>
#include
<dune/typetree/visitor.hh>
#include
<amdis/common/ForEach.hpp>
#include
<amdis/common/Logical.hpp>
#include
<amdis/common/Range.hpp>
#include
<amdis/common/TypeTraits.hpp>
namespace
AMDiS
{
// forward declaration of main engine struct
template
<
typename
NodeTag
,
bool
visit
=
true
>
struct
TraverseTree
;
// Do not visit nodes the visitor is not interested in
template
<
typename
NodeTag
>
struct
TraverseTree
<
NodeTag
,
false
>
{
template
<
typename
Node
,
typename
Visitor
,
typename
TreePath
>
static
void
apply
(
const
Node
&
node
,
const
Visitor
&
visitor
,
TreePath
const
&
tp
)
{}
};
#ifndef DOXYGEN
// some implementation details
template
<
class
Node
,
class
Index
>
struct
HybridChildType
:
HybridChildType
<
std
::
remove_const_t
<
Node
>
,
std
::
remove_const_t
<
Index
>>
{};
template
<
class
Node
>
struct
HybridChildType
<
Node
,
std
::
size_t
>
{
using
type
=
typename
Node
::
template
Child
<
0
>
::
Type
;
};
template
<
class
Node
,
std
::
size_t
K
>
struct
HybridChildType
<
Node
,
Dune
::
index_constant
<
K
>>
{
using
type
=
typename
Node
::
template
Child
<
K
>
::
Type
;
};
template
<
class
NodeTag
,
class
Node
>
constexpr
std
::
size_t
hybridDegree
(
NodeTag
,
Node
const
&
node
)
{
return
Dune
::
TypeTree
::
degree
(
node
);
}
template
<
class
Node
>
constexpr
auto
hybridDegree
(
Dune
::
TypeTree
::
CompositeNodeTag
,
Node
const
&
node
)
{
return
Dune
::
index_constant
<
Node
::
CHILDREN
>
{};
}
template
<
std
::
size_t
k
,
std
::
size_t
n
>
constexpr
bool
notLastChild
(
Dune
::
index_constant
<
k
>
const
&
,
Dune
::
index_constant
<
n
>
const
&
)
{
return
k
<
n
-
1
;
}
constexpr
bool
notLastChild
(
std
::
size_t
k
,
std
::
size_t
n
)
{
return
k
<
n
-
1
;
}
#endif
template
<
class
NodeTag
>
struct
TraverseTree
<
NodeTag
,
true
>
{
template
<
typename
N
,
typename
V
,
typename
TreePath
>
static
void
apply
(
N
&&
n
,
V
&&
v
,
TreePath
const
&
tp
)
// NOTE: backport of dune/typetree/traversal.hpp from Dune 2.7
namespace
AMDiS
{
enum
class
TreePathType
{
using
Node
=
std
::
remove_reference_t
<
N
>
;
using
Visitor
=
std
::
remove_reference_t
<
V
>
;
DYNAMIC
,
STATIC
};
namespace
Impl
{
// This is a constexpr version of the ternery operator c?t1:t1.
// In contrast to the latter the type of t1 and t2 can be different.
// Notice that std::conditional would not do the trick, because
// it only selects between types.
template
<
bool
c
,
class
T1
,
class
T2
,
std
::
enable_if_t
<
c
,
int
>
=
0
>
constexpr
auto
conditionalValue
(
T1
&&
t1
,
T2
&&
t2
)
{
return
std
::
forward
<
T1
>
(
t1
);
}
template
<
bool
c
,
class
T1
,
class
T2
,
std
::
enable_if_t
<
not
c
,
int
>
=
0
>
constexpr
auto
conditionalValue
(
T1
&&
t1
,
T2
&&
t2
)
{
return
std
::
forward
<
T2
>
(
t2
);
}
/* The signature is the same as for the public applyToTree
* function in Dune::Typetree, despite the additionally passed
* treePath argument. The path passed here is associated to
* the tree and the relative paths of the children (wrt. to tree)
* are appended to this. Hence the behavior of the public function
* is resembled by passing an empty treePath.
*/
/*
* This is the overload for leaf traversal
*/
template
<
class
T
,
class
TP
,
class
V
,
std
::
enable_if_t
<
remove_cvref_t
<
T
>
::
isLeaf
,
int
>
=
0
>
void
apply_to_tree
(
T
&&
tree
,
TP
treePath
,
V
&&
visitor
)
{
visitor
.
leaf
(
tree
,
treePath
);
}
/*
* This is the general overload doing child traversal.
*/
template
<
class
T
,
class
TP
,
class
V
,
std
::
enable_if_t
<
not
remove_cvref_t
<
T
>
::
isLeaf
,
int
>
=
0
>
void
apply_to_tree
(
T
&&
tree
,
TP
treePath
,
V
&&
visitor
)
{
// Do we really want to take care for const-ness of the Tree
// when instantiating VisitChild below? I'd rather expect this:
// using Tree = remove_cvref_t<T>;
// using Visitor = remove_cvref_t<V>;
using
Tree
=
std
::
remove_reference_t
<
T
>
;
using
Visitor
=
std
::
remove_reference_t
<
V
>
;
visitor
.
pre
(
tree
,
treePath
);
// Use statically encoded degree unless tree
// is a power node and dynamic traversal is requested.
constexpr
auto
useDynamicTraversal
=
(
Tree
::
isPower
and
Visitor
::
treePathType
==
TreePathType
::
DYNAMIC
);
auto
degree
=
conditionalValue
<
useDynamicTraversal
>
(
Tree
::
degree
(),
Dune
::
index_constant
<
Tree
::
degree
()
>
{});
auto
indices
=
Dune
::
range
(
degree
);
Dune
::
Hybrid
::
forEach
(
indices
,
[
&
](
auto
i
)
{
auto
childTP
=
Dune
::
TypeTree
::
push_back
(
treePath
,
i
);
auto
&&
child
=
tree
.
child
(
i
);
using
Child
=
TYPEOF
(
child
);
visitor
.
beforeChild
(
tree
,
child
,
treePath
,
i
);
// This requires that visiotor.in(...) can always be instantiated,
// even if there's a single child only.
if
(
i
>
0
)
visitor
.
in
(
tree
,
treePath
);
static
constexpr
auto
visitChild
=
Visitor
::
template
VisitChild
<
Tree
,
Child
,
TP
>
::
value
;
#if AMDIS_HAS_CXX_CONSTEXPR_IF
if
constexpr
(
visitChild
)
applyToTree
(
child
,
childTP
,
visitor
);
#else // AMDIS_HAS_CXX_CONSTEXPR_IF
Dune
::
Hybrid
::
ifElse
(
bool_t
<
visitChild
>
{},
[
&
]
(
auto
/*id*/
)
{
applyToTree
(
child
,
childTP
,
visitor
);
});
#endif // AMDIS_HAS_CXX_CONSTEXPR_IF
visitor
.
afterChild
(
tree
,
child
,
treePath
,
i
);
});
visitor
.
post
(
tree
,
treePath
);
}
// Overload for leaf nodes
template
<
class
Tree
,
class
TP
,
class
Pre
,
class
Leaf
,
class
Post
,
std
::
enable_if_t
<
remove_cvref_t
<
Tree
>
::
isLeaf
,
int
>
=
0
>
void
for_each_node
(
Tree
&&
tree
,
TP
treePath
,
Pre
&&
/*preFunc*/
,
Leaf
&&
leafFunc
,
Post
&&
/*postFunc*/
)
{
leafFunc
(
tree
,
treePath
);
}
// Overload for non-leaf nodes
// Forward declaration needed for recursion
template
<
class
Tree
,
class
TP
,
class
Pre
,
class
Leaf
,
class
Post
,
std
::
enable_if_t
<
not
remove_cvref_t
<
Tree
>
::
isLeaf
,
int
>
=
0
>
void
for_each_node
(
Tree
&&
tree
,
TP
treePath
,
Pre
&&
preFunc
,
Leaf
&&
leafFunc
,
Post
&&
postFunc
);
// Helper for power nodes
template
<
class
Tree
,
class
TP
,
class
Pre
,
class
Leaf
,
class
Post
,
std
::
size_t
...
I
,
std
::
enable_if_t
<
remove_cvref_t
<
Tree
>
::
isPower
,
int
>
=
0
>
void
for_each_node_unfold
(
Tree
&&
tree
,
TP
treePath
,
Pre
&&
preFunc
,
Leaf
&&
leafFunc
,
Post
&&
postFunc
,
std
::
index_sequence
<
I
...
>
)
{
for
(
std
::
size_t
i
=
0
;
i
<
sizeof
...(
I
);
++
i
)
Impl
::
for_each_node
(
tree
.
child
(
i
),
Dune
::
TypeTree
::
push_back
(
treePath
,
i
),
preFunc
,
leafFunc
,
postFunc
);
}
v
.
pre
(
FWD
(
n
),
tp
);
// Helper for composite nodes
template
<
class
Tree
,
class
TP
,
class
Pre
,
class
Leaf
,
class
Post
,
std
::
size_t
...
I
,
std
::
enable_if_t
<
not
remove_cvref_t
<
Tree
>
::
isPower
,
int
>
=
0
>
void
for_each_node_unfold
(
Tree
&&
tree
,
TP
treePath
,
Pre
&&
preFunc
,
Leaf
&&
leafFunc
,
Post
&&
postFunc
,
std
::
index_sequence
<
I
...
>
)
{
(
void
)
std
::
initializer_list
<
int
>
{(
Impl
::
for_each_node
(
tree
.
child
(
Dune
::
index_constant
<
I
>
{}),
Dune
::
TypeTree
::
push_back
(
treePath
,
Dune
::
index_constant
<
I
>
{}),
preFunc
,
leafFunc
,
postFunc
),
0
)...
};
}
auto
const
deg
=
hybridDegree
(
NodeTag
{},
n
);
Dune
::
Hybrid
::
forEach
(
Dune
::
range
(
deg
),
[
&
](
auto
const
_k
)
/*
* Traverse tree and visit each node. The signature is the same
* as for the public for_each_node function in Dune::Typtree,
* despite the additionally passed treePath argument. The path
* passed here is associated to the tree and the relative
* paths of the children (wrt. to tree) are appended to this.
* Hence the behavior of the public function is resembled
* by passing an empty treePath.
*
* See also the specialization for leaf-nodes.
*/
template
<
class
Tree
,
class
TP
,
class
Pre
,
class
Leaf
,
class
Post
,
std
::
enable_if_t
<
not
remove_cvref_t
<
Tree
>
::
isLeaf
,
int
>>
void
for_each_node
(
Tree
&&
tree
,
TP
treePath
,
Pre
&&
preFunc
,
Leaf
&&
leafFunc
,
Post
&&
postFunc
)
{
// always call beforeChild(), regardless of the value of visit
v
.
beforeChild
(
FWD
(
n
),
n
.
child
(
_k
),
tp
,
_k
);
auto
indices
=
std
::
make_index_sequence
<
TYPEOF
(
tree
)
::
degree
()
>
{};
preFunc
(
tree
,
treePath
);
Impl
::
for_each_node_unfold
(
tree
,
treePath
,
preFunc
,
leafFunc
,
postFunc
,
indices
);
postFunc
(
tree
,
treePath
);
}
}
// namespace Impl
// ********************************************************************************
// Public Interface
// ********************************************************************************
// descend to child
using
C
=
typename
HybridChildType
<
Node
,
decltype
(
_k
)
>::
type
;
const
bool
visit
=
Visitor
::
template
VisitChild
<
Node
,
C
,
TreePath
>
::
value
;
TraverseTree
<
Dune
::
TypeTree
::
NodeTag
<
C
>
,
visit
>::
apply
(
n
.
child
(
_k
),
FWD
(
v
),
push_back
(
tp
,
_k
));
//! Apply visitor to TypeTree.
/**
* \code
* #include <amdis/typetree/Traversal.hpp>
* \endcode
* This function applies the given visitor to the given tree. Both visitor and tree may be const
* or non-const (if the compiler supports rvalue references, they may even be a non-const temporary).
*
* \note The visitor must implement the interface laid out by DefaultVisitor (most easily achieved by
* inheriting from it) and specify the required type of tree traversal (static or dynamic) by
* inheriting from either StaticTraversal or DynamicTraversal.