// vim:set ft=cpp: -*- Mode: C++ -*-
/**
 * \file
 * L4::Capability class.
 *
 * \author Alexander Warg <alexander.warg@os.inf.tu-dresden.de>
 *
 */
/*
 * (c) 2008-2009 Author(s)
 *     economic rights: Technische Universität Dresden (Germany)
 *
 * License: see LICENSE.spdx (in this directory or the directories above)
 */
#pragma once

#include <l4/sys/capability>

namespace L4 {

/**
 * Smart capability class.
 */
template< typename T, typename SMART >
class Smart_cap : public Cap_base, private SMART
{
public:

  SMART const &smart() const noexcept { return *this; }

  void _delete() noexcept
  {
    SMART::free(const_cast<Smart_cap<T,SMART>&>(*this));
  }

  Cap<T> release() const noexcept
  {
    l4_cap_idx_t r = cap();
    SMART::invalidate(const_cast<Smart_cap<T,SMART>&>(*this));

    return Cap<T>(r);
  }

  void reset() noexcept
  {
    _c = L4_INVALID_CAP;
  }

  Smart_cap() noexcept : Cap_base(Invalid) {}

  Smart_cap(Cap_base::Cap_type t) noexcept : Cap_base(t) {}

  /**
   * Internal constructor, use to generate a capability from a `this` pointer.
   *
   * \attention This constructor is only useful to generate a capability
   *            from the `this` pointer of an objected that is an L4::Kobject.
   *            Do `never` use this constructor for something else!
   * \param p  The `this` pointer of the Kobject or derived object
   */
  template< typename O >
  Smart_cap(Cap<O> const &p) noexcept : Cap_base(p.cap())
  { Cap<T>::template check_convertible_from<O>(); }

  template< typename O >
  Smart_cap(Cap<O> const &p, SMART const &smart) noexcept
  : Cap_base(p.cap()), SMART(smart)
  { Cap<T>::template check_convertible_from<O>(); }

  template< typename O >
  Smart_cap(Smart_cap<O, SMART> const &o) noexcept
  : Cap_base(SMART::copy(o)), SMART(o.smart())
  { Cap<T>::template check_convertible_from<O>(); }

  Smart_cap(Smart_cap const &o) noexcept
  : Cap_base(SMART::copy(o)), SMART(o.smart())
  { }

  template< typename O >
  Smart_cap(typename Cap<O>::Cap_type cap) noexcept : Cap_base(cap)
  { Cap<T>::template check_convertible_from<O>(); }

  void operator = (typename Cap<T>::Cap_type cap) noexcept
  {
    _delete();
    _c = cap;
  }

  template< typename O >
  void operator = (Smart_cap<O, SMART> const &o) noexcept
  {
    _delete();
    _c = this->SMART::copy(o).cap();
    this->SMART::operator = (o.smart());
    // return *this;
  }

  Smart_cap const &operator = (Smart_cap const &o) noexcept
  {
    if (&o == this)
      return *this;

    _delete();
    _c = this->SMART::copy(o).cap();
    this->SMART::operator = (o.smart());
    return *this;
  }

#if __cplusplus >= 201103L
  template< typename O >
  Smart_cap(Smart_cap<O, SMART> &&o) noexcept
  : Cap_base(o.release()), SMART(o.smart())
  { Cap<T>::template check_convertible_from<O>(); }

  Smart_cap(Smart_cap &&o) noexcept
  : Cap_base(o.release()), SMART(o.smart())
  { }

  template< typename O >
  void operator = (Smart_cap<O, SMART> &&o) noexcept
  {
    _delete();
    _c = o.release().cap();
    this->SMART::operator = (o.smart());
    // return *this;
  }

  Smart_cap const &operator = (Smart_cap &&o) noexcept
  {
    if (&o == this)
      return *this;

    _delete();
    _c = o.release().cap();
    this->SMART::operator = (o.smart());
    return *this;
  }
#endif

  /**
   * Member access of a `T`.
   */
  Cap<T> operator -> () const noexcept { return Cap<T>(_c); }

  Cap<T> get() const noexcept { return Cap<T>(_c); }

  ~Smart_cap() noexcept { _delete(); }
};

template< typename T >
class Weak_cap : public Cap_base
{
public:
  Weak_cap() noexcept : Cap_base(Invalid) {}

  template< typename O >
  Weak_cap(typename Cap<O>::Cap_type t) noexcept : Cap_base(t)
  { Cap<T>::template check_convertible_from<O>(); }

  template< typename O, typename S >
  Weak_cap(Smart_cap<O, S> const &c) noexcept : Cap_base(c.cap())
  { Cap<T>::template check_convertible_from<O>(); }

  Weak_cap(Weak_cap const &o) noexcept : Cap_base(o) {}

  template< typename O >
  Weak_cap(Weak_cap<O> const &o) noexcept : Cap_base(o)
  { Cap<T>::template check_convertible_from<O>(); }

};

namespace Cap_traits {
  template< typename T1, typename T2 >
  struct Type { enum { Equal = false }; };

  template< typename T1 >
  struct Type<T1,T1> { enum { Equal = true }; };
};

/**
 * `static_cast` for (smart) capabilities.
 *
 * \tparam T      Type to cast the capability to.
 * \tparam F      (implicit) Type of the passed capability.
 * \tparam SMART  (implicit) Class implementing the Smart_cap interface.
 * \param  c      Capability to be casted.
 *
 * \return A smart capability with new type `T`.
 */
template< typename T, typename F, typename SMART >
inline
Smart_cap<T, SMART> cap_cast(Smart_cap<F, SMART> const &c) noexcept
{
  Cap<T>::template check_castable_from<F>();
  return Smart_cap<T, SMART>(Cap<T>(SMART::copy(c).cap()));
}


/**
 * `reinterpret_cast` for (smart) capabilities.
 *
 * \tparam T      Type to cast the capability to.
 * \tparam F      (implicit) Type of the passed capability.
 * \tparam SMART  (implicit) Class implementing the Smart_cap interface.
 * \param  c      Capability to be casted.
 *
 * \return A smart capability with new type `T`.
 */
template< typename T, typename F, typename SMART >
inline
Smart_cap<T, SMART> cap_reinterpret_cast(Smart_cap<F, SMART> const &c) noexcept
{
  return Smart_cap<T, SMART>(Cap<T>(SMART::copy(c).cap()));
}


}
