#ifndef	__RWBITVEC_H__
#define	__RWBITVEC_H__

/*
 * Ar`bit'rarily long bit vector.
 *
 * $Id: bitvec.h,v 2.11 1993/09/10 02:56:53 keffer Exp $
 *
 ****************************************************************************
 *
 * Rogue Wave Software, Inc.
 * P.O. Box 2328
 * Corvallis, OR 97339
 * Voice: (503) 754-3010	FAX: (503) 757-6650
 *
 * Copyright (C) 1989 - 1993.
 * This software is subject to copyright protection under the laws of
 * the United States and other countries.
 *
 ***************************************************************************
 *
 * $Log: bitvec.h,v $
 * Revision 2.11  1993/09/10  02:56:53  keffer
 * Switched RCS idents to avoid spurious diffs
 *
 * Revision 2.10  1993/07/31  01:43:04  keffer
 * Added member functions firstFalse() and firstTrue().
 *
 * Revision 2.9  1993/05/18  00:44:51  keffer
 * Added rwexport qualifier to overloaded shift operators.
 *
 * Revision 2.8  1993/04/09  19:35:45  keffer
 * Indexing is now done using size_t
 *
 * Revision 2.7  1993/04/09  02:50:00  keffer
 * Added support for operator<< and >> for virtual streams and RWFile.
 *
 * Revision 2.6  1993/03/24  01:29:51  keffer
 * Indexing operations now used unsigned
 *
 * Revision 2.5  1993/01/28  01:53:04  myersn
 * derive from RWMemoryPool via the macro RWMemoryPool_OPTION for MT-safety
 *
 * Revision 2.4  1993/01/27  19:18:15  keffer
 * Now use RWor, RWand, and RWxor always.
 *
 * Revision 2.3  1993/01/25  18:12:13  keffer
 * RW_NO_CONST_OVERLOADS->RW_NO_CONST_OVERLOAD
 *
 * Revision 2.1  1992/11/19  05:45:01  keffer
 * Introduced new <rw/compiler.h> macro directives
 *
 * Revision 2.0  1992/10/23  03:27:32  keffer
 * RCS Baseline version
 *
 * 
 *    Rev 1.6   03 May 1992 09:58:18   KEFFER
 * Added RWExport qualifier to RWBitVec.
 * 
 *    Rev 1.5   17 Mar 1992 19:21:08   KEFFER
 * Changed BOUNDS_CHECK to RWBOUNDS_CHECK
 * 
 *    Rev 1.4   04 Mar 1992 09:03:02   KEFFER
 * nil changed to rwnil
 * 
 *    Rev 1.3   18 Feb 1992 19:21:42   KEFFER
 * Added m.f. nfull()
 * 
 *    Rev 1.2   28 Oct 1991 09:08:08   keffer
 * Changed inclusions to <rw/xxx.h>
 * 
 *    Rev 1.1   10 Oct 1991 09:35:10   keffer
 * Exported global operators and ::sum().
 * 
 *    Rev 1.0   28 Jul 1991 08:12:16   keffer
 * Tools.h++ V4.0.5 PVCS baseline version
 *
 */

/*
 * Defining the preprocessor directive RWBOUNDS_CHECK will
 * cause bounds checking on the subscripting operator.
 */

#include "rw/bitref.h"

class RWExport RWBitVec   RWMemoryPool_OPTION
{

public:

  RWBitVec() : vec_(rwnil), npts_(0) {;}
  RWBitVec(size_t N);
  RWBitVec(size_t N, RWBoolean initVal);
  RWBitVec(const RWByte*, size_t N);
  RWBitVec(const RWBitVec&);
  ~RWBitVec();

  // Assignment operators
  RWBitVec&		operator=(const RWBitVec&);
  RWBitVec&		operator=(RWBoolean);
  RWBitVec&		operator&=(const RWBitVec& V)
	{RWand(vec_, V.vec_, nbytes()); return *this;}
  RWBitVec&		operator^=(const RWBitVec& V)
	{RWxor(vec_, V.vec_, nbytes()); return *this;}
  RWBitVec&		operator|=(const RWBitVec& V)
	{RWor(vec_, V.vec_, nbytes()); return *this;}

  // Indexing operators
  RWBitRef		operator[](size_t i);	// Can be used as lvalue
  RWBitRef		operator()(size_t i);	//       ditto
#ifndef RW_NO_CONST_OVERLOAD
  RWBoolean		operator[](size_t i) const; // Can't be used as lvalue
  RWBoolean		operator()(size_t i) const; //       ditto
#endif

  // Other operators ---
  RWBoolean		operator==(const RWBitVec& u) const {return  isEqual(u);}
  RWBoolean		operator!=(const RWBitVec& u) const {return !isEqual(u);}
  RWBoolean		operator==(RWBoolean b) const;
  RWBoolean		operator!=(RWBoolean b) const {return !operator==(b);}

  friend RWBitVec rwexport	operator!(const RWBitVec&);
  friend RWBitVec rwexport 	operator&(const RWBitVec&,const RWBitVec&);
  friend RWBitVec rwexport 	operator^(const RWBitVec&,const RWBitVec&);
  friend RWBitVec rwexport 	operator|(const RWBitVec&,const RWBitVec&);
  friend ostream& rwexport	operator<<(ostream&, const RWBitVec&);
  friend istream& rwexport	operator>>(istream&, RWBitVec&);

  // Member functions
  void			clearBit(size_t i);		// Clear bit i
  const RWByte*		data() const	{ return vec_; }
  size_t		firstFalse() const;		// Find first OFF bit
  size_t		firstTrue() const;		// Find first ON  bit
  unsigned		hash() const;
  RWBoolean		isEqual(const RWBitVec&) const;
  size_t		length() const	{return npts_;}
  ostream&		printOn(ostream&) const;
  void			restoreFrom(RWvistream&);
  void			restoreFrom(RWFile&);
  void			resize(size_t);
  void			saveOn(RWvostream&) const;
  void			saveOn(RWFile&) const;
  istream&		scanFrom(istream&);
  void			setBit(size_t i);			// Set bit i
  RWBoolean		testBit(size_t i) const;		// Return value of bit i

  // Other friend functions:
  friend size_t rwexport	sum(const RWBitVec&);		// Total # of bits set

private:

  void			indexRangeErr(size_t) const;
  void			lengthErr(size_t, size_t) const;
  size_t		nbytes() const	{ return (npts_+7) >> 3; }
  size_t		nfull()  const  { return npts_ >> 3; }

  RWByte*		vec_;		// The bit data, packed within a byte vector
  size_t		npts_;		// Length of vector in bits

};

inline RWvistream& operator>>(RWvistream& str,       RWBitVec& vec)
  { vec.restoreFrom(str);  return str; }
inline RWFile&     operator>>(RWFile& file,          RWBitVec& vec)
  { vec.restoreFrom(file); return file; }
inline RWvostream& operator<<(RWvostream& str, const RWBitVec& vec)
  { vec.saveOn(str);       return str; }
inline RWFile&     operator<<(RWFile& file,    const RWBitVec& vec)
  { vec.saveOn(file);      return file; }

inline size_t RWBitVec::firstFalse() const
  { return rwFirstFalse(vec_, npts_); }
inline size_t RWBitVec::firstTrue() const
  { return rwFirstTrue(vec_, npts_); }

// This macro isolates bit 'i'
#define RWBIT(i) (*(((i)>>3) + (vec_)) & (1<<(7&(i))))

inline RWBitRef
RWBitVec::operator[](size_t i)
{
  if (i >= npts_) indexRangeErr(i);
  return RWBitRef(vec_,i);
}
	
inline RWBitRef
RWBitVec::operator()(size_t i)
{
#ifdef RWBOUNDS_CHECK
  if (i >= npts_) indexRangeErr(i);
#endif
  return RWBitRef(vec_,i);
}

#ifndef RW_NO_CONST_OVERLOAD
	
inline RWBoolean
RWBitVec::operator[](size_t i) const
{
  if (i >= npts_) indexRangeErr(i);
  return RWBIT(i) != 0;
}
	
inline RWBoolean
RWBitVec::operator()(size_t i) const
{
#ifdef RWBOUNDS_CHECK
  if (i >= npts_) indexRangeErr(i);
#endif
  return RWBIT(i) != 0;
}

#endif	/* RW_NO_CONST_OVERLOAD */

inline void
RWBitVec::clearBit(size_t i)
{ (*(vec_ + (i>>3))) &= ~(1<<(7&i)); }

inline void
RWBitVec::setBit(size_t i)
{ (*(vec_ + (i>>3))) |= (1<<(7&i)); }

inline RWBoolean
RWBitVec::testBit(size_t i) const
{ return RWBIT(i) != 0; }

#endif /* __RWBITVEC_H__ */

