#ifndef __RWVREF_H__
#define __RWVREF_H__

/*
 * RWVirtualRef: Reference counted virtual array reference.
 *
 * $Id: vref.h,v 2.5 1993/09/10 02:56:53 keffer Exp $
 *
 ****************************************************************************
 *
 * Rogue Wave Software, Inc.
 * P.O. Box 2328
 * Corvallis, OR 97339
 *
 * Copyright (C) 1992. This software is subject to copyright 
 * protection under the laws of the United States and other countries.
 *
 ***************************************************************************
 *
 * $Log: vref.h,v $
 * Revision 2.5  1993/09/10  02:56:53  keffer
 * Switched RCS idents to avoid spurious diffs
 *
 * Revision 2.4  1993/04/12  12:35:17  jims
 * Now uses RWMutex class for locking
 *
 * Revision 2.3  1993/02/06  02:09:37  keffer
 * Made findLocation(), lock() and unlock() public.
 *
 * Revision 2.2  1993/01/29  20:26:17  myersn
 * add MT-safe reference-counting.
 *
 * Revision 2.0  1992/10/23  03:27:32  keffer
 * RCS Baseline version
 * 
 *    Rev 1.2   04 Aug 1992 19:04:50   KEFFER
 * Destructor is now virtual.
 * 
 *    Rev 1.1   04 Jun 1992 14:49:22   KEFFER
 * Ported to Glock under Unix.
 * 
 *    Rev 1.0   11 Mar 1992 14:10:00   KEFFER
 * Initial revision.
 */

#ifndef __RWREF_H__
#  include "rw/ref.h"
#endif
#include "rw/vpage.h"
STARTWRAP
#include <stdlib.h>
ENDWRAP
#ifdef RW_MULTI_THREAD
#include "rw/mutex.h"
#endif

typedef unsigned RWPageSlot;

class RWExport RWVirtualRef : public RWReference {

public:

  RWVirtualRef(long length, size_t elementSize, RWVirtualPageHeap* h);
  RWVirtualRef(const RWVirtualRef&);	// Deep copy
  virtual ~RWVirtualRef();

  long			capacity() const	{return nSlots_*nPerPage_;}
  RWVirtualPageHeap*	heap() const		{return myHeap_;}
  long			length() const		{return length_;}
  void			slide(long start, long delta);
  void			setSlice(long start1, long extent1,
				RWVirtualRef& v, long start2, long extent2);
  void			reshape(long newLength);

public:

  // The following three functions are formally intended to be
  // protected, but to avoid many friend functions have been made part
  // of the public interface.

  void			findLocation(long, RWPageSlot&, unsigned&) const;
  void*			lock(RWPageSlot p)	{return myHeap_->lock(handles_[p]);}
  void			unlock(RWPageSlot p)	{myHeap_->unlock(handles_[p]);}

protected:

  // Neither augmentLeft nor augmentRight change the vector length.
  // They just add capacity to one side or the other.
  void			augmentLeft(long);	// Add capacity on left
  void			augmentRight(long);	// Add capacity on right
  void			init();
  unsigned		pages()			{return nSlots_;}
  unsigned		pageSize()		{return myHeap_->pageSize();}
  void			dirty(RWPageSlot p)	{myHeap_->dirty(handles_[p]);}

  // Supplied by specializing class:
  virtual void		conformalCopy(long start1, RWVirtualRef& v2, long start2, long N) = 0;

protected:

  // Protected data.
  // Note that the length of the vector handles_ is nSlots_.

  long			length_;	// Total number of elements
  long			baseIndex_;	// Start of actual data
  unsigned		nPerPage_;	// Number of elements per page
  RWVirtualPageHeap*	myHeap_;	// The heap I'm getting my pages from
  RWHandle*		handles_;	// Array of handles
  RWPageSlot		nSlots_;	// Length of handles_.

#ifdef RW_MULTI_THREAD
public:
  void addReference() { RWReference::addReference(mutexLock_); }
  unsigned removeReference()
    { return RWReference::removeReference(mutexLock_); }
private:
  RWMutex mutexLock_;
#endif

};

#endif	/* __RWVREF_H__ */
