// $Header: /usr/u/moudgill/project/Socket/RCS/select.C,v 1.4 1992/10/02 18:34:56 moudgill Exp moudgill $
// 19th December, 1991. Mayan Moudgill.

static const char rcsid[] = "$Id: select.C,v 1.4 1992/10/02 18:34:56 moudgill Exp moudgill $";

#include "selset.h"

void                    selset::setsize()
{
   size = 0;
   for( int i = 0; i < totalsize; i ++ ) {
      if(FD_ISSET(i, &set) ) {
	 size++;
      }
   }
}

void                    selset::setmax(int m)
{
    if( size == 0) {
       max = -1;
       return;
    }
    for( int i = howmany(m, wordsize); set.fds_bits[i]== 0; i-- ) {
    }
    max = i * wordsize;
    for( fd_mask val = set.fds_bits[i]; (val & ~1) != 0;
	  val = (val >> 1) & selset::msbmask, max++) {
    }
}

                        selset::selset()
{
   size = 0;
   max  = -1;
   FD_ZERO(&set);
}
                        selset::selset(selset * s)
{
   if( s != 0) {
      size = s->size;
      max  = s->max;
      for( int i = 0; i <= howmany(s->max, wordsize); i++ ) {
          set.fds_bits[i] = s->set.fds_bits[i];
      }
   }
   else {
      size = 0;
      max  = -1;
      FD_ZERO(&set);
   }
}

ostream&                operator<<(ostream& o, selset& s)
{
   if( s.size == 0 ) {
      return o << "{}";
   }
   o << "#" << s.size << " " << s.max << " ";
   o << "{ ";
   for(int i = 0; i <= howmany(s.max, selset::wordsize); i++) {
      int n = selset::wordsize * i;
      for( fd_mask val = s.set.fds_bits[i]; val != 0 && n < FD_SETSIZE;
            val = (val >> 1) & selset::msbmask, n++) {
         if( val & 1 ) {
            o << n << " ";
         }
      }
   }
   return o << "}";
}

int                     seliter::operator()( selset& s)
{
   sel = s;
   if( sel.size == 0 ) {
      num = sel.max + 1;
      return -1;
   }
   for( num = 0, ix = 0; sel.set.fds_bits[ix] == 0;
         ix++, num += selset::wordsize ) {
   }
   for( val = sel.set.fds_bits[ix]; (val&1) == 0 && num < FD_SETSIZE ;
         val = (val >> 1) & selset::msbmask, num++) {
   }
   return num;
}


int                     seliter::operator++()
{
   if( num >= sel.max) {
      num++;
      return -1;
   }
   val = (val >> 1) & selset::msbmask;
   num++;
   if( val == 0) {
      for( ix++ ; sel.set.fds_bits[ix] == 0; ix++ ) {
      }
      val = sel.set.fds_bits[ix];
      num = ix*selset::wordsize;
   }
   for( ; (val&1) == 0; val = (val >> 1) & selset::msbmask, num++) {
   }
   return num;
}

inline int               selmax3(int i1, int i2, int i3)
{
int t = i1>i2 ? i1 : i2;

    return i3 > t ? i3 : t;
}

int                      selpoll(selset& rd, selset& wr, selset& ex)
{
timeval  t;
int      ret;
int      size= selmax3(rd.max, wr.max, ex.max) + 1;
 
   t.tv_sec  = 0;
   t.tv_usec = 0;
   ret = select(
	 size,
	 rd.size==0?(fd_set *)0:&rd.set,
	 wr.size==0?(fd_set *)0:&wr.set,
	 ex.size==0?(fd_set *)0:&ex.set,
	 &t
	 );

   if( rd.size != 0) {
      rd.setsize();
      rd.setmax(rd.max);
   }

   if( wr.size != 0) {
      wr.setsize();
      wr.setmax(wr.max);
   }

   if( ex.size != 0) {
      ex.setsize();
      ex.setmax(ex.max);
   }

   return ret;
}

int                      seltime(double tm, selset &rd, selset& wr, selset& ex)
{
timeval  t;
int      ret;
int      size= selmax3(rd.max, wr.max, ex.max) + 1;

   t.tv_sec  = tm;
// bug discoverd by Clifford Beshers (beshers@tune.cs.columbia.edu)
   t.tv_usec = 1000000*(tm - t.tv_sec);
   ret = select(
	 size,
	 rd.size==0?(fd_set *)0:&rd.set,
	 wr.size==0?(fd_set *)0:&wr.set,
	 ex.size==0?(fd_set *)0:&ex.set,
	 &t
	 );

   if( rd.size != 0) {
      rd.setsize();
      rd.setmax(rd.max);
   }

   if( wr.size != 0) {
      wr.setsize();
      wr.setmax(wr.max);
   }

   if( ex.size != 0) {
      ex.setsize();
      ex.setmax(ex.max);
   }

   return ret;
}

int                      selwait(selset &rd, selset& wr, selset& ex)
{
int      size= selmax3(rd.max, wr.max, ex.max) + 1;
int      ret;
 
   ret = select(
	 size,
	 rd.size==0?(fd_set *)0:&rd.set,
	 wr.size==0?(fd_set *)0:&wr.set,
	 ex.size==0?(fd_set *)0:&ex.set,
	 0
	 );

   if( rd.size != 0) {
      rd.setsize();
      rd.setmax(rd.max);
   }

   if( wr.size != 0) {
      wr.setsize();
      wr.setmax(wr.max);
   }

   if( ex.size != 0) {
      ex.setsize();
      ex.setmax(ex.max);
   }

   return ret;
}
