//
// Copyright (C) 2000, 2001 GRACE development team  <grace@msu.ru>
//
// GRACE is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// GRACE is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with GRACE; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// $Source: /usr/local/cvs/grace/src/gr_tptr.hh,v $
// $Revision: 1.21 $
// $Date: 2001/05/28 12:19:49 $

#ifndef __gr_tptr_hh__
#define __gr_tptr_hh__

#include "gr_tval.hh"
#include "gr_message.hh"
#include "gr_memo.hh"

#include <asm/atomic.h>

namespace grace
{

extern atomic_t* tptr_unique_id_count ;

//------------------------------------------------------------------------------
//! Pointer to t-value
//------------------------------------------------------------------------------

template <typename val_t>
class T_Ptr
{

private:
  //
  //! ID of computational space where t-value is located.
  //! \todo Try to reduce t-ptr size.
  mutable CompSpaceID id ;
  //
  //! A union containing pointer to t-val or pointer to memo table entry
  //  containing a t-val.
  union {
    mutable T_Val<val_t>* tval ;
    mutable MemoTableEntry<T_Ptr<val_t>, T_Val<val_t> >* tptr_and_tval ;
  } ;
  //
  //! Unique t-ptr id, needed to provide correct memoization.
  // FIXME: Try to avoid this additional field (may be after reference
  // counting memo table entries this will not be need)
  volatile unsigned unique_id ;

public:
  //
  //! Default constructor from real pointer to t-val.
  inline T_Ptr (T_Val<val_t> const* const _tval = null) ;
  //
  //! Copy constructor. Always creates globalized t-ptr.
  inline T_Ptr (T_Ptr const& _tptr) ;
  //
  //! Destructor.
  inline ~T_Ptr () ;
  //
  //! Assignment operator from real pointer to t-val.
  inline T_Ptr<val_t>& operator = (T_Val<val_t> const* const _tval) ;
  //
  //! Assignment operator from another t-ptr.
  inline T_Ptr<val_t>& operator = (T_Ptr const& _tptr) ;
  //
  //! Get reference to attached t-val (for non-const t-ptrs).
  // FIXME: This function is deprecated. Use operator * instead.
  inline T_Val<val_t>& get_tval () ;
  //
  //! Get reference to attached t-val (for const t-ptrs).
  // FIXME: This function is deprecated. Use operator * instead.
  inline T_Val<val_t> const& get_tval () const ;
  //
  //! Get reference to attached t-val (for non-const t-ptrs).
  inline T_Val<val_t>& operator * () ;
  //
  //! Get reference to attached t-val (for const t-ptrs).
  inline T_Val<val_t> const& operator * () const ;
  //
  //! Casting to real pointer.
  inline operator val_t* () ;
  //
  //! Casting to real pointer (for const t-ptrs).
  inline operator val_t const* () const ;
  //
  //! Waiting for non-const tptr
  inline void wait () ;
  //
  //! Overloaded operator -> to get fields of object referenced by a t-ptr.
  inline val_t* operator -> () ;
  //
  //! Overloaded operator -> (for const t-ptrs).
  inline val_t const* operator -> () const ;
  //
  //! Check whether t-ptrs are equal.
  inline bool operator == (T_Ptr<val_t> const& _tptr) const ;
  //
  //! Check whether t-ptrs are not equal.
  inline bool operator != (T_Ptr<val_t> const& _tptr) const ;
  //
  //! Check whether t-ptr is equal to real ptr.
  inline bool operator == (T_Val<val_t> const* _ptr) const ;
  //
  //! Check whether t-ptrs is not equal to real ptr.
  inline bool operator != (T_Val<val_t> const* _ptr) const ;
  //
  //! Get a real object value (for non-const t-ptrs)
  inline val_t& get_value () ;
  //
  //! Get a real object value (for const t-ptrs)
  inline val_t const& get_value () const ;

private:
  //
  //! Check whether t-ptr is localized (i.e. points to local t-val).
  inline bool is_localized() const ;
  //
  //! Bind a t-val to t-ptr, forcing upload of t-val.
  inline static void bind_tval_with_upload (
    T_Ptr<val_t>& _ptr, T_Val<val_t>& _tval
  ) ;
  //
  //! Bind a t-val to t-ptr, forcing download of t-val.
  inline static void bind_tval_with_download (
    T_Ptr<val_t>& ptr, T_Val<val_t>& tval
  ) ;
  //
  //! Localize t-ptr.
  inline void localize (bool do_download) const ;
  //
  //! Globalize t-ptr.
  inline void globalize () const ;
  //
  //! Inner class containing a value for upload.
  struct UploadMessage : Message {

  private:
    //
    //! A value itself.
    val_t val ;
    //
    //! Pointer to t-val on a remote node.
    T_Val<val_t>* rtval ;

  public:
    //
    //! Constructor.
    UploadMessage (val_t const& _val, T_Val<val_t>* _rtval) ;
    //
    //! Serialization. Currently does nothing.
    Message* serialize () ;
    //
    //! Deserialization. Currently does nothing.
    Message* deserialize () ;
    //
    //! Assign incoming value.
    void handle() ;

  };

  //
  //! Arguments structure for upload_tval()
  struct UploadArgs {
    T_Val<val_t>* tval;
    T_Ptr<val_t> tptr;
  };

  //
  //! Results structure for upload_tval()
  struct UploadRess {
  };

  //
  //! Upload function
  inline static void tfun_upload_tval (
    UploadArgs const* _args, UploadRess * _ress
  ) ;

};

}

#endif // __gr_tptr_hh__