vtk-m2/vtkm/internal/FunctionInterfaceDetailPre.h.in
Robert Maynard c631dccfcb Invocation parameters are now non const and can be 'modified'
The invocation parameters need to be non const as we want to
be able to call non-const methods like `PrepareForOutput` on them
from a transport function.

The original implementation abused the fact that everything
could be copied by value and have that work properly. But
when we start introducing virtual classes copying by value of
a base type can cause type slicing.
2018-07-06 14:27:36 -04:00

388 lines
12 KiB
C

//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
$# This file uses the pyexpander macro processing utility to build the
$# FunctionInterface facilities that use a variable number of arguments.
$# Information, documentation, and downloads for pyexpander can be found at:
$#
$# http://pyexpander.sourceforge.net/
$#
$# To build the source code, execute the following (after installing
$# pyexpander, of course):
$#
$# expander.py FunctionInterfaceDetailPre.h.in > FunctionInterfaceDetailPre.h
$#
$# Ignore the following comment. It is meant for the generated file.
// **** DO NOT EDIT THIS FILE!!! ****
// This file is automatically generated by FunctionInterfaceDetailPre.h.in
#ifndef vtk_m_internal_FunctionInterfaceDetailPre_h
#define vtk_m_internal_FunctionInterfaceDetailPre_h
#if !defined(vtk_m_internal_FunctionInterface_h) && !defined(VTKM_TEST_HEADER_BUILD)
#error FunctionInterfaceDetailPre.h must be included from FunctionInterface.h
#endif
#include <vtkm/Types.h>
#include <vtkm/internal/IndexTag.h>
#include <type_traits>
#include <vtkm/internal/brigand.hpp>
$py(max_parameters=20)\
#define VTKM_MAX_FUNCTION_PARAMETERS $(max_parameters)
$# Python commands used in template expansion.
$py(
def comma_if(flag):
if flag:
return ','
else:
return '';
def ptype(num, name=""):
if num == 0:
return '%sR' % name
else:
return '%sP%d' % (name, num)
def template_params(num_params, start=0, name=''):
if num_params < start:
return ''
result = 'typename %s' % ptype(start, name)
for param in xrange(start+1, num_params+1):
result += ',\n typename %s' % ptype(param, name)
return result
def signature(num_params, return_type=ptype(0), name=''):
result = '%s(' % return_type
if num_params > 0:
result += ptype(1, name)
for param in xrange(2, num_params+1):
result += ', %s' % ptype(param, name)
result += ')'
return result
)\
$#
$extend(comma_if, ptype, template_params, signature)\
namespace vtkm
{
namespace internal
{
/// This struct is used internally by FunctionInterface to store the return
/// value of a function. There is a special implementation for a return type of
/// void, which stores nothing.
///
template <typename T>
struct FunctionInterfaceReturnContainer
{
T Value;
static constexpr bool VALID = true;
};
template <>
struct FunctionInterfaceReturnContainer<void>
{
// Nothing to store for void return.
static constexpr bool VALID = false;
};
namespace detail
{
//============================================================================
// This templated class contains the state of parameters. If you get a compiler
// error stating that this class is not specialized, that probably means that
// you are using FunctionInterface with an unsupported number of arguments.
template <typename FunctionSignature>
struct ParameterContainer;
// clang-format off
$for(num_params in range(0, max_parameters+1))\
template <$template_params(num_params)>
struct ParameterContainer<$signature(num_params)>
{
VTKM_SUPPRESS_EXEC_WARNINGS
~ParameterContainer() = default;
$for(param_index in range(1, num_params+1))\
$ptype(param_index) Parameter$(param_index);
$endfor\
};
$endfor\
// clang-format on
//============================================================================
template <typename>
struct FunctionSigInfo;
template <typename R, typename... ArgTypes>
struct FunctionSigInfo<R(ArgTypes...)>
{
static constexpr std::size_t Arity = sizeof...(ArgTypes);
using ArityType = std::integral_constant<int, static_cast<int>(Arity)>;
using ResultType = R;
using Components = brigand::list<R, ArgTypes...>;
using Parameters = brigand::list<ArgTypes...>;
};
template <int, typename>
struct AtType;
template <int Index, typename R, typename... ArgTypes>
struct AtType<Index, R(ArgTypes...)>
{
using type = brigand::at_c<brigand::list<R, ArgTypes...>, Index>;
};
template <typename Collection, typename NewType>
struct AppendType;
template <template <typename...> class L, typename T, typename NT, typename... U>
struct AppendType<L<T, U...>, NT>
{
using type = T(U..., NT);
};
template <typename Collection>
struct AsSigType;
template <template <typename...> class L, typename T, typename... U>
struct AsSigType<L<T, U...>>
{
using type = T(U...);
};
template <typename Components, vtkm::IdComponent ParameterIndex, typename NewType>
class ReplaceType
{
using Index = std::integral_constant<std::size_t, (std::size_t)ParameterIndex>;
using split = brigand::split_at<Components, Index>;
using front = brigand::push_back<brigand::front<split>, NewType>;
using back = brigand::pop_front<brigand::back<split>>;
using replaced = brigand::append<front, back>;
public:
using type = typename AsSigType<replaced>::type;
};
//============================================================================
template <int ParameterIndex>
struct ParameterContainerAccess;
$for(param_index in range(1, max_parameters+1))\
template <>
struct ParameterContainerAccess<$(param_index)>
{
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename FunctionSignature>
VTKM_EXEC_CONT const typename AtType<$(param_index), FunctionSignature>::type& Get(
const ParameterContainer<FunctionSignature>& parameters)
{
return parameters.Parameter$(param_index);
}
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename FunctionSignature>
VTKM_EXEC_CONT void Set(ParameterContainer<FunctionSignature>& parameters,
const typename AtType<$(param_index), FunctionSignature>::type& value)
{
parameters.Parameter$(param_index) = value;
}
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename FunctionSignatureDest, typename FunctionSignatureSrc>
VTKM_EXEC_CONT void Move(ParameterContainer<FunctionSignatureDest>& dest,
const ParameterContainer<FunctionSignatureSrc>& src)
{
dest.Parameter$(param_index) = std::move(src.Parameter$(param_index));
}
};
$endfor\
//============================================================================
template <vtkm::IdComponent NumToCopy>
struct CopyAllParameters;
$for(num_params in range(1, max_parameters+1))\
template <>
struct CopyAllParameters<$(num_params)>
{
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename DestSignature, typename SrcSignature>
VTKM_EXEC_CONT void Copy(vtkm::internal::detail::ParameterContainer<DestSignature>& dest,
const vtkm::internal::detail::ParameterContainer<SrcSignature>& src)
{
$for(param_index in range(1, num_params+1))\
dest.Parameter$(param_index) = src.Parameter$(param_index);
$endfor\
}
};
$endfor\
template <>
struct CopyAllParameters<0>
{
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename DestSignature, typename SrcSignature>
VTKM_EXEC_CONT void Copy(vtkm::internal::detail::ParameterContainer<DestSignature>&,
const vtkm::internal::detail::ParameterContainer<SrcSignature>&)
{
// Nothing to copy.
}
};
//============================================================================
// clang-format off
$for(num_params in range(0, max_parameters+1))\
$# Invoke functions need both control and execution versions
$for(environment in ['Cont', 'Exec'])\
$# Invoke functions also need to accept const and non-const versions of the functor
$for(functor_const in ['const ', ''])\
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename Functor,
typename TransformFunctor,
$template_params(num_params)>
VTKM_$(environment.upper()) void DoInvoke$(environment)($(functor_const)Functor& f,
ParameterContainer<$signature(num_params)>& parameters,
FunctionInterfaceReturnContainer<$ptype(0)>& result,
const TransformFunctor& transform)
{
$if(num_params < 1)\
(void)parameters;
result.Value = transform(f());
$else\
result.Value = transform(f(
$for(param_index in xrange(1, num_params))\
transform(parameters.Parameter$(param_index)),
$endfor\
transform(parameters.Parameter$(num_params))));
$endif\
}
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename Functor,
typename TransformFunctor$comma_if(num_params>0)
$template_params(num_params,1)>
VTKM_$(environment.upper()) void DoInvoke$(environment)($(functor_const)Functor& f,
ParameterContainer<$signature(num_params,'void')>& parameters,
FunctionInterfaceReturnContainer<void>&,
const TransformFunctor& transform)
{
$if(num_params < 1)\
(void)parameters;
(void)transform;
f();
$else\
f(
$for(param_index in xrange(1, num_params))\
transform(parameters.Parameter$(param_index)),
$endfor\
transform(parameters.Parameter$(num_params)));
$endif\
}
$endfor\
$endfor\
$endfor\
// clang-format on
//============================================================================
template <typename OriginalSignature, typename Transform>
struct FunctionInterfaceStaticTransformType;
// clang-format off
$for(num_params in xrange(0, max_parameters))\
$# Transform functions need both control and execution versions
$for(environment in ['Cont', 'Exec'])\
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename Transform,
$template_params(num_params,0,'Original'),
$template_params(num_params,0,'Transformed')>
VTKM_$(environment.upper()) void DoStaticTransform$(environment)(
const Transform& transform,
ParameterContainer<$signature(num_params,ptype(0,'Original'),'Original')>& originalParameters,
ParameterContainer<$signature(num_params,ptype(0,'Transformed'),'Transformed')>& transformedParameters)
{
$if(num_params < 1)\
(void)transform;
(void)originalParameters;
(void)transformedParameters;
$else\
$for(param_index in xrange(1, num_params+1))\
transformedParameters.Parameter$(param_index) =
transform(originalParameters.Parameter$(param_index), vtkm::internal::IndexTag<$(param_index)>());
$endfor\
$endif\
}
$endfor\
$endfor\
// clang-format on
//============================================================================
// clang-format off
$for(num_params in xrange(0, max_parameters))\
$# ForEach functions need both control and execution versions
$for(environment in ['Cont', 'Exec'])\
$# ForEach functions also need to accept const and non-const versions of the FunctionInterface
$for(function_interface_const in ['const ', ''])\
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename Functor,
$template_params(num_params)>
VTKM_$(environment.upper()) void DoForEach$(environment)(
const Functor& f,
$(function_interface_const)ParameterContainer<$signature(num_params)>& parameters)
{
$if(num_params < 1)\
(void)f;
(void)parameters;
$else\
$for(param_index in xrange(1, num_params+1))\
f(parameters.Parameter$(param_index), vtkm::internal::IndexTag<$(param_index)>());
$endfor\
$endif\
}
$endfor\
$endfor\
$endfor\
// clang-format on
} // namespace detail
}
} // namespace vtkm::internal
#endif //vtk_m_internal_FunctionInterfaceDetailPre_h