/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkDispatcher.h

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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.

=========================================================================*/

////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2001 by Andrei Alexandrescu
// This code accompanies the book:
// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
//     Patterns Applied". Copyright (c) 2001. Addison-Wesley.
// Permission to use, copy, modify, distribute and sell this software for any
//     purpose is hereby granted without fee, provided that the above copyright
//     notice appear in all copies and that both that copyright notice and this
//     permission notice appear in supporting documentation.
// The author or Addison-Wesley Longman make no representations about the
//     suitability of this software for any purpose. It is provided "as is"
//     without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
#ifndef vtkDispatcher_Private_h
#define vtkDispatcher_Private_h

#include "vtkConfigure.h"

#ifndef VTK_LEGACY_REMOVE
#ifndef __VTK_WRAP__

#include <cassert>
#include <memory>
#include <typeinfo>

namespace vtkDispatcherPrivate
{
////////////////////////////////////////////////////////////////////////////////
// Dispatch helper for reference functors
////////////////////////////////////////////////////////////////////////////////
template <class BaseLhs, class SomeLhs, typename RT, class CastLhs, class Fun>
class FunctorRefDispatcherHelper
{
  Fun& fun_;

public:
  typedef RT ResultType;

  FunctorRefDispatcherHelper(const FunctorRefDispatcherHelper& rhs)
    : fun_(rhs.fun_)
  {
  }
  FunctorRefDispatcherHelper(Fun& f)
    : fun_(f)
  {
  }

  ResultType operator()(BaseLhs& lhs) { return fun_(CastLhs::Cast(lhs)); }

private:
  FunctorRefDispatcherHelper& operator=(const FunctorRefDispatcherHelper& b);
};

////////////////////////////////////////////////////////////////////////////////
// Dispatch helper
////////////////////////////////////////////////////////////////////////////////
template <class BaseLhs, class SomeLhs, typename RT, class CastLhs, class Fun>
class FunctorDispatcherHelper
{
  Fun fun_;

public:
  typedef RT ResultType;

  FunctorDispatcherHelper(const FunctorDispatcherHelper& rhs)
    : fun_(rhs.fun_)
  {
  }
  FunctorDispatcherHelper(Fun fun)
    : fun_(fun)
  {
  }

  ResultType operator()(BaseLhs& lhs) { return fun_(CastLhs::Cast(lhs)); }
};

////////////////////////////////////////////////////////////////////////////////
// Parent class for all FunctorImpl, helps hide functor template args
////////////////////////////////////////////////////////////////////////////////
template <typename R, typename P1>
class FunctorImpl
{
public:
  typedef R ResultType;
  typedef P1 Parm1;

  virtual ~FunctorImpl() {}
  virtual R operator()(P1&) = 0;
  virtual FunctorImpl* DoClone() const = 0;

  template <class U>
  static U* Clone(U* pObj)
  {
    if (!pObj)
      return nullptr;
    U* pClone = static_cast<U*>(pObj->DoClone());
    assert(typeid(*pClone) == typeid(*pObj));
    return pClone;
  }

protected:
  FunctorImpl() {}
  FunctorImpl(const FunctorImpl&) {}

private:
  FunctorImpl& operator=(const FunctorImpl&) = delete;
};

////////////////////////////////////////////////////////////////////////////////
// Impl functor that calls a user functor
////////////////////////////////////////////////////////////////////////////////
template <class ParentFunctor, typename Fun>
class FunctorHandler : public ParentFunctor::Impl
{
  typedef typename ParentFunctor::Impl Base;

public:
  typedef typename Base::ResultType ResultType;
  typedef typename Base::Parm1 Parm1;

  FunctorHandler(Fun& fun)
    : f_(fun)
  {
  }
  ~FunctorHandler() override {}

  ResultType operator()(Parm1& p1) override { return f_(p1); }
  FunctorHandler* DoClone() const override { return new FunctorHandler(*this); }

private:
  Fun f_;
  FunctorHandler(const FunctorHandler& b)
    : ParentFunctor::Impl(b)
    , f_(b.f_)
  {
  }
  FunctorHandler& operator=(const FunctorHandler& b) = delete;
};

////////////////////////////////////////////////////////////////////////////////
// Functor wrapper class
////////////////////////////////////////////////////////////////////////////////
template <typename R, typename Parm1>
class Functor
{
public:
  typedef FunctorImpl<R, Parm1> Impl;
  typedef R ResultType;

  Functor()
    : spImpl_()
  {
  }

  Functor(const Functor& rhs)
    : spImpl_(Impl::Clone(rhs.spImpl_.get()))
  {
  }

  template <typename Fun>
  Functor(Fun fun)
    : spImpl_(new FunctorHandler<Functor, Fun>(fun))
  {
  }

  Functor& operator=(const Functor& rhs)
  {
    Functor copy(rhs);
    spImpl_.swap(copy.spImpl_);
    return *this;
  }

  ResultType operator()(Parm1& p1) { return (*spImpl_)(p1); }

private:
  std::unique_ptr<Impl> spImpl_;
};

}

namespace vtkDoubleDispatcherPrivate
{

////////////////////////////////////////////////////////////////////////////////
// Dispatch helper
////////////////////////////////////////////////////////////////////////////////
template <class BaseLhs, class BaseRhs, class SomeLhs, class SomeRhs, typename RT, class CastLhs,
  class CastRhs, class Fun>
class FunctorRefDispatcherHelper
{
  Fun& fun_;

public:
  typedef RT ResultType;
  FunctorRefDispatcherHelper(const FunctorRefDispatcherHelper& rhs)
    : fun_(rhs.fun_)
  {
  }
  FunctorRefDispatcherHelper(Fun& fun)
    : fun_(fun)
  {
  }

  ResultType operator()(BaseLhs& lhs, BaseRhs& rhs)
  {
    return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
  }

private:
  FunctorRefDispatcherHelper& operator=(const FunctorRefDispatcherHelper& b);
};

template <class BaseLhs, class BaseRhs, class SomeLhs, class SomeRhs, typename RT, class CastLhs,
  class CastRhs, class Fun>
class FunctorDoubleDispatcherHelper
{
  Fun fun_;

public:
  typedef RT ResultType;
  FunctorDoubleDispatcherHelper(const FunctorDoubleDispatcherHelper& rhs)
    : fun_(rhs.fun_)
  {
  }
  FunctorDoubleDispatcherHelper(Fun fun)
    : fun_(fun)
  {
  }

  ResultType operator()(BaseLhs& lhs, BaseRhs& rhs)
  {
    return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
  }
};

////////////////////////////////////////////////////////////////////////////////
// Parent class for all FunctorImpl, helps hide functor template args
////////////////////////////////////////////////////////////////////////////////
template <typename R, typename P1, typename P2>
class FunctorImpl
{
public:
  typedef R ResultType;
  typedef P1 Parm1;
  typedef P2 Parm2;

  virtual ~FunctorImpl() {}
  virtual R operator()(P1&, P2&) = 0;
  virtual FunctorImpl* DoClone() const = 0;

  template <class U>
  static U* Clone(U* pObj)
  {
    if (!pObj)
      return nullptr;
    U* pClone = static_cast<U*>(pObj->DoClone());
    assert(typeid(*pClone) == typeid(*pObj));
    return pClone;
  }

protected:
  FunctorImpl() {}
  FunctorImpl(const FunctorImpl&) {}

private:
  FunctorImpl& operator=(const FunctorImpl&) = delete;
};

////////////////////////////////////////////////////////////////////////////////
// Impl functor that calls a user functor
////////////////////////////////////////////////////////////////////////////////
template <class ParentFunctor, typename Fun>
class FunctorHandler : public ParentFunctor::Impl
{
  typedef typename ParentFunctor::Impl Base;

public:
  typedef typename Base::ResultType ResultType;
  typedef typename Base::Parm1 Parm1;
  typedef typename Base::Parm2 Parm2;

  FunctorHandler(const Fun& fun)
    : f_(fun)
  {
  }
  ~FunctorHandler() override {}

  ResultType operator()(Parm1& p1, Parm2& p2) override { return f_(p1, p2); }

  FunctorHandler* DoClone() const override { return new FunctorHandler(*this); }

private:
  Fun f_;
  FunctorHandler(const FunctorHandler& b)
    : ParentFunctor::Impl(b)
    , f_(b.f_)
  {
  }
  FunctorHandler& operator=(const FunctorHandler& b) = delete;
};

////////////////////////////////////////////////////////////////////////////////
// Functor wrapper class
////////////////////////////////////////////////////////////////////////////////
template <typename R, typename Parm1, typename Parm2>
class Functor
{
public:
  typedef FunctorImpl<R, Parm1, Parm2> Impl;
  typedef R ResultType;

  Functor()
    : spImpl_()
  {
  }

  Functor(const Functor& rhs)
    : spImpl_(Impl::Clone(rhs.spImpl_.get()))
  {
  }

  template <typename Fun>
  Functor(const Fun& fun)
    : spImpl_(new FunctorHandler<Functor, Fun>(fun))
  {
  }

  Functor& operator=(const Functor& rhs)
  {
    Functor copy(rhs);
    spImpl_.swap(copy.spImpl_);
    return *this;
  }

  ResultType operator()(Parm1& p1, Parm2& p2) { return (*spImpl_)(p1, p2); }

private:
  std::unique_ptr<Impl> spImpl_;
};
}

namespace vtkDispatcherCommon
{

template <class To, class From>
struct DynamicCaster
{
  static To& Cast(From& obj) { return dynamic_cast<To&>(obj); }

  static To* Cast(From* obj) { return dynamic_cast<To*>(obj); }
};

template <class To, class From>
struct vtkCaster
{
  static To& Cast(From& obj) { return *(To::SafeDownCast(&obj)); }

  static To* Cast(From* obj) { return To::SafeDownCast(obj); }
};

class TypeInfo
{
public:
  // Constructors
  TypeInfo();                      // needed for containers
  TypeInfo(const std::type_info&); // non-explicit

  // Access for the wrapped std::type_info
  const std::type_info& Get() const;
  // Compatibility functions
  bool before(const TypeInfo& rhs) const;
  const char* name() const;

private:
  const std::type_info* pInfo_;
};

// Implementation

inline TypeInfo::TypeInfo()
{
  class Nil
  {
  };
  pInfo_ = &typeid(Nil);
  assert(pInfo_);
}

inline TypeInfo::TypeInfo(const std::type_info& ti)
  : pInfo_(&ti)
{
  assert(pInfo_);
}

inline bool TypeInfo::before(const TypeInfo& rhs) const
{
  assert(pInfo_);
  // type_info::before return type is int in some VC libraries
  return pInfo_->before(*rhs.pInfo_) != 0;
}

inline const std::type_info& TypeInfo::Get() const
{
  assert(pInfo_);
  return *pInfo_;
}

inline const char* TypeInfo::name() const
{
  assert(pInfo_);
  return pInfo_->name();
}

// Comparison operators

inline bool operator==(const TypeInfo& lhs, const TypeInfo& rhs)
// type_info::operator== return type is int in some VC libraries
{
  return (lhs.Get() == rhs.Get()) != 0;
}

inline bool operator<(const TypeInfo& lhs, const TypeInfo& rhs)
{
  return lhs.before(rhs);
}

inline bool operator!=(const TypeInfo& lhs, const TypeInfo& rhs)
{
  return !(lhs == rhs);
}

inline bool operator>(const TypeInfo& lhs, const TypeInfo& rhs)
{
  return rhs < lhs;
}

inline bool operator<=(const TypeInfo& lhs, const TypeInfo& rhs)
{
  return !(lhs > rhs);
}

inline bool operator>=(const TypeInfo& lhs, const TypeInfo& rhs)
{
  return !(lhs < rhs);
}

}

#endif // wrapping
#endif // legacy remove
#endif // vtkDispatcherPrivate_h
// VTK-HeaderTest-Exclude: vtkDispatcher_Private.h
