Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F64676300
component_libmultiscale.hh
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, May 28, 15:26
Size
27 KB
Mime Type
text/x-c++
Expires
Thu, May 30, 15:26 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
17943088
Attached To
rLIBMULTISCALE LibMultiScale
component_libmultiscale.hh
View Options
/**
* @file component_libmultiscale.hh
*
* @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
*
* @date Mon Sep 08 23:40:22 2014
*
* @brief This describe the root objects to be combined into valid LM
* components
*
* @section LICENSE
*
* Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
* Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
*
* LibMultiScale is free software: you can redistribute it and/or modify it
* under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* LibMultiScale 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 Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with LibMultiScale. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef __LIBMULTISCALE_COMPONENT_LIBMULTISCALE_HH__
#define __LIBMULTISCALE_COMPONENT_LIBMULTISCALE_HH__
/* -------------------------------------------------------------------------- */
#include "container.hh"
#include "lm_common.hh"
#include "lm_object.hh"
#include <cmath>
#include <limits>
#include <map>
#include <memory>
#include <stdexcept>
#include <typeindex>
#include <typeinfo>
/* -------------------------------------------------------------------------- */
__BEGIN_LIBMULTISCALE__
/* -------------------------------------------------------------------------- */
namespace
detail
{
template
<
class
F
,
class
Tuple
,
std
::
size_t
...
I
>
constexpr
decltype
(
auto
)
apply_impl
(
F
&&
f
,
Tuple
&&
t
,
std
::
index_sequence
<
I
...
>
)
{
return
f
(
std
::
get
<
I
>
(
std
::
forward
<
Tuple
>
(
t
))...);
}
}
// namespace detail
template
<
class
F
,
class
Tuple
>
constexpr
decltype
(
auto
)
apply
(
F
&&
f
,
Tuple
&&
t
)
{
return
detail
::
apply_impl
(
std
::
forward
<
F
>
(
f
),
std
::
forward
<
Tuple
>
(
t
),
std
::
make_index_sequence
<
std
::
tuple_size
<
std
::
remove_reference_t
<
Tuple
>>::
value
>
{});
}
/* -------------------------------------------------------------------------- */
namespace
detail
{
template
<
int
I
>
struct
foreach_tuple_impl
{
template
<
class
F
,
class
Tuple
>
static
void
doIt
(
F
&&
f
,
Tuple
&&
t
)
{
f
(
std
::
get
<
I
>
(
std
::
forward
<
Tuple
>
(
t
)));
foreach_tuple_impl
<
I
-
1
>::
doIt
(
f
,
t
);
}
};
template
<>
struct
foreach_tuple_impl
<-
1
>
{
template
<
class
F
,
class
Tuple
>
static
void
doIt
(
F
&&
f
,
Tuple
&&
t
)
{}
};
}
// namespace detail
template
<
class
F
,
class
Tuple
>
constexpr
decltype
(
auto
)
foreach_tuple
(
F
&&
f
,
Tuple
&&
t
)
{
detail
::
foreach_tuple_impl
<
std
::
tuple_size
<
std
::
remove_reference_t
<
std
::
remove_pointer_t
<
Tuple
>>>::
value
-
1
>::
doIt
(
std
::
forward
<
F
>
(
f
),
std
::
forward
<
Tuple
>
(
t
));
}
/* -------------------------------------------------------------------------- */
class
ContainerInterface
;
template
<
typename
T
>
class
ContainerArray
;
template
<
typename
Tuple
>
struct
getFirstArgument
{
// this is a non used case....
static
int
get
(
Tuple
&
tuple
)
{
return
10
;
};
};
template
<
typename
T
>
struct
getFirstArgument
<
std
::
tuple
<
T
>>
{
static
auto
&
get
(
std
::
tuple
<
T
>
&
tuple
)
{
return
std
::
get
<
0
>
(
tuple
);
}
};
/* -------------------------------------------------------------------------- */
class
ReleasedObject
{
public
:
ReleasedObject
()
{
release
=
0
;
}
//! return actual release
UInt
getRelease
()
const
{
return
release
;
};
//! return actual release
void
setRelease
(
UInt
r
)
{
release
=
r
;
};
//! increment the release
void
incRelease
()
{
++
release
;
};
template
<
typename
Dependencies
>
void
acquireRelease
(
const
Dependencies
&
deps
)
{
for
(
auto
&
pair
:
deps
)
{
auto
*
ptr
=
pair
.
second
;
if
(
ptr
==
nullptr
)
LM_FATAL
(
pair
.
first
<<
": input was not created/computed/connected"
);
release
=
std
::
max
(
release
,
(
*
ptr
)
->
getRelease
());
}
}
template
<
typename
Dependencies
>
bool
checkDependency
(
const
Dependencies
&
deps
)
{
for
(
auto
&
pair
:
deps
)
{
if
(
pair
.
second
==
nullptr
)
return
true
;
try
{
if
(
!
pair
.
second
->
isAllocated
())
return
true
;
auto
&
dep
=
pair
.
second
->
get
();
if
(
release
<
dep
.
getRelease
())
return
true
;
}
catch
(...)
{
return
true
;
}
}
return
false
;
}
private
:
UInt
release
;
};
struct
ArgumentInterface
:
public
ReleasedObject
{
ArgumentInterface
(){};
virtual
~
ArgumentInterface
(){};
virtual
std
::
type_index
get_type_index
()
const
=
0
;
virtual
std
::
string
get_type_info
()
const
=
0
;
template
<
typename
T
>
T
&
cast
();
virtual
void
printself
(
std
::
ostream
&
os
)
const
=
0
;
virtual
void
_copyContainerInfo
(
ContainerInterface
&
c
)
=
0
;
};
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
ArgumentInterface
&
a
)
{
a
.
printself
(
os
);
return
os
;
}
template
<
typename
T1
>
std
::
enable_if_t
<
std
::
is_base_of
<
ContainerInterface
,
std
::
decay_t
<
T1
>>::
value
>
_copyContainerInfo_casted
(
T1
&
value
,
ContainerInterface
&
a
)
{
value
.
copyContainerInfo
(
a
);
}
template
<
typename
T1
>
std
::
enable_if_t
<!
std
::
is_base_of
<
ContainerInterface
,
std
::
decay_t
<
T1
>>::
value
>
_copyContainerInfo_casted
(
T1
&
value
,
ContainerInterface
&
a
)
{}
template
<
typename
T1
>
void
_copyContainerInfo_casted
(
std
::
shared_ptr
<
T1
>
value
,
ContainerInterface
&
a
)
{
T1
&
v
=
*
value
;
_copyContainerInfo_casted
<
T1
>
(
v
,
a
);
}
template
<
typename
T
>
struct
Argument
:
public
ArgumentInterface
{
void
_copyContainerInfo
(
ContainerInterface
&
c
)
override
{
_copyContainerInfo_casted
(
value
,
c
);
};
Argument
(
Argument
&&
arg
)
=
default
;
Argument
(
T
&&
val
)
:
value
(
val
)
{}
inline
void
printself
(
std
::
ostream
&
os
)
const
override
{
const
T
&
temp
=
this
->
value
;
os
<<
"("
<<
this
<<
")"
<<
this
->
get_type_info
()
<<
" : "
<<
" "
<<
&
temp
;
}
const
std
::
type_index
type_index
=
typeid
(
T
);
inline
std
::
type_index
get_type_index
()
const
override
{
return
type_index
;
};
inline
std
::
string
get_type_info
()
const
override
{
return
typeinfo
<
T
>
();
};
inline
virtual
T
&
get
()
{
return
value
;
};
T
value
;
};
template
<
typename
T
>
T
&
ArgumentInterface
::
cast
()
{
auto
ptr1
=
dynamic_cast
<
Argument
<
T
>
*>
(
this
);
auto
ptr2
=
dynamic_cast
<
Argument
<
T
&>
*>
(
this
);
auto
ptr3
=
dynamic_cast
<
Argument
<
std
::
shared_ptr
<
T
>>
*>
(
this
);
if
(
ptr1
==
nullptr
&&
ptr2
==
nullptr
&&
ptr3
==
nullptr
)
{
LM_FATAL
(
"cannot cast argument from "
<<
this
->
get_type_info
()
<<
" into "
<<
typeinfo
<
T
>
());
}
if
(
ptr1
)
return
ptr1
->
get
();
if
(
ptr2
)
return
ptr2
->
get
();
return
*
ptr3
->
get
();
}
class
Component
;
class
ArgumentContainer
{
public
:
ArgumentContainer
()
:
component
(
nullptr
),
ptr
(
nullptr
){};
ArgumentContainer
(
Component
&
component
)
:
component
(
&
component
),
ptr
(
nullptr
){};
ArgumentContainer
(
ArgumentContainer
&&
other
)
=
default
;
ArgumentInterface
*
operator
->
()
{
return
&
this
->
get
();
}
ArgumentInterface
&
operator
*
()
{
return
this
->
get
();
}
template
<
typename
T
>
ArgumentContainer
&
operator
=
(
Argument
<
T
>
&&
val
)
{
if
(
ptr_allocated
.
get
()
!=
nullptr
)
ptr_allocated
.
release
();
ptr_allocated
=
std
::
make_unique
<
Argument
<
T
>>
(
std
::
forward
<
decltype
(
val
)
>
(
val
));
ptr
=
ptr_allocated
.
get
();
return
*
this
;
}
UInt
getRelease
()
{
return
ptr
->
getRelease
();
}
void
setRelease
(
UInt
release
)
{
ptr
->
setRelease
(
release
);
}
ArgumentContainer
&
operator
=
(
ArgumentContainer
&&
arg
)
=
default
;
ArgumentContainer
&
operator
=
(
const
ArgumentContainer
&
arg
)
{
if
(
ptr_allocated
.
get
()
!=
nullptr
)
ptr_allocated
.
release
();
ptr
=
arg
.
ptr
;
return
*
this
;
}
inline
ArgumentInterface
&
get
(
bool
eval
=
true
);
inline
const
ArgumentInterface
&
get
()
const
;
inline
bool
isAllocated
();
private
:
Component
*
component
;
ArgumentInterface
*
ptr
;
std
::
unique_ptr
<
ArgumentInterface
>
ptr_allocated
;
public
:
class
UnallocatedPointer
:
public
std
::
exception
{};
};
template
<
typename
T
>
Argument
<
T
>
make_argument
(
T
&&
val
)
{
return
Argument
<
T
>
(
std
::
forward
<
T
>
(
val
));
}
/* --------------------------------------------------------------------- */
class
Component
:
public
ReleasedObject
,
public
virtual
LMObject
{
public
:
Component
()
:
calculated_once
(
false
)
{}
virtual
~
Component
(){
};
template
<
typename
T
>
void
connect
(
const
std
::
string
&
input
,
Argument
<
T
>
&&
arg
);
inline
void
connect
(
const
std
::
string
&
input
,
ArgumentContainer
&
arg
);
template
<
typename
...
Args
>
inline
void
setInput
(
Args
&&
...
args
)
{
auto
tup
=
std
::
forward_as_tuple
(
args
...);
int
cpt
=
0
;
std
::
vector
<
std
::
string
>
keys
;
std
::
for_each
(
inputs
.
begin
(),
inputs
.
end
(),
[
&
keys
](
auto
key
)
{
keys
.
push_back
(
key
.
first
);
});
auto
f
=
[
&
](
auto
&
arg
)
{
auto
key
=
keys
[
cpt
];
auto
search
=
inputs
.
find
(
key
);
if
(
search
==
inputs
.
end
())
{
LM_FATAL
(
this
->
getID
()
+
":"
+
key
+
": input not existing"
);
}
if
(
this
->
inputs
[
key
]
==
nullptr
)
this
->
inputs
[
key
]
=
new
ArgumentContainer
();
*
this
->
inputs
[
key
]
=
make_argument
(
arg
);
++
cpt
;
};
apply
(
f
,
tup
);
};
inline
ArgumentContainer
*
allocInput
(
const
std
::
string
&
input
);
inline
void
createOutput
(
const
std
::
string
&
output
);
inline
void
createInput
(
const
std
::
string
&
input
);
inline
void
removeInput
(
const
std
::
string
&
input
);
inline
bool
isConnected
(
const
std
::
string
&
input
);
inline
virtual
void
compute
()
{
bool
need_recompute
=
this
->
checkDependency
(
this
->
inputs
);
if
(
!
need_recompute
&&
calculated_once
)
return
;
this
->
compute_make_call
();
this
->
acquireRelease
(
this
->
inputs
);
for
(
auto
&
pair
:
this
->
outputs
)
{
auto
&
arg
=
pair
.
second
;
arg
.
setRelease
(
this
->
getRelease
());
}
calculated_once
=
true
;
}
template
<
typename
...
Args
>
void
buildManual
(
Args
&&
...
args
)
{
this
->
setInput
(
args
...);
this
->
compute_make_call
();
calculated_once
=
true
;
}
template
<
typename
T
>
std
::
enable_if_t
<
std
::
is_base_of
<
ContainerInterface
,
T
>::
value
>
_copyContainerInfo
(
T
&
a
)
{
for
(
auto
&
output
:
this
->
outputs
)
{
auto
&
o
=
output
.
second
.
get
(
false
);
o
.
_copyContainerInfo
(
a
);
}
}
template
<
typename
T
>
std
::
enable_if_t
<
not
std
::
is_base_of
<
ContainerInterface
,
T
>::
value
>
_copyContainerInfo
(
T
&
a
)
{}
virtual
void
compute_make_call
()
=
0
;
inline
ArgumentContainer
&
getInput
(
const
std
::
string
&
input
)
{
auto
search
=
inputs
.
find
(
input
);
if
(
search
==
inputs
.
end
())
{
LM_FATAL
(
this
->
getID
()
+
":"
+
input
+
": input not existing"
);
}
if
(
this
->
inputs
[
input
]
==
nullptr
)
throw
UnconnectedInput
{
this
->
getID
()
+
":"
+
input
+
": input not existing"
};
return
*
this
->
inputs
[
input
];
}
inline
auto
&
getOutputs
()
{
return
outputs
;
}
inline
ArgumentContainer
&
getOutput
(
const
std
::
string
&
output
=
"output"
)
{
// DUMP(this->getID() << ": getOutput(" << output << ")", DBG_INFO);
auto
search
=
outputs
.
find
(
output
);
if
(
search
==
outputs
.
end
())
{
LM_FATAL
(
this
->
getID
()
+
":"
+
output
+
": output not existing"
);
}
return
outputs
[
output
];
};
template
<
typename
Cont
>
auto
&
getCastedOutput
(
bool
eval
=
true
,
const
std
::
string
&
output
=
"output"
)
{
auto
&
arg
=
this
->
getOutput
(
output
).
get
(
eval
);
return
arg
.
cast
<
Cont
>
();
}
template
<
typename
Cont
,
typename
...
T
>
auto
&
allocAndGetCastedOutput
(
T
&&
...
construction_parameters
)
{
using
type
=
typename
Cont
::
ContainerSubset
;
using
ptr_type
=
std
::
shared_ptr
<
type
>
;
try
{
this
->
getCastedOutput
<
ptr_type
>
(
false
);
}
catch
(
ArgumentContainer
::
UnallocatedPointer
&
e
)
{
this
->
getOutput
()
=
make_argument
(
std
::
make_shared
<
type
>
(
construction_parameters
...));
}
auto
&
output
=
*
getCastedOutput
<
ptr_type
>
(
false
);
return
output
;
}
inline
void
printself
(
std
::
ostream
&
os
)
const
;
void
clear_inputs
()
{
inputs
.
clear
();
}
struct
UnconnectedInput
:
public
std
::
runtime_error
{
using
std
::
runtime_error
::
runtime_error
;
};
private
:
friend
class
ActionInterface
;
std
::
map
<
std
::
string
,
ArgumentContainer
*>
inputs
;
std
::
map
<
std
::
string
,
ArgumentContainer
>
outputs
;
std
::
map
<
std
::
string
,
std
::
unique_ptr
<
ArgumentContainer
>>
allocated_inputs
;
private
:
bool
calculated_once
;
};
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
Component
&
comp
)
{
comp
.
printself
(
os
);
return
os
;
}
void
Component
::
printself
(
std
::
ostream
&
os
)
const
{
for
(
auto
&
pair
:
this
->
inputs
)
{
os
<<
"input "
<<
pair
.
first
<<
":"
;
if
(
pair
.
second
!=
nullptr
)
os
<<
pair
.
second
->
get
()
<<
"
\n
"
;
else
os
<<
"not yet defined/computed
\n
"
;
}
for
(
auto
&
pair
:
this
->
outputs
)
{
os
<<
"output "
<<
pair
.
first
<<
":"
;
try
{
os
<<
pair
.
second
.
get
()
<<
"
\n
"
;
}
catch
(...)
{
os
<<
"not yet defined/computed
\n
"
;
}
}
}
void
Component
::
connect
(
const
std
::
string
&
input
,
ArgumentContainer
&
arg
)
{
auto
search
=
inputs
.
find
(
input
);
if
(
search
==
inputs
.
end
())
{
LM_FATAL
(
this
->
getID
()
+
":"
+
typeinfo
<
decltype
(
*
this
)
>
()
+
":"
+
input
+
": input not existing"
);
}
inputs
[
input
]
=
&
arg
;
};
template
<
typename
T
>
void
Component
::
connect
(
const
std
::
string
&
input
,
Argument
<
T
>
&&
arg
)
{
auto
search
=
inputs
.
find
(
input
);
if
(
search
==
inputs
.
end
())
{
LM_FATAL
(
this
->
getID
()
+
":"
+
typeinfo
<
decltype
(
*
this
)
>
()
+
":"
+
input
+
": input not existing"
);
}
if
(
inputs
[
input
]
==
nullptr
)
{
inputs
[
input
]
=
allocInput
(
input
);
}
*
inputs
[
input
]
=
std
::
move
(
arg
);
};
ArgumentContainer
*
Component
::
allocInput
(
const
std
::
string
&
input
)
{
allocated_inputs
[
input
]
=
std
::
make_unique
<
ArgumentContainer
>
();
return
allocated_inputs
[
input
].
get
();
}
void
Component
::
createOutput
(
const
std
::
string
&
output
)
{
outputs
[
output
]
=
ArgumentContainer
(
*
this
);
}
void
Component
::
createInput
(
const
std
::
string
&
input
)
{
inputs
[
input
]
=
nullptr
;
}
void
Component
::
removeInput
(
const
std
::
string
&
input
)
{
inputs
.
erase
(
input
);
}
bool
Component
::
isConnected
(
const
std
::
string
&
input
)
{
return
inputs
.
count
(
input
)
>
0
&&
inputs
[
input
]
!=
nullptr
;
}
/* --------------------------------------------------------------------- */
bool
ArgumentContainer
::
isAllocated
()
{
return
this
->
ptr
!=
nullptr
;
}
/* --------------------------------------------------------------------- */
ArgumentInterface
&
ArgumentContainer
::
get
(
bool
eval
)
{
if
(
this
->
component
!=
nullptr
&&
eval
)
{
this
->
component
->
compute
();
}
if
(
ptr
==
nullptr
)
throw
UnallocatedPointer
{};
return
*
ptr
;
}
/* --------------------------------------------------------------------- */
const
ArgumentInterface
&
ArgumentContainer
::
get
()
const
{
if
(
ptr
==
nullptr
)
LM_FATAL
(
"unallocated pointer"
);
return
*
ptr
;
}
/* --------------------------------------------------------------------- */
template
<
typename
possible_types
,
int
n
>
struct
_cpp_dynamic_cast
{
template
<
typename
Functor
,
typename
Arg
>
static
void
cast
(
Functor
&
func
,
Arg
&
arg
)
{
using
_type
=
std
::
remove_pointer_t
<
std
::
decay_t
<
std
::
tuple_element_t
<
n
,
possible_types
>>>
;
// std::cout << "testing type " << typeid(_type).name() << std::endl;
ArgumentInterface
&
arg_gotten
=
arg
->
get
();
// std::cout << "with object " << arg_gotten << std::endl;
if
(
auto
*
ref
=
dynamic_cast
<
Argument
<
_type
>
*>
(
&
arg_gotten
))
{
func
(
ref
->
get
());
return
;
}
if
(
auto
*
ref
=
dynamic_cast
<
Argument
<
_type
&>
*>
(
&
arg_gotten
))
{
func
(
ref
->
get
());
return
;
}
if
(
auto
*
ref
=
dynamic_cast
<
Argument
<
std
::
shared_ptr
<
_type
>>
*>
(
&
arg_gotten
))
{
func
(
*
(
ref
->
get
()));
return
;
}
_cpp_dynamic_cast
<
possible_types
,
n
-
1
>::
cast
(
func
,
arg
);
}
};
struct
ImpossibleCast
:
public
std
::
runtime_error
{
ImpossibleCast
(
ArgumentContainer
&
arg
)
:
std
::
runtime_error
(
"cannot cast component with type : "
+
arg
.
get
().
get_type_info
()),
arg
(
arg
)
{}
// std::cerr << typeid(Arg).name() << " " << arg << std::endl;
ArgumentContainer
&
arg
;
};
template
<
typename
possible_types
>
struct
_cpp_dynamic_cast
<
possible_types
,
-
1
>
{
template
<
typename
Functor
,
typename
Arg
>
static
void
cast
(
Functor
&
func
,
Arg
&
arg
)
{
throw
ImpossibleCast
(
*
arg
);
}
};
template
<
typename
possible_types
,
typename
Functor
,
typename
Arg
>
void
cpp_dynamic_cast
(
Functor
&
func
,
Arg
&
arg
)
{
constexpr
size_t
N
=
std
::
tuple_size
<
possible_types
>::
value
;
_cpp_dynamic_cast
<
possible_types
,
N
-
1
>::
cast
(
func
,
arg
);
}
/* --------------------------------------------------------------------- */
template
<
template
<
typename
>
class
TransformClass
,
typename
...
T
>
struct
apply_type_transform
{};
template
<
template
<
typename
>
class
TransformClass
,
typename
...
Ts
>
struct
apply_type_transform
<
TransformClass
,
std
::
tuple
<
Ts
...
>>
{
using
type
=
std
::
tuple
<
typename
TransformClass
<
Ts
>::
type
...
>
;
};
template
<
template
<
typename
>
class
TransformClass
,
typename
...
T
>
using
apply_type_transform_t
=
typename
apply_type_transform
<
TransformClass
,
T
...
>::
type
;
/* --------------------------------------------------------------------- */
template
<
typename
T
>
struct
expand_argument_type
{
using
types
=
std
::
tuple
<
T
>
;
};
/* --------------------------------------------------------------------- */
template
<
int
n
,
typename
T
>
struct
expand_argument_types
{
static
constexpr
auto
get
()
{
using
type
=
std
::
decay_t
<
std
::
tuple_element_t
<
n
,
T
>>
;
using
new_types
=
typename
expand_argument_type
<
type
>::
types
;
apply_type_transform_t
<
std
::
add_pointer
,
new_types
>
types_head
{};
auto
types_tail
=
expand_argument_types
<
n
-
1
,
T
>::
get
();
return
std
::
tuple_cat
(
types_head
,
types_tail
);
}
};
template
<
typename
T
>
struct
expand_argument_types
<-
1
,
T
>
{
static
constexpr
auto
get
()
{
return
std
::
tuple
<>
{};
}
};
/* --------------------------------------------------------------------- */
template
<
typename
T
,
UInt
n
>
struct
get_possible_types
{
static
auto
get
()
{
using
types
=
std
::
tuple_element_t
<
n
,
typename
T
::
possible_types
>
;
constexpr
size_t
N
=
std
::
tuple_size
<
types
>::
value
;
return
expand_argument_types
<
N
-
1
,
types
>::
get
();
}
};
/* --------------------------------------------------------------------- */
template
<
int
n
,
typename
tuple_type
,
typename
tuple_type_casted
>
struct
CallCast
{
template
<
typename
Obj
,
typename
Functor
>
static
void
call_compute
(
Obj
&
obj
,
Functor
&
functor
,
tuple_type
args
,
tuple_type_casted
args_casted
)
{
auto
possible_types
=
get_possible_types
<
Obj
,
n
>::
get
();
auto
argn
=
std
::
get
<
n
>
(
args
);
// functor that will be called after the dynamic cast is resolved
auto
&&
func_cast
=
[
&
](
auto
&&
casted_object
)
{
auto
tup
=
std
::
forward_as_tuple
(
casted_object
);
auto
new_args_casted
=
std
::
tuple_cat
(
tup
,
args_casted
);
CallCast
<
n
-
1
,
decltype
(
args
),
decltype
(
new_args_casted
)
>::
call_compute
(
obj
,
functor
,
args
,
new_args_casted
);
};
using
RawPossibleTypes
=
apply_type_transform_t
<
std
::
remove_pointer
,
decltype
(
possible_types
)
>
;
try
{
cpp_dynamic_cast
<
RawPossibleTypes
>
(
func_cast
,
argn
);
}
catch
(
ImpossibleCast
&
exception
)
{
auto
type_info
=
exception
.
arg
.
get
().
get_type_info
();
std
::
stringstream
sstr
;
sstr
<<
"Component "
<<
obj
.
getID
()
<<
"("
<<
typeinfo
<
decltype
(
obj
)
>
()
<<
")"
<<
" argument "
<<
n
+
1
<<
" has invalid type "
<<
type_info
<<
std
::
endl
<<
std
::
endl
;
sstr
<<
"possible types are:"
<<
std
::
endl
;
foreach_tuple
(
[
&
](
auto
&&
t
)
{
sstr
<<
typeinfo
<
std
::
remove_pointer_t
<
std
::
remove_reference_t
<
decltype
(
t
)
>>>
()
<<
std
::
endl
;
},
possible_types
);
std
::
string
mesg
=
sstr
.
str
();
LM_FATAL
(
mesg
);
}
}
};
// specialization for the end of recursion: all args have been dynamic casted
// need to call the function
template
<
typename
tuple_type
,
typename
tuple_type_formatted
>
struct
CallCast
<-
1
,
tuple_type
,
tuple_type_formatted
>
{
template
<
typename
Obj
,
typename
Functor
>
static
void
call_compute
(
Obj
&
obj
,
Functor
&
functor
,
tuple_type
args
,
tuple_type_formatted
args_formatted
)
{
apply
([
&
](
auto
&
...
args
)
{
functor
(
args
...);
},
args_formatted
);
constexpr
auto
nb_arguments
=
std
::
tuple_size
<
decltype
(
args_formatted
)
>::
value
;
if
(
nb_arguments
!=
1
)
return
;
// if a single argument, try to copyContainerInfo
auto
&&
a
=
getFirstArgument
<
decltype
(
args_formatted
)
>::
get
(
args_formatted
);
obj
.
_copyContainerInfo
(
a
);
}
};
/* --------------------------------------------------------------------- */
struct
MD
{};
struct
CONTINUUM
{};
struct
DD
{};
struct
COMPUTE
{};
struct
MESH
{};
struct
POINT
{};
/* --------------------------------------------------------------------- */
template
<
typename
Functor
,
typename
Obj
,
typename
...
Args
>
void
call_compute
(
Obj
&
obj
,
Functor
func
,
Args
&
...
args
)
{
auto
tup
=
std
::
make_tuple
(
&
args
...);
constexpr
size_t
N
=
std
::
tuple_size
<
decltype
(
tup
)
>::
value
;
// auto types = get_possible_types<Obj>::get();
// CallCast<N - 1, decltype(tup), std::tuple<>>::call_compute(
// obj, func, types, tup, std::tuple<>{});
CallCast
<
N
-
1
,
decltype
(
tup
),
std
::
tuple
<>>::
call_compute
(
obj
,
func
,
tup
,
std
::
tuple
<>
{});
}
/* --------------------------------------------------------------------- */
template
<
typename
Output
,
typename
Component
>
class
SingleOutputComponent
:
public
Component
{
public
:
using
Component
::
Component
;
SingleOutputComponent
(
const
LMID
&
name
)
:
LMObject
(
name
),
Component
(
name
)
{}
operator
Output
&
()
{
return
this
->
getOutput
().
get
().
template
cast
<
Output
>
();
}
auto
begin
()
{
return
(
*
this
)
->
begin
();
}
auto
end
()
{
return
(
*
this
)
->
end
();
}
Output
*
operator
->
()
{
return
&
static_cast
<
Output
&>
(
*
this
);
}
Output
&
operator
*
()
{
return
*
this
;
}
};
template
<
typename
T
>
struct
casted_component
{
template
<
typename
CastT
>
using
cast
=
SingleOutputComponent
<
CastT
,
T
>
;
};
/* --------------------------------------------------------------------- */
#include <boost/preprocessor.hpp>
// ************ Should boost this ***********************************
// #include "atom_model_list.hh"
// #include "continuum_model_list.hh"
// #include "dd_model_list.hh"
// ******************************************************************
template
<
UInt
Dim
>
class
RefPoint
;
template
<
UInt
Dim
>
class
RefPointData
;
template
<
UInt
Dim
>
class
RefGenericElem
;
template
<
typename
T
>
class
ContainerArray
;
template
<
typename
ContNode
,
typename
ContElem
>
class
ContainerMesh
;
template
<
UInt
Dim
>
using
ContainerGenericMesh
=
ContainerMesh
<
ContainerArray
<
RefPointData
<
Dim
>>
,
ContainerArray
<
RefGenericElem
<
Dim
>>>
;
// possible containers of MD
#ifdef LIBMULTISCALE_MD1D
class
ContainerMD1D
;
class
RefMD1D
;
#endif
#ifdef LIBMULTISCALE_LAMMPS_PLUGIN
template
<
UInt
Dim
>
class
ContainerLammps
;
template
<
UInt
Dim
>
class
RefLammps
;
#endif
using
md_containers
=
std
::
tuple
<
#ifdef LIBMULTISCALE_MD1D
ContainerMD1D
,
ContainerArray
<
RefMD1D
>
#endif
#if defined(LIBMULTISCALE_LAMMPS_PLUGIN) && defined(LIBMULTISCALE_MD1D)
,
#endif
#ifdef LIBMULTISCALE_LAMMPS_PLUGIN
ContainerLammps
<
2
>
,
ContainerLammps
<
3
>
,
ContainerArray
<
RefLammps
<
2
>>
,
ContainerArray
<
RefLammps
<
3
>>
#endif
>
;
template
<>
struct
expand_argument_type
<
MD
>
{
using
types
=
md_containers
;
};
#ifdef LIBMULTISCALE_PARADIS_PLUGIN
class
ContainerNodesParaDiS
;
class
ContainerElemsParaDiS
;
class
RefNodeParaDiS
;
class
RefElemParaDiS
;
#endif
template
<
UInt
Dim
>
class
RefGenericDDElem
;
template
<
UInt
Dim
>
using
ContainerGenericDDMesh
=
ContainerMesh
<
ContainerArray
<
RefPointData
<
Dim
>>
,
ContainerArray
<
RefGenericDDElem
<
Dim
>>>
;
// possible containers of DD
using
dd_containers
=
std
::
tuple
<
ContainerGenericDDMesh
<
2u
>
,
ContainerGenericDDMesh
<
3u
>
#ifdef LIBMULTISCALE_PARADIS_PLUGIN
,
ContainerMesh
<
ContainerNodesParaDiS
,
ContainerElemsParaDiS
>
,
ContainerMesh
<
ContainerArray
<
RefNodeParaDiS
>
,
ContainerArray
<
RefElemParaDiS
>>
#endif
>
;
template
<>
struct
expand_argument_type
<
DD
>
{
using
types
=
dd_containers
;
};
// possible containers of CONTINUUM
#ifdef LIBMULTISCALE_MECA1D
class
ContainerElemsMeca1D
;
class
ContainerNodesMeca1D
;
class
RefNodeMeca1D
;
class
RefElemMeca1D
;
#endif
using
continuum_containers
=
std
::
tuple
<
#ifdef LIBMULTISCALE_MECA1D
ContainerMesh
<
ContainerNodesMeca1D
,
ContainerElemsMeca1D
>
,
ContainerMesh
<
ContainerArray
<
RefNodeMeca1D
>
,
ContainerArray
<
RefElemMeca1D
>>
#endif
>
;
template
<>
struct
expand_argument_type
<
CONTINUUM
>
{
using
types
=
continuum_containers
;
};
// possible containers of points
using
point_containers
=
std
::
tuple
<
ContainerArray
<
RefPointData
<
1u
>>
,
ContainerArray
<
RefPointData
<
2u
>>
,
ContainerArray
<
RefPointData
<
3u
>>>
;
template
<>
struct
expand_argument_type
<
POINT
>
{
using
types
=
point_containers
;
};
// possible containers of meshes
using
mesh_containers
=
std
::
tuple
<
ContainerGenericMesh
<
1u
>
,
ContainerGenericMesh
<
2u
>
,
ContainerGenericMesh
<
3u
>>
;
template
<>
struct
expand_argument_type
<
MESH
>
{
using
types
=
mesh_containers
;
};
// possible computes as input
template
<>
struct
expand_argument_type
<
COMPUTE
>
{
using
types
=
std
::
tuple
<
ContainerArray
<
Real
>>
;
};
/* --------------------------------------------------------------------- */
template
<
typename
T
,
typename
Tuple
>
struct
has_type
;
template
<
typename
T
>
struct
has_type
<
T
,
std
::
tuple
<>>
:
std
::
false_type
{};
template
<
typename
T
,
typename
U
,
typename
...
Ts
>
struct
has_type
<
T
,
std
::
tuple
<
U
,
Ts
...
>>
:
has_type
<
T
,
std
::
tuple
<
Ts
...
>>
{};
template
<
typename
T
,
typename
...
Ts
>
struct
has_type
<
T
,
std
::
tuple
<
T
,
Ts
...
>>
:
std
::
true_type
{};
/* --------------------------------------------------------------------- */
template
<
typename
T
,
typename
RetT
=
void
>
struct
_enable_if_md
:
std
::
enable_if
<
has_type
<
T
,
md_containers
>::
value
,
RetT
>
{
};
template
<
typename
T
,
typename
RetT
=
void
>
using
enable_if_md
=
typename
_enable_if_md
<
T
,
RetT
>::
type
;
template
<
typename
T
,
typename
RetT
=
void
>
struct
_enable_if_mesh
:
std
::
enable_if
<
has_type
<
T
,
mesh_containers
>::
value
or
has_type
<
T
,
continuum_containers
>::
value
or
has_type
<
T
,
dd_containers
>::
value
,
RetT
>
{};
template
<
typename
T
,
typename
RetT
=
void
>
using
enable_if_mesh
=
typename
_enable_if_mesh
<
T
,
RetT
>::
type
;
template
<
typename
T
,
typename
RetT
=
void
>
struct
_enable_if_continuum
:
std
::
enable_if
<
has_type
<
T
,
continuum_containers
>::
value
,
RetT
>
{};
template
<
typename
T
,
typename
RetT
=
void
>
using
enable_if_continuum
=
typename
_enable_if_continuum
<
T
,
RetT
>::
type
;
template
<
typename
T
,
typename
RetT
=
void
>
struct
_enable_if_point
:
std
::
enable_if
<
has_type
<
T
,
md_containers
>::
value
or
has_type
<
T
,
point_containers
>::
value
,
RetT
>
{};
template
<
typename
T
,
typename
RetT
=
void
>
using
enable_if_point
=
typename
_enable_if_point
<
T
,
RetT
>::
type
;
template
<
typename
T
,
typename
RetT
=
void
>
struct
_enable_if_dd
:
std
::
enable_if
<
has_type
<
T
,
dd_containers
>::
value
,
RetT
>
{
};
template
<
typename
T
,
typename
RetT
=
void
>
using
enable_if_dd
=
typename
_enable_if_dd
<
T
,
RetT
>::
type
;
/* --------------------------------------------------------------------- */
#define DECLARE_INPUT(...) \
using possible_types = std::tuple<std::tuple<__VA_ARGS__>>
#define DECLARE_MULTIPLE_INPUT(...) \
using possible_types = std::tuple<__VA_ARGS__>
/* --------------------------------------------------------------------- */
__END_LIBMULTISCALE__
#endif
/* __LIBMULTISCALE_COMPONENT_LIBMULTISCALE_HH__ */
Event Timeline
Log In to Comment