FunctionInterface.h 33.3 KB
Newer Older
1 2 3 4 5 6 7 8
//============================================================================
//  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.
//
Kenneth Moreland's avatar
Kenneth Moreland committed
9
//  Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
10
//  Copyright 2014 UT-Battelle, LLC.
11
//  Copyright 2014 Los Alamos National Security.
12
//
Kenneth Moreland's avatar
Kenneth Moreland committed
13
//  Under the terms of Contract DE-NA0003525 with NTESS,
14 15 16 17 18 19
//  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.
//============================================================================
20 21
#ifndef vtk_m_internal_FunctionInterface_h
#define vtk_m_internal_FunctionInterface_h
22 23 24

#include <vtkm/Types.h>

25
#include <vtkm/internal/FunctionInterfaceDetailPre.h>
26
#include <vtkm/internal/IndexTag.h>
27

28 29
#include <utility>

30 31 32 33
namespace vtkm
{
namespace internal
{
34

35 36
namespace detail
{
37

38 39 40 41 42 43 44
struct IdentityFunctor
{
  template <typename T>
  VTKM_EXEC_CONT T& operator()(T& x) const
  {
    return x;
  }
45

46 47 48 49 50
  template <typename T>
  VTKM_EXEC_CONT const T& operator()(const T& x) const
  {
    return x;
  }
51
};
52 53 54

// These functions exist to help copy components of a FunctionInterface.

55 56 57
template <vtkm::IdComponent NumToMove, vtkm::IdComponent ParameterIndex = 1>
struct FunctionInterfaceMoveParameters
{
58
  VTKM_SUPPRESS_EXEC_WARNINGS
59 60 61 62
  template <typename DestSignature, typename SrcSignature>
  static VTKM_EXEC_CONT void Move(
    vtkm::internal::detail::ParameterContainer<DestSignature>& dest,
    const vtkm::internal::detail::ParameterContainer<SrcSignature>& src)
63
  {
64
    ParameterContainerAccess<ParameterIndex> pca;
65 66

    // using forwarding_type = typename AtType<ParameterIndex, SrcSignature>::type;
67 68 69 70
    pca.Move(dest, src);
    // std::forward<forwarding_type>(pca.Get(src)) );
    // pca.Get(src));
    FunctionInterfaceMoveParameters<NumToMove - 1, ParameterIndex + 1>::Move(dest, src);
71 72 73
  }
};

74 75 76 77 78 79
template <vtkm::IdComponent ParameterIndex>
struct FunctionInterfaceMoveParameters<0, ParameterIndex>
{
  template <typename DestSignature, typename SrcSignature>
  static VTKM_EXEC_CONT void Move(vtkm::internal::detail::ParameterContainer<DestSignature>&,
                                  const vtkm::internal::detail::ParameterContainer<SrcSignature>&)
80
  {
81
    // Nothing left to move.
82 83 84
  }
};

85
template <typename OriginalSignature, typename Transform>
86 87
struct FunctionInterfaceStaticTransformType;

88 89 90
template <typename OriginalFunction,
          typename NewFunction,
          typename TransformFunctor,
91
          typename FinishFunctor>
92 93 94 95
class FunctionInterfaceDynamicTransformContContinue;

} // namespace detail

96 97 98
/// \brief Holds parameters and result of a function.
///
/// To make VTK-m easier for the end user developer, the
99
/// \c Invoke method of dispatchers takes an arbitrary amount of
100 101 102 103 104
/// arguments that get transformed and swizzled into arguments and return value
/// for a worklet operator. In between these two invocations a complicated
/// series of transformations and operations can occur.
///
/// Supporting arbitrary function and template arguments is difficult and
luz.paz's avatar
luz.paz committed
105
/// really requires separate implementations for ANSI and C++11 versions of
106 107 108 109 110 111
/// compilers. Thus, variatic template arguments are, at this point in time,
/// something to be avoided when possible. The intention of \c
/// FunctionInterface is to collect most of the variatic template code into one
/// place. The \c FunctionInterface template class takes a function signature,
/// which can have a variable number of arguments. The \c FunctionInterface
/// will hold in its state a copy of all input parameters (regardless of number
112
/// or type) and the return value if it exists (i.e. non-nullptr) and the function
113 114 115 116 117 118 119 120 121 122 123 124
/// has been invoked. This means that all arguments can be passed around in a
/// single object so that objects and functions dealing with these variadic
/// parameters can be templated on a single type (the type of \c
/// FunctionInterface).
///
/// Note that the indexing of the parameters in a \c FunctionInterface starts
/// at 1. You can think of the return value being the parameter at index 0,
/// even if there is no return value. Although this is uncommon in C++, it
/// matches better the parameter indexing for other classes that deal with
/// function signatures.
///
/// The \c FunctionInterface contains several ways to invoke a functor whose
125 126
/// parameters match those of the function interface. This allows you to
/// complete the transition of calling an arbitrary function (like a worklet).
127
///
128 129
/// The following is a rundown of how a \c FunctionInterface is created and
/// used. See the independent documentation for more details.
130 131 132 133 134 135 136 137
///
/// Use the \c make_FunctionInterface function to create a \c FunctionInterface
/// and initialize the state of all the parameters. \c make_FunctionInterface
/// takes a variable number of arguments, one for each parameter. Since the
/// return type is not specified as an argument, you must always specify it as
/// a template parameter.
///
/// \code{.cpp}
138
/// vtkm::internal::FunctionInterface<void(vtkm::IdComponent,double,char)> functionInterface =
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
///     vtkm::internal::make_FunctionInterface<void>(1, 2.5, 'a');
/// \endcode
///
/// The number of parameters can be retrieved either with the constant field
/// \c ARITY or with the \c GetArity method.
///
/// \code{.cpp}
/// functionInterface.GetArity();
/// \endcode
///
/// You can get a particular parameter using the templated method \c
/// GetParameter. The template parameter is the index of the parameter
/// (starting at 1). Note that if the \c FunctionInterface is used in a
/// templated function or method where the type is not fully resolved, you need
/// to use the \c template keyword. One of the two forms should work. Try
/// switching if you get a compiler error.
///
/// \code{.cpp}
/// // Use this form if functionInterface is a fully resolved type.
/// functionInterface.GetParameter<1>();
///
/// // Use this form if functionInterface is partially specified.
/// functionInterface.template GetParameter<1>();
/// \endcode
///
/// Likewise, there is a \c SetParameter method for changing parameters. The
/// same rules for indexing and template specification apply.
///
/// \code{.cpp}
/// // Use this form if functionInterface is a fully resolved type.
/// functionInterface.SetParameter<1>(100);
///
/// // Use this form if functionInterface is partially specified.
/// functionInterface.template SetParameter<1>(100);
/// \endcode
///
/// \c FunctionInterface can invoke a functor of a matching signature using the
/// parameters stored within. If the functor returns a value, that return value
/// will be stored in the \c FunctionInterface object for later retrieval.
/// There are several versions of the invoke method including those for the
/// control and execution environments as well as methods that allow
/// transformation of the parameters and return value. See the method document
/// for more details.
///
/// \code{.cpp}
/// functionInterface.InvokeCont(Functor());
/// \endcode
///
/// Once a functor has been invoked, the return value can be retrieved with the
/// \c GetReturnValue method. \c GetReturnValue should only be used if the
/// function signature has a non-void return value. Otherwise calling this
/// method will result in a compile error.
///
/// \code{.cpp}
/// functionInterface.GetReturnValue();
/// \endcode
///
/// Providing the appropriate template specification to specialize when there
/// is no return value can be done but can be tricky. To make it easier, \c
/// FunctionInterface also has a \c GetReturnValueSafe method that provides the
/// return value wrapped in a \c FunctionInterfaceReturnContainer structure.
/// This will work regardless of whether the return value exists (although this
/// container might be empty). Specializing on the type of \c
/// FunctionInterfaceReturnContainer is much easier.
///
/// \code{.cpp}
/// functionInterface.GetReturnValueSafe();
/// \endcode
///
/// \c FunctionInterface also provides several methods for modifying the
/// parameters. First, the \c Append method tacks an additional parameter to
/// the end of the function signature.
///
/// \code{.cpp}
/// functionInterface.Append<std::string>(std::string("New Arg"));
/// \endcode
///
/// Next, the \c Replace method removes a parameter at a particular position
/// and replaces it with another object of a different type.
///
/// \code{.cpp}
/// functionInterface.Replace<1>(std::string("new first argument"));
/// \endcode
///
/// Finally, there are a couple of ways to replace all of the parameters at
/// once. The \c StaticTransform methods take a transform functor that modifies
/// each of the parameters. The \c DynamicTransform methods similarly take a
/// transform functor, but is called in a different way to defer the type
/// resolution to run time. See the documentation for each of these methods for
/// details on how they are used.
///
230
template <typename FunctionSignature>
231 232
class FunctionInterface
{
233
  template <typename OtherSignature>
234 235 236
  friend class FunctionInterface;

public:
237
  using Signature = FunctionSignature;
238

239
  VTKM_SUPPRESS_EXEC_WARNINGS
240 241 242
  FunctionInterface()
    : Result()
    , Parameters()
243 244 245
  {
  }

246 247 248 249 250 251 252
  VTKM_SUPPRESS_EXEC_WARNINGS
  explicit FunctionInterface(const detail::ParameterContainer<FunctionSignature>& p)
    : Result()
    , Parameters(p)
  {
  }

253
  // the number of parameters as an integral constant
254 255 256 257 258
  using SigInfo = detail::FunctionSigInfo<FunctionSignature>;
  using SignatureArity = typename SigInfo::ArityType;
  using ResultType = typename SigInfo::ResultType;
  using ComponentSig = typename SigInfo::Components;
  using ParameterSig = typename SigInfo::Parameters;
259

260 261 262
  template <vtkm::IdComponent ParameterIndex>
  struct ParameterType
  {
263
    using type = typename detail::AtType<ParameterIndex, FunctionSignature>::type;
264
  };
265

266 267 268 269
  static const bool RETURN_VALID = FunctionInterfaceReturnContainer<ResultType>::VALID;

  /// The number of parameters in this \c Function Interface.
  ///
270
  static const vtkm::IdComponent ARITY = SigInfo::Arity;
271 272 273 274

  /// Returns the number of parameters held in this \c FunctionInterface. The
  /// return value is the same as \c ARITY.
  ///
275
  VTKM_EXEC_CONT
276
  vtkm::IdComponent GetArity() const { return ARITY; }
277 278 279 280 281

  /// Retrieves the return value from the last invocation called. This method
  /// will result in a compiler error if used with a function having a void
  /// return type.
  ///
282
  VTKM_EXEC_CONT
283 284 285 286 287 288 289 290
  ResultType GetReturnValue() const { return this->Result.Value; }

  /// Retrieves the return value from the last invocation wrapped in a \c
  /// FunctionInterfaceReturnContainer object. This call can succeed even if
  /// the return type is void. You still have to somehow check to make sure the
  /// return is non-void before trying to use it, but using this method can
  /// simplify templated programming.
  ///
291
  VTKM_EXEC_CONT
292
  const FunctionInterfaceReturnContainer<ResultType>& GetReturnValueSafe() const
293 294 295
  {
    return this->Result;
  }
296
  VTKM_EXEC_CONT
297
  FunctionInterfaceReturnContainer<ResultType>& GetReturnValueSafe() { return this->Result; }
298 299

  /// Gets the value for the parameter of the given index. Parameters are
300 301 302 303 304 305 306
  /// indexed starting at 1. To use this method you have to specify a static,
  /// compile time index. There are two ways to specify the index. The first is
  /// to specify a specific template parameter (e.g.
  /// <tt>GetParameter<1>()</tt>). Note that if you are using FunctionInterface
  /// within a template (which is almost always the case), then you will have
  /// to use the template keyword. For example, here is a simple implementation
  /// of a method that grabs the first parameter of FunctionInterface.
307 308 309
  ///
  /// \code{.cpp}
  /// template<FunctionSignature>
310
  /// void Foo(const vtkm::internal::FunctionInterface<FunctionSignature> &fInterface)
311 312 313 314 315
  /// {
  ///   bar(fInterface.template GetParameter<1>());
  /// }
  /// \endcode
  ///
316 317 318 319 320 321 322 323 324 325 326 327 328
  /// Alternatively the \c GetParameter method also has an optional argument
  /// that can be a \c IndexTag that specifies the parameter index. Here is
  /// a repeat of the previous example using this method.
  ///
  /// \code{.cpp}
  /// template<FunctionSignature>
  /// void Foo(const vtkm::internal::FunctionInterface<FunctionSignature> &fInterface)
  /// {
  ///   using vtkm::internal::IndexTag;
  ///   bar(fInterface.GetParameter(IndexTag<1>()));
  /// }
  /// \endcode
  ///
329 330 331 332
  template <vtkm::IdComponent ParameterIndex>
  VTKM_EXEC_CONT const typename ParameterType<ParameterIndex>::type& GetParameter(
    vtkm::internal::IndexTag<ParameterIndex> = vtkm::internal::IndexTag<ParameterIndex>()) const
  {
333
    return (detail::ParameterContainerAccess<ParameterIndex>()).Get(this->Parameters);
334 335
  }

336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
  /// Sets the value for the parameter of the given index. Parameters are
  /// indexed starting at 1. To use this method you have to specify a static,
  /// compile time index. There are two ways to specify the index. The first is
  /// to specify a specific template parameter (e.g.
  /// <tt>SetParameter<1>(value)</tt>). Note that if you are using
  /// FunctionInterface within a template (which is almost always the case),
  /// then you will have to use the template keyword. For example, here is a
  /// simple implementation of a method that grabs the first parameter of
  /// FunctionInterface.
  ///
  /// \code{.cpp}
  /// template<FunctionSignature>
  /// void Foo(vtkm::internal::FunctionInterface<FunctionSignature> &fInterface)
  /// {
  ///   fInterface.template SetParameter<1>(bar);
  /// }
  /// \endcode
  ///
  /// Alternatively the \c GetParameter method also has an optional argument
  /// that can be a \c IndexTag that specifies the parameter index. Here is
  /// a repeat of the previous example using this method.
  ///
  /// \code{.cpp}
  /// template<FunctionSignature>
  /// void Foo(vtkm::internal::FunctionInterface<FunctionSignature> &fInterface)
  /// {
  ///   using vtkm::internal::IndexTag;
  ///   fInterface.SetParameter(bar, IndexTag<1>());
  /// }
  /// \endcode
  ///
367 368 369 370 371 372
  /// Sets the value for the parameter of the given index. Parameters are
  /// indexed starting at 1. To use this method you have to specify the index
  /// as a template parameter. If you are using FunctionInterface within a
  /// template (which is almost always the case), then you will have to use the
  /// template keyword.
  ///
373 374 375 376
  template <vtkm::IdComponent ParameterIndex>
  VTKM_EXEC_CONT void SetParameter(
    const typename ParameterType<ParameterIndex>::type& parameter,
    vtkm::internal::IndexTag<ParameterIndex> = vtkm::internal::IndexTag<ParameterIndex>())
377
  {
378
    return (detail::ParameterContainerAccess<ParameterIndex>()).Set(this->Parameters, parameter);
379 380 381 382 383 384 385 386
  }

  /// Copies the parameters and return values from the given \c
  /// FunctionInterface to this object. The types must be copiable from source
  /// to destination. If the number of parameters in the two objects are not
  /// the same, copies the first N arguments, where N is the smaller arity of
  /// the two function interfaces.
  ///
387 388
  template <typename SrcFunctionSignature>
  void Copy(const FunctionInterface<SrcFunctionSignature>& src)
389 390
  {
    this->Result = src.GetReturnValueSafe();
391

392
    constexpr vtkm::UInt16 minArity = (ARITY < FunctionInterface<SrcFunctionSignature>::ARITY)
393 394
      ? ARITY
      : FunctionInterface<SrcFunctionSignature>::ARITY;
395 396

    (detail::CopyAllParameters<minArity>()).Copy(this->Parameters, src.Parameters);
397 398
  }

399
  void Copy(const FunctionInterface<FunctionSignature>& src)
400 401 402
  { //optimized version for assignment/copy
    this->Result = src.GetReturnValueSafe();
    this->Parameters = src.Parameters;
403 404 405 406 407 408 409 410 411
  }

  /// Invoke a function \c f using the arguments stored in this
  /// FunctionInterface.
  ///
  /// If this FunctionInterface specifies a non-void return value, then the
  /// result of the function call is stored within this FunctionInterface and
  /// can be retrieved with GetReturnValue().
  ///
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
  template <typename Function>
  VTKM_CONT void InvokeCont(const Function& f)
  {
    detail::DoInvokeCont(f, this->Parameters, this->Result, detail::IdentityFunctor());
  }
  template <typename Function>
  VTKM_CONT void InvokeCont(Function& f)
  {
    detail::DoInvokeCont(f, this->Parameters, this->Result, detail::IdentityFunctor());
  }
  template <typename Function>
  VTKM_EXEC void InvokeExec(const Function& f)
  {
    detail::DoInvokeExec(f, this->Parameters, this->Result, detail::IdentityFunctor());
  }
  template <typename Function>
  VTKM_EXEC void InvokeExec(Function& f)
  {
    detail::DoInvokeExec(f, this->Parameters, this->Result, detail::IdentityFunctor());
431 432 433 434 435 436 437 438 439 440 441
  }

  /// Invoke a function \c f using the arguments stored in this
  /// FunctionInterface and a transform.
  ///
  /// These versions of invoke also apply a transform to the input arguments.
  /// The transform is a second functor passed a second argument. If this
  /// FunctionInterface specifies a non-void return value, then the result of
  /// the function call is also transformed and stored within this
  /// FunctionInterface and can be retrieved with GetReturnValue().
  ///
442 443 444
  template <typename Function, typename TransformFunctor>
  VTKM_CONT void InvokeCont(const Function& f, const TransformFunctor& transform)
  {
445 446
    detail::DoInvokeCont(f, this->Parameters, this->Result, transform);
  }
447 448 449
  template <typename Function, typename TransformFunctor>
  VTKM_CONT void InvokeCont(Function& f, const TransformFunctor& transform)
  {
450 451
    detail::DoInvokeCont(f, this->Parameters, this->Result, transform);
  }
452 453 454
  template <typename Function, typename TransformFunctor>
  VTKM_EXEC void InvokeExec(const Function& f, const TransformFunctor& transform)
  {
455 456
    detail::DoInvokeExec(f, this->Parameters, this->Result, transform);
  }
457 458 459
  template <typename Function, typename TransformFunctor>
  VTKM_EXEC void InvokeExec(Function& f, const TransformFunctor& transform)
  {
460 461 462
    detail::DoInvokeExec(f, this->Parameters, this->Result, transform);
  }

463
  template <typename NewType>
464 465
  struct AppendType
  {
466
    using type = FunctionInterface<typename detail::AppendType<ComponentSig, NewType>::type>;
467 468
  };

469 470 471 472 473
  /// Returns a new \c FunctionInterface with all the parameters of this \c
  /// FunctionInterface and the given method argument appended to these
  /// parameters. The return type can be determined with the \c AppendType
  /// template.
  ///
474 475
  template <typename NewType>
  VTKM_CONT typename AppendType<NewType>::type Append(const NewType& newParameter) const
476
  {
477
    using AppendSignature = typename detail::AppendType<ComponentSig, NewType>::type;
478

479
    FunctionInterface<AppendSignature> appendedFuncInterface;
480
    appendedFuncInterface.Copy(*this);
481
    appendedFuncInterface.template SetParameter<ARITY + 1>(newParameter);
482 483 484
    return appendedFuncInterface;
  }

485
  template <vtkm::IdComponent ParameterIndex, typename NewType>
486 487 488
  struct ReplaceType
  {
    using type =
489
      FunctionInterface<typename detail::ReplaceType<ComponentSig, ParameterIndex, NewType>::type>;
490 491
  };

492 493
  /// Returns a new \c FunctionInterface with all the parameters of this \c
  /// FunctionInterface except that the parameter indexed at the template
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
  /// parameter \c ParameterIndex (also specified with the optional second
  /// argument) is replaced with the given argument. This method can be used in
  /// place of SetParameter when the parameter type changes. The return type
  /// can be determined with the \c ReplaceType template.
  /// Gets the value for the parameter of the given index. Parameters are
  /// indexed starting at 1. To use this method you have to specify a static,
  /// compile time index. There are two ways to specify the index. The first is
  /// to specify a specific template parameter (e.g.
  /// <tt>GetParameter<1>()</tt>). Note that if you are using FunctionInterface
  /// within a template (which is almost always the case), then you will have
  /// to use the template keyword. For example, here is a simple implementation
  /// of a method that grabs the first parameter of FunctionInterface.
  ///
  /// \code{.cpp}
  /// template<FunctionSignature>
  /// void Foo(const vtkm::internal::FunctionInterface<FunctionSignature> &fInterface)
  /// {
  ///   bar(fInterface.template GetParameter<1>());
  /// }
  /// \endcode
  ///
  /// Alternatively the \c GetParameter method also has an optional argument
  /// that can be a \c IndexTag that specifies the parameter index. Here is
  /// a repeat of the previous example using this method.
  ///
  /// \code{.cpp}
  /// template<FunctionSignature>
  /// void Foo(const vtkm::internal::FunctionInterface<FunctionSignature> &fInterface)
  /// {
  ///   using vtkm::internal::IndexTag;
  ///   bar(fInterface.GetParameter(IndexTag<1>()));
  /// }
  /// \endcode
  ///
528
  ///
529 530 531 532
  template <vtkm::IdComponent ParameterIndex, typename NewType>
  VTKM_CONT typename ReplaceType<ParameterIndex, NewType>::type Replace(
    const NewType& newParameter,
    vtkm::internal::IndexTag<ParameterIndex> = vtkm::internal::IndexTag<ParameterIndex>()) const
533 534
  {

535 536
    using ReplaceSigType =
      typename detail::ReplaceType<ComponentSig, ParameterIndex, NewType>::type;
537
    FunctionInterface<ReplaceSigType> replacedFuncInterface;
538

539 540
    detail::FunctionInterfaceMoveParameters<ParameterIndex - 1>::Move(
      replacedFuncInterface.Parameters, this->Parameters);
541

542
    replacedFuncInterface.template SetParameter<ParameterIndex>(newParameter);
543

544 545
    detail::FunctionInterfaceMoveParameters<ARITY - ParameterIndex, ParameterIndex + 1>::Move(
      replacedFuncInterface.Parameters, this->Parameters);
546 547 548
    return replacedFuncInterface;
  }

549 550 551
  template <typename Transform>
  struct StaticTransformType
  {
552 553
    using type = FunctionInterface<
      typename detail::FunctionInterfaceStaticTransformType<FunctionSignature, Transform>::type>;
554 555 556 557 558
  };

  /// \brief Transforms the \c FunctionInterface based on compile-time
  /// information.
  ///
559
  /// The \c StaticTransform methods transform all the parameters of this \c
560
  /// FunctionInterface to different types and values based on compile-time
561 562 563 564 565 566 567
  /// information. It operates by accepting a functor that two arguments. The
  /// first argument is the parameter to transform and the second argument is
  /// an \c IndexTag specifying the index of the parameter (which can be
  /// ignored in many cases). The functor's return value is the transformed
  /// value. The functor must also contain a templated struct name ReturnType
  /// with an internal type named \c type that defines the return type of the
  /// transform for a given input type and parameter index.
568 569
  ///
  /// The transformation is only applied to the parameters of the function. The
Kenneth Moreland's avatar
Kenneth Moreland committed
570
  /// return argument is unaffected.
571 572 573 574 575 576 577 578 579 580
  ///
  /// The return type can be determined with the \c StaticTransformType
  /// template.
  ///
  /// Here is an example of a transformation that converts a \c
  /// FunctionInterface to another \c FunctionInterface containing pointers to
  /// all of the parameters.
  ///
  /// \code
  /// struct MyTransformFunctor {
581
  ///   template<typename T, vtkm::IdComponent Index>
582 583 584 585
  ///   struct ReturnType {
  ///     typedef const T *type;
  ///   };
  ///
586
  ///   template<typename T, vtkm::IdComponent Index>
587
  ///   VTKM_CONT
588
  ///   const T *operator()(const T &x, vtkm::internal::IndexTag<Index>) const {
589 590 591 592 593 594 595 596 597 598 599 600
  ///     return &x;
  ///   }
  /// };
  ///
  /// template<typename FunctionSignature>
  /// typename vtkm::internal::FunctionInterface<FunctionSignature>::template StaticTransformType<MyTransformFunctor>::type
  /// ImportantStuff(const vtkm::internal::FunctionInterface<FunctionSignature> &funcInterface)
  /// {
  ///   return funcInterface.StaticTransformCont(MyTransformFunctor());
  /// }
  /// \endcode
  ///
601 602 603
  template <typename Transform>
  VTKM_CONT typename StaticTransformType<Transform>::type StaticTransformCont(
    const Transform& transform) const
604 605
  {
    typename StaticTransformType<Transform>::type newFuncInterface;
606
    detail::DoStaticTransformCont(transform, this->Parameters, newFuncInterface.Parameters);
607 608
    return newFuncInterface;
  }
609 610 611
  template <typename Transform>
  VTKM_EXEC typename StaticTransformType<Transform>::type StaticTransformExec(
    const Transform& transform) const
612 613
  {
    typename StaticTransformType<Transform>::type newFuncInterface;
614
    detail::DoStaticTransformExec(transform, this->Parameters, newFuncInterface.Parameters);
615 616 617
    return newFuncInterface;
  }

618 619 620 621 622
  /// \brief Transforms the \c FunctionInterface based on run-time information.
  ///
  /// The \c DynamicTransform method transforms all the parameters of this \c
  /// FunctionInterface to different types and values based on run-time
  /// information. It operates by accepting two functors. The first functor
623 624 625
  /// accepts three arguments. The first argument is a parameter to transform,
  /// the second is a functor to call with the transformed result, and the third
  /// is an instance of \c IndexTag denoting the index parameter..
626
  ///
627
  /// The second argument to \c DynamicTransform is another functor that
628 629 630 631 632 633
  /// accepts the transformed \c FunctionInterface and does something. If that
  /// transformed \c FunctionInterface has a return value, that return value
  /// will be passed back to this \c FunctionInterface.
  ///
  /// Here is a contrived but illustrative example. This transformation will
  /// pass all arguments except any string that looks like a number will be
Kenneth Moreland's avatar
Kenneth Moreland committed
634
  /// converted to a vtkm::FloatDefault. Note that because the types are not
635
  /// determined until runtime, this transform cannot be determined at compile
636 637 638 639
  /// time with meta-template programming.
  ///
  /// \code
  /// struct MyTransformFunctor {
640 641 642
  ///   template<typename InputType,
  ///            typename ContinueFunctor,
  ///            vtkm::IdComponent Index>
643
  ///   VTKM_CONT
644
  ///   void operator()(const InputType &input,
645 646
  ///                   const ContinueFunctor &continueFunc,
  ///                   vtkm::internal::IndexTag<Index>) const
647
  ///   {
Kenneth Moreland's avatar
Kenneth Moreland committed
648
  ///     continueFunc(input);
649 650
  ///   }
  ///
651
  ///   template<typename ContinueFunctor, vtkm::IdComponent Index>
652
  ///   VTKM_CONT
653
  ///   void operator()(const std::string &input,
654 655
  ///                   const ContinueFunctor &continueFunc,
  ///                   vtkm::internal::IndexTag<Index>) const
656 657 658 659
  ///   {
  ///     if ((input[0] >= '0' && (input[0] <= '9'))
  ///     {
  ///       std::stringstream stream(input);
Kenneth Moreland's avatar
Kenneth Moreland committed
660
  ///       vtkm::FloatDefault value;
661 662 663 664 665 666 667 668 669 670 671 672
  ///       stream >> value;
  ///       continueFunc(value);
  ///     }
  ///     else
  ///     {
  ///       continueFunc(input);
  ///     }
  ///   }
  /// };
  ///
  /// struct MyFinishFunctor {
  ///   template<typename FunctionSignature>
673
  ///   VTKM_CONT
674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
  ///   void operator()(vtkm::internal::FunctionInterface<FunctionSignature> &funcInterface) const
  ///   {
  ///     // Do something
  ///   }
  /// };
  ///
  /// template<typename FunctionSignature>
  /// void ImportantStuff(vtkm::internal::FunctionInterface<FunctionSignature> &funcInterface)
  /// {
  ///   funcInterface.DynamicTransformCont(MyContinueFunctor(), MyFinishFunctor());
  /// }
  /// \endcode
  ///
  /// An interesting feature of \c DynamicTransform is that there does not have
  /// to be a one-to-one transform. It is possible to make many valid
  /// transforms by calling the continue functor multiple times within the
  /// transform functor. It is also possible to abort the transform by not
  /// calling the continue functor.
  ///
693 694 695 696
  template <typename TransformFunctor, typename FinishFunctor>
  VTKM_CONT void DynamicTransformCont(const TransformFunctor& transform,
                                      const FinishFunctor& finish) const
  {
697 698 699 700 701
    using ContinueFunctorType =
      detail::FunctionInterfaceDynamicTransformContContinue<FunctionSignature,
                                                            ResultType(),
                                                            TransformFunctor,
                                                            FinishFunctor>;
702 703 704

    FunctionInterface<ResultType()> emptyInterface;
    ContinueFunctorType continueFunctor =
705
      ContinueFunctorType(*this, emptyInterface, transform, finish);
706 707

    continueFunctor.DoNextTransform(emptyInterface);
708
    //    this->Result = emptyInterface.GetReturnValueSafe();
709 710
  }

711 712
  /// \brief Applies a function to all the parameters.
  ///
713 714 715 716 717
  /// The \c ForEach methods take a functor and apply that functor to each of
  /// the parameters in the \c FunctionInterface. (Return values are not
  /// effected.) The first argument of the functor is the parameter value and
  /// the second argument is an \c IndexTag, which can be used to identify the
  /// index of the parameter.
718
  ///
719 720 721
  template <typename Functor>
  VTKM_CONT void ForEachCont(const Functor& f) const
  {
722 723
    detail::DoForEachCont(f, this->Parameters);
  }
724 725 726
  template <typename Functor>
  VTKM_CONT void ForEachCont(const Functor& f)
  {
727 728
    detail::DoForEachCont(f, this->Parameters);
  }
729 730 731
  template <typename Functor>
  VTKM_EXEC void ForEachExec(const Functor& f) const
  {
732 733
    detail::DoForEachExec(f, this->Parameters);
  }
734 735 736
  template <typename Functor>
  VTKM_EXEC void ForEachExec(const Functor& f)
  {
737 738 739
    detail::DoForEachExec(f, this->Parameters);
  }

740 741 742 743 744
private:
  vtkm::internal::FunctionInterfaceReturnContainer<ResultType> Result;
  detail::ParameterContainer<FunctionSignature> Parameters;
};

745 746
namespace detail
{
747

748 749 750
template <typename OriginalFunction,
          typename NewFunction,
          typename TransformFunctor,
751
          typename FinishFunctor>
752 753 754 755
class FunctionInterfaceDynamicTransformContContinue
{
public:
  FunctionInterfaceDynamicTransformContContinue(
756
    const vtkm::internal::FunctionInterface<OriginalFunction>& originalInterface,
757 758
    vtkm::internal::FunctionInterface<NewFunction>& newInterface,
    const TransformFunctor& transform,
759 760 761 762 763 764 765 766 767 768
    const FinishFunctor& finish)
    : OriginalInterface(originalInterface)
    , NewInterface(newInterface)
    , Transform(transform)
    , Finish(finish)
  {
  }

  template <typename T>
  VTKM_CONT void operator()(const T& newParameter) const
769
  {
770
    using NewFSigComp = typename FunctionInterface<NewFunction>::ComponentSig;
771

772
    //Determine if we should do the next transform
773
    using appended = brigand::push_back<NewFSigComp, T>;
774
    using interfaceSig = typename detail::AsSigType<appended>::type;
775
    using NextInterfaceType = FunctionInterface<interfaceSig>;
776

777 778
    static constexpr std::size_t newArity = NextInterfaceType::ARITY;
    static constexpr std::size_t oldArity = detail::FunctionSigInfo<OriginalFunction>::Arity;
779
    typedef std::integral_constant<bool, (newArity < oldArity)> ShouldDoNextTransformType;
780

781
    NextInterfaceType nextInterface = this->NewInterface.Append(newParameter);
782

783
    this->DoNextTransform(nextInterface, ShouldDoNextTransformType());
784
    this->NewInterface.GetReturnValueSafe() = nextInterface.GetReturnValueSafe();
785 786
  }

787 788
  template <typename NextFunction>
  void DoNextTransform(vtkm::internal::FunctionInterface<NextFunction>& nextInterface) const
789
  {
790 791 792 793
    using NextContinueType = FunctionInterfaceDynamicTransformContContinue<OriginalFunction,
                                                                           NextFunction,
                                                                           TransformFunctor,
                                                                           FinishFunctor>;
794 795
    NextContinueType nextContinue =
      NextContinueType(this->OriginalInterface, nextInterface, this->Transform, this->Finish);
796
    static const vtkm::IdComponent Index =
797
      vtkm::internal::FunctionInterface<NextFunction>::ARITY + 1;
798
    vtkm::internal::IndexTag<Index> indexTag;
799
    this->Transform(this->OriginalInterface.GetParameter(indexTag), nextContinue, indexTag);
800 801
  }

802
private:
803 804 805 806
  template <typename NextFunction>
  void DoNextTransform(vtkm::internal::FunctionInterface<NextFunction>& nextInterface,
                       std::true_type) const
  {
807 808 809 810
    using NextContinueType = FunctionInterfaceDynamicTransformContContinue<OriginalFunction,
                                                                           NextFunction,
                                                                           TransformFunctor,
                                                                           FinishFunctor>;
811 812
    NextContinueType nextContinue =
      NextContinueType(this->OriginalInterface, nextInterface, this->Transform, this->Finish);
813
    static const vtkm::IdComponent Index =
814
      vtkm::internal::FunctionInterface<NextFunction>::ARITY + 1;
815
    vtkm::internal::IndexTag<Index> indexTag;
816
    this->Transform(this->OriginalInterface.GetParameter(indexTag), nextContinue, indexTag);
817 818
  }

819 820 821
  template <typename NextFunction>
  void DoNextTransform(vtkm::internal::FunctionInterface<NextFunction>& nextInterface,
                       std::false_type) const
822 823 824 825 826
  {
    this->Finish(nextInterface);
  }

private:
827 828 829 830
  const vtkm::internal::FunctionInterface<OriginalFunction>& OriginalInterface;
  vtkm::internal::FunctionInterface<NewFunction>& NewInterface;
  const TransformFunctor& Transform;
  const FinishFunctor& Finish;
831

832 833 834 835
  void operator=(const FunctionInterfaceDynamicTransformContContinue<OriginalFunction,
                                                                     NewFunction,
                                                                     TransformFunctor,
                                                                     FinishFunctor>&) = delete;
836 837 838 839 840 841
};

} // namespace detail
}
} // namespace vtkm::internal

842 843
#include <vtkm/internal/FunctionInterfaceDetailPost.h>

844
#endif //vtk_m_internal_FunctionInterface_h