//-----------------------------------------------------------------------------
// Copyright (c) 1994,1995 Southeastern Universities Research Association,
//                         Continuous Electron Beam Accelerator Facility
//
// This software was developed under a United States Government license
// described in the NOTICE file included as part of this distribution.
//
//-----------------------------------------------------------------------------
//
// Description:
//      File Descriptor Mask Class (Based On ACE Handler_Set)
//
// Author:  Jie Chen
//
// Revision History:
//   cdevFdSet.h,v
// Revision 1.6  1997/03/26  18:34:58  akers
// Ongoing development
//
// Revision 1.5  1996/10/01  13:58:23  akers
// Changes to support AIX
//
// Revision 1.4  1996/09/19  18:50:06  akers
// Included time.h in order to match redefinition of fd_set to __fd_set.
//
// Revision 1.3  1995/12/15  15:08:06  chen
// Add VMS Fix
//
// Revision 1.2  1995/10/05  16:30:12  chen
// Fix for VMS
//
// Revision 1.1.1.1  1995/06/16  17:14:02  epics
// initial import of cdev
//
//
#ifndef _CDEV_FDSET_H
#define _CDEV_FDSET_H

#include <stdio.h>
#include <string.h>
#include <cdevSpec.h>

#ifdef _WIN32
#include <winsock2.h>
#include <time.h>
#else
#include <sys/time.h>

#ifdef __VMS
#ifdef _TGV_MULTINET
// Under TGV multinet and VMS, if you want sys/types.h you need to have
// types.h already pulled in because sys/types.h makes it look like types.h
// is loaded. Then when types.h does get loaded, it is ignored because it 
// looks like it is already loaded -- Mr. Danial Van Olst
#include <types.h>
#endif
#endif

#ifdef __VMS
#ifdef _TGV_MULTINET
// Under TGV Multinet and VMS, the file sys/param.h does not define
// NOFILE (max number of open files per process).
// FD_SETSIZE seems to be the correct value for NOFILE.
// See Multinet's sys/types.h file for more info on FD_SETSIZE.
// - Daniel Van Olst
#ifndef NOFILE
#define NOFILE FD_SETSIZE
#endif /* NOFILE not defined. */

#endif /* _TGV_MULTINET defined. */
#endif /* __VMS defined.   */

#include <sys/types.h>
#include <sys/param.h>

/* The header sys/select.h must be included on AIX machines    */
/* in order to define the FD_ZERO macro.                       */
#ifdef _AIX
	#include <sys/select.h>
#endif

/* This wrapper design is not very portable to DEC OSF/1	*/
/* I had to redefine NFDBITS to 32. On OSF/1 NFDBITS is a 	*/
/* macro that expands to (sizeof(fd_mask)*8) which is 4096 by	*/
/* default. This was an inappropriate value for defining the 	*/
/* MSB_MASK default value. Any ideas?	The workaround is a 	*/
/* pretty severe restriction for OSF/1.		DJT		*/
/*#if defined (__osf__)						*/
/*#define NFDBITS 32						*/
/*#endif							*/

#endif

class CDEV_CLASS_SPEC cdevFdSet 
{
  // = TITLE
  //     C++ wrapper for the BSD fd_set abstraction. 
  //
  // = DESCRIPTION
  //

  friend class cdevFdSet_Iterator;
 public:
  // = Initialization and termination. 

  cdevFdSet (void);
  cdevFdSet (const fd_set &mask);

  // = Methods for manipulating bitsets.
  void reset (void);
  int  is_set (int) const;
  void set_bit (int);
  void clr_bit (int);
  int  num_set (void) const;
  int  max_set (void) const;
  int  pr_mask ( FILE * fp = stdout );
  void sync (int max = FD_SETSIZE);
  operator fd_set *( void ) { return &mask_; }

private:
  int	 size_;
  int	 max_handle_;
  fd_set mask_;

  enum 
  {
#ifdef _WIN32
    MAX_SIZE  = FD_SETSIZE,
#else
    MAX_SIZE  = NOFILE,
    WORD_SIZE = NFDBITS,
    NUM_WORDS = howmany (NOFILE, NFDBITS),
#ifdef __DECCXX
    // DECC warns about integer overflow if 1 used because 1 is signed
    MSB_MASK	= ~(1U << (NFDBITS - 1))
#elif defined (CDEV_HAS_64BIT_LONGS)
    MSB_MASK	= ~(1UL << (NFDBITS - 1))
#else
    MSB_MASK	= ~(1 << (NFDBITS - 1))
#endif

#endif
  };

  int  count_bits (unsigned long n) const;
  void set_max (int max);

  static const char nbits_[256];
};

class cdevFdSet_Iterator
  // = TITLE
  //  Iterator for the cdevFdSet abstraction. 
  //
  // = DESCRIPTION
  //
{
public:
  cdevFdSet_Iterator (cdevFdSet &);
  int operator ()(void);
  void operator++ (void);

private:
  cdevFdSet  &fds_;
#ifdef _WIN32
  /* index into fd_array[FD_SETSIZE] */
  unsigned int index_;
#else
  /* index into fd_mask array */
  int	  index_;
#endif
  /* current FD value = bit number in the long mask */
  /* not used in the WIN32 platform                 */
  int	  num_; 

#ifndef _WIN32
  fd_mask val_;
#endif
};

#endif
