/*
 *
 * Copyright (c) 2003
 * François Dumont
 *
 * This material is provided "as is", with absolutely no warranty expressed
 * or implied. Any use is at your own risk.
 *
 * Permission to use or copy this software for any purpose is hereby granted 
 * without fee, provided the above notices are retained on all copies.
 * Permission to modify the code and to distribute modified code is granted,
 * provided the above notices are retained, and a notice that the code was
 * modified is included with the above copyright notice.
 *
 */

#ifndef _STLP_MOVE_CONSTRUCT_FWK_H
#define _STLP_MOVE_CONSTRUCT_FWK_H

#ifndef _STLP_TYPE_TRAITS_H
# include <stl/type_traits.h>
#endif

_STLP_BEGIN_NAMESPACE

/*************************************************************
 * Move constructor framework
 *************************************************************/

/*************************************************************
 *Partial move:
 *The source HAS to be a valid instance after the move!
 *************************************************************/
template <class _Tp>
class __move_source {
  _Tp &_M_data;
public:
  explicit __move_source (_Tp &_src) : _M_data(_src)
  {};

  _Tp& get() const
  {return _M_data;}
};

//Class used to signal move constructor support, implementation and type.
template <class _Tp>
struct __move_traits {
  /*
   * implemented tells if a the special move constructor has to be called or the classic
   * copy constructor is just fine. Most of the time the copy constructor is fine only
   * if the following info is true.
   */
#if defined(_STLP_USE_PARTIAL_SPEC_WORKAROUND) && !defined(_STLP_CLASS_PARTIAL_SPECIALIZATION)
  typedef typename _IsStlportClass<_Tp>::_Ret implemented;
#else
  typedef __false_type implemented;
#endif /* _STLP_USE_PARTIAL_SPEC_WORKAROUND */
  /*
   * complete tells if the move is complete or partial, that is to say, does the source
   * needs to be destroyed once it has been moved.
   */
  typedef typename __type_traits<_Tp>::has_trivial_destructor complete;
};

/*
 * This struct should never be used if the user has not explicitely stipulated
 * that its class support the full move concept. To check that the return type
 * in such a case will be __invalid_source<_Tp> to generate a compile error
 * revealing the configuration problem.
 */
template <class _Tp>
struct _MoveSourceTraits {
  typedef typename __move_traits<_Tp>::implemented _MvImpRet;
  enum {_MvImp = __type2bool<_MvImpRet>::_Ret};
  typedef typename __select<_MvImp,
                            __move_source<_Tp>,
                            _Tp const&>::_Ret _Type;
};

//The helper function
template <class _Tp>
inline _STLP_TYPENAME_ON_RETURN_TYPE _MoveSourceTraits<_Tp>::_Type
_AsMoveSource (_Tp &src) {
  typedef typename _MoveSourceTraits<_Tp>::_Type _SrcType;
  return _SrcType(src);
}

struct __move_traits_POD {
  typedef __false_type implemented;
  typedef __true_type complete;
};

//Helper structs used for many class.
template <class _Tp>
struct __move_traits_aux {
  typedef typename __move_traits<_Tp>::implemented implemented;
  typedef typename __move_traits<_Tp>::complete complete;
};

template <class _Tp1, class _Tp2>
struct __move_traits_aux2 {
  typedef __move_traits<_Tp1> _MoveTraits1;
  typedef __move_traits<_Tp2> _MoveTraits2;

  typedef typename _Lor2<typename _MoveTraits1::implemented,
                         typename _MoveTraits2::implemented>::_Ret implemented;
  typedef typename _Land2<typename _MoveTraits1::complete,
                          typename _MoveTraits2::complete>::_Ret complete;
};

/*
 * Most of the time a class implement a move constructor but its use depends
 * on a third party, this is what the following struct is for.
 */
template <class _Tp>
struct __move_traits_help {
  typedef __true_type implemented;
  typedef typename __move_traits<_Tp>::complete complete;
};

template <class _Tp1, class _Tp2>
struct __move_traits_help2 {
  typedef __move_traits<_Tp1> _MoveTraits1;
  typedef __move_traits<_Tp2> _MoveTraits2;

  typedef __true_type implemented;
  typedef typename _Land2<typename _MoveTraits1::complete,
                          typename _MoveTraits2::complete>::_Ret complete;
};

_STLP_END_NAMESPACE

#endif /* _STLP_MOVE_CONSTRUCT_FWK_H */
