File:  [Research Unix] / researchv10dc / cmd / icon / src / iconx / fstruct.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:34 2018 UTC (8 years, 3 months ago) by root
Branches: belllabs, MAIN
CVS tags: researchv10, HEAD
researchv10 Dan Cross

/*
 * File: fstruct.c
 *  Contents: delete, get, insert, member, pop, pull, push, put, sort
 */

#include "../h/rt.h"

/*
 * delete(S,x) - delete element x from set S if it is there
 *  (always succeeds and returns S).
 */

FncDcl(delete,2)
   {
   register struct descrip *pd;
   int res ;
   extern struct descrip *memb();

   Arg0 = Arg1;

   if (Arg1.dword != D_Set)
       runerr(119,&Arg1);

      /*
      * The technique and philosophy here are the same
      *  as used in insert - see comment there.
      */
   pd = memb((struct b_set *)BlkLoc(Arg1),&Arg2,hash(&Arg2),&res);
   if (res == 1) {
      /*
      * The element is there so delete it.
      */
      *pd = BlkLoc(*pd)->selem.clink;
      (BlkLoc(Arg1)->set.size)--;
      }
   Return;
   }


/*
 * get(x) - get an element from end of list x.
 *  Identical to pop(x).
 */

FncDcl(get,1)
   {
   register word i;
   register struct b_list *hp;
   register struct b_lelem *bp;
   extern struct b_lelem *alclstb();

   /*
    * x must be a list.
    */
   if (Arg1.dword != D_List)
      runerr(108, &Arg1);

   /*
    * Fail if the list is empty.
    */
   hp = (struct b_list *) BlkLoc(Arg1);
   if (hp->size <= 0)
      Fail;

   /*
    * Point bp at the first list block.  If the first block has no
    *  elements in use, point bp at the next list block.
    */
   bp = (struct b_lelem *) BlkLoc(hp->listhead);
   if (bp->nused <= 0) {
      bp = (struct b_lelem *) BlkLoc(bp->listnext);
      BlkLoc(hp->listhead) = (union block *) bp;
      bp->listprev = nulldesc;
      }
   /*
    * Locate first element and assign it to Arg0 for return.
    */
   i = bp->first;
   Arg0 = bp->lslots[i];
   /*
    * Set bp->first to new first element, or 0 if the block is now
    *  empty.  Decrement the usage count for the block and the size
    *  of the list.
    */
   if (++i >= bp->nelem)
      i = 0;
   bp->first = i;
   bp->nused--;
   hp->size--;
   Return;
   }


/*
 * insert(S,x) - insert element x into set S if not already there
 *  (always succeeds and returns S).
 */

FncDcl(insert,2)
   {
   register struct descrip *pd;
   register word hn;
   int res;
   extern struct b_selem *alcselem();
   extern struct descrip *memb();

   Arg0 = Arg1;

   if (Arg1.dword != D_Set)
      runerr(119,&Arg1);

      /*
      * We may need at most one new element.
      */
   blkreq((word)sizeof(struct b_selem));
   hn = hash(&Arg2);
   /*
    * If Arg2 is a member of set Arg1 then res will have the
    *  value 1 and pd will have a pointer to the descriptor
    *  that points to that member.
    *  If Arg2 is not a member of the set then res will have
    *  the value 0 and pd will point to the descriptor
    *  which should point to the member - thus we know where
    *  to link in the new element without having to do any
    *  repetitive looking.
    */
   pd = memb((struct b_set *)BlkLoc(Arg1),&Arg2,hn,&res);
   if (res == 0)
      /*
      * The element is not in the set - insert it.
      */
      addmem((struct b_set *)BlkLoc(Arg1),alcselem(&Arg2,hn),pd);
   Return;
   }


/*
 * member(S,x) - returns x if x is a member of set S otherwise fails.
 */

FncDcl(member,2)
   {
   int res;
   extern struct descrip *memb();

   if (Arg1.dword != D_Set)
      runerr(119,&Arg1);	/* S is not a set  */

   /* If Arg2 is a member of set Arg1 then "res" will have the
    * value 1 otherwise it will have the value 0.
    */
   memb((struct b_set *)BlkLoc(Arg1),&Arg2,hash(&Arg2),&res);
   if (res == 1) {		/* It is a member. */
      Arg0 = Arg2;		/* Return the member if it is in Arg1. */
      Return;
      }
   Fail;
   }


/*
 * pop(x) - pop an element from beginning of list x.
 */

/* >pop */
FncDcl(pop,1)
   {
   register word i;
   register struct b_list *hp;
   register struct b_lelem *bp;
   extern struct b_lelem *alclstb();

   /*
    * Arg1 must be a list.
    */
   if (Arg1.dword != D_List)
      runerr(108, &Arg1);

   /*
    * Fail if the list is empty.
    */
   hp = (struct b_list *) BlkLoc(Arg1);
   if (hp->size <= 0)
      Fail;

   /*
    * Point bp to the first list block.  If the first block has no
    *  elements in use, point bp at the next list block.
    */
   bp = (struct b_lelem *) BlkLoc(hp->listhead);
   if (bp->nused <= 0) {
      bp = (struct b_lelem *) BlkLoc(bp->listnext);
      BlkLoc(hp->listhead) = (union block *) bp;
      bp->listprev = nulldesc;
      }
   /*
    * Locate first element and assign it to Arg0 for return.
    */
   i = bp->first;
   Arg0 = bp->lslots[i];

   /*
    * Set bp->first to new first element, or 0 if the block is now
    *  empty.  Decrement the usage count for the block and the size
    *  of the list.
    */
   if (++i >= bp->nelem)
      i = 0;
   bp->first = i;
   bp->nused--;
   hp->size--;
   Return;
   }
/* <pop */


/*
 * pull(x) - pull an element from end of list x.
 */

FncDcl(pull,1)
   {
   register word i;
   register struct b_list *hp;
   register struct b_lelem *bp;
   extern struct b_lelem *alclstb();

   /*
    * x must be a list.
    */
   if (Arg1.dword != D_List)
      runerr(108, &Arg1);

   /*
    * Point at list header block and fail if the list is empty.
    */
   hp = (struct b_list *) BlkLoc(Arg1);
   if (hp->size <= 0)
      Fail;
   /*
    * Point bp at the last list element block.  If the last block has no
    *  elements in use, point bp at the previous list element block.
    */
   bp = (struct b_lelem *) BlkLoc(hp->listtail);
   if (bp->nused <= 0) {
      bp = (struct b_lelem *) BlkLoc(bp->listprev);
      BlkLoc(hp->listtail) = (union block *) bp;
      bp->listnext = nulldesc;
      }
   /*
    * Set i to position of last element and assign the element to
    *  Arg0 for return.  Decrement the usage count for the block
    *  and the size of the list.
    */
   i = bp->first + bp->nused - 1;
   if (i >= bp->nelem)
      i -= bp->nelem;
   Arg0 = bp->lslots[i];
   bp->nused--;
   hp->size--;
   Return;
   }


/*
 * push(x,val) - push val onto beginning of list x.
 */
FncDcl(push,2)
   {
   register word i;
   register struct b_list *hp;
   register struct b_lelem *bp;
   extern struct b_lelem *alclstb();

   /*
    * x must be a list.
    */
   if (Arg1.dword != D_List)
      runerr(108, &Arg1);

   /*
    * A new list element block might be needed, so ensure space for it.
    */
   blkreq((word)sizeof(struct b_lelem)+MinListSlots*sizeof(struct descrip));

   /*
    * Point hp at the list header block and bp at the first
    * list element block.
    */
   hp = (struct b_list *) BlkLoc(Arg1);
   bp = (struct b_lelem *) BlkLoc(hp->listhead);
   /*
    * If the first list element block is full,
    * allocate a new list element block, make it the first list
    *  element block and make it the previous block of the
    *  former first list element block.
    */
   if (bp->nused >= bp->nelem) {
      bp = alclstb((word)MinListSlots, (word)0, (word)0);
      BlkLoc(hp->listhead)->lelem.listprev.dword = D_Lelem;
      BlkLoc(BlkLoc(hp->listhead)->lelem.listprev) = (union block *) bp;
      bp->listnext = hp->listhead;
      BlkLoc(hp->listhead) = (union block *) bp;
      }
   /*
    * Set i to position of new first element and assign val (Arg2) to
    *  that element.
    */
   i = bp->first - 1;
   if (i < 0)
      i = bp->nelem - 1;
   bp->lslots[i] = Arg2;
   /*
    * Adjust value of location of first element, block usage count,
    *  and current list size.
    */
   bp->first = i;
   bp->nused++;
   hp->size++;
   /*
    * Return the list.
    */
   Arg0 = Arg1;
   Return;
   }


/*
 * put(x,val) - put val onto end of list x.
 */

FncDcl(put,2)
   {
   register word i;
   register struct b_list *hp;
   register struct b_lelem *bp;
   extern struct b_lelem *alclstb();

   /*
    * Arg1 must be a list.
    */
   if (Arg1.dword != D_List)
      runerr(108, &Arg1);

   /*
    * A new list element block might be needed, so ensure space for it.
    */
   blkreq((word)sizeof(struct b_lelem)+MinListSlots*sizeof(struct descrip));

/* >put */
   /*
    * Point hp to the list header block and bp to the last
    *  list element block.
    */
   hp = (struct b_list *) BlkLoc(Arg1);
   bp = (struct b_lelem *) BlkLoc(hp->listtail);

   /*
    * If the last list element block is full, allocate a new
    *  list element block, make it the first list element block
    *  and it make it the next block of the former last list
    *  element block.
    */
   if (bp->nused >= bp->nelem) {
      bp = alclstb((word)MinListSlots, (word)0, (word)0);
      BlkLoc(hp->listtail)->lelem.listnext.dword = D_Lelem;
      BlkLoc(BlkLoc(hp->listtail)->lelem.listnext) = (union block *) bp;
      bp->listprev = hp->listtail;
      BlkLoc(hp->listtail) = (union block *) bp;
      }

   /*
    * Set i to position of new last element and assign Arg2 to
    *  that element.
    */
   i = bp->first + bp->nused;
   if (i >= bp->nelem)
      i -= bp->nelem;
   bp->lslots[i] = Arg2;

   /*
    * Adjust block usage count and current list size.
    */
   bp->nused++;
   hp->size++;

   /*
    * Return the list.
    */
   Arg0 = Arg1;
   Return;
   }
/* <put */


struct dpair {
   struct descrip dr;
   struct descrip dv;
   };

/*
 * sort(l) - sort list l.
 * sort(S) - sort set S.
 * sort(t,i) - sort table.
 */

FncDcl(sort,2)
   {
   register struct descrip *d1;
   register word size;
   register int i;
   word nelem;
   struct b_list *lp, *tp;
   union block *bp, *ep;
   extern struct b_list *alclist();
   extern struct b_lelem *alclstb();
   extern anycmp(), trefcmp(), tvalcmp(), trcmp3(), tvcmp4();

   if (Arg1.dword == D_List) {
      /*
       * Sort the list by copying it into a new list and then using
       *  qsort to sort the descriptors.  (That was easy!)
       */
      size = BlkLoc(Arg1)->list.size;
      cplist(&Arg1, &Arg0, (word)1, size + 1);
      qsort(BlkLoc(BlkLoc(Arg0)->list.listhead)->lelem.lslots, size,
            sizeof(struct descrip), anycmp);
      }
   else if (Arg1.dword == D_Set) {
      /*
       * Create a list the size of the set (or at least 
       *  MinListSlots), copy each element into the list, and
       *  then sort the list using qsort as in list sorting
       *  and return the sorted list.
       */
   nelem = size = BlkLoc(Arg1)->set.size;
   if(nelem < MinListSlots)
      nelem = MinListSlots;
   blkreq(sizeof(struct b_list) + sizeof(struct b_lelem) +
      nelem * sizeof(struct descrip));

   bp = BlkLoc(Arg1);
   lp = alclist(size);
   lp->listhead.dword = lp->listtail.dword = D_Lelem;
      BlkLoc(lp->listtail) = (union block *) alclstb(nelem, (word)0, size);
   BlkLoc(lp->listhead) = BlkLoc(lp->listtail);
   if (size > 0) {  /* only need to sort non-empty sets */
      d1 = BlkLoc(lp->listhead)->lelem.lslots;
      for(i = 0; i < SSlots; i++) {
      ep = BlkLoc(bp->set.sbucks[i]);
      while (ep != NULL) {
         *d1 = ep->selem.setmem;
         d1++;
         ep = BlkLoc(ep->selem.clink);
         }
      }
      qsort(BlkLoc(lp->listhead)->lelem.lslots,size,
         sizeof(struct descrip),anycmp);
   }
   Arg0.dword = D_List;
   BlkLoc(Arg0) = (union block *) lp;
   }

   else if (Arg1.dword == D_Table) {
      /*
       * Default i (the type of sort) to 1.
       */
      defshort(&Arg2, 1);
      switch (IntVal(Arg2)) {

      /*
       * Cases 1 and 2 are as in standard Version 5.
       */
         case 1:
         case 2:
                {
      /*
       * The list resulting from the sort will have as many elements as
       *  the table has, so get that value and also make a valid list
       *  block size out of it.
       */
      nelem = size = BlkLoc(Arg1)->table.size;
      if (nelem < MinListSlots)
         nelem = MinListSlots;
      /*
       * Ensure space for: the list header block and a list element
       *  block for the list which is to be returned,
       *  a list header block and a list element block for each of the two
       *  element lists the sorted list is to contain.  Note that the
       *  calculation might be better expressed as:
       *    list_header_size + list_block_size + nelem * descriptor_size +
       *     nelem * (list_header_size + list_block_size + 2*descriptor_size)
       */
      blkreq(sizeof(struct b_list) + sizeof(struct b_lelem) +
         nelem * (sizeof(struct b_list) + sizeof(struct b_lelem) +
            3 * sizeof(struct descrip)));
      /*
       * Point bp at the table header block of the table to be sorted
       *  and point lp at a newly allocated list
       *  that will hold the the result of sorting the table.
       */
      bp = BlkLoc(Arg1);
      lp = alclist(size);
      lp->listhead.dword = lp->listtail.dword = D_Lelem;
      BlkLoc(lp->listtail) = (union block *) alclstb(nelem, (word)0, size);
      BlkLoc(lp->listhead) = BlkLoc(lp->listtail);
      /*
       * If the table is empty, there is no need to sort anything.
       */
      if (size <= 0)
         break;
         /*
          * Point d1 at the start of the list elements in the new list
          *  element block in preparation for use as an index into the list.
          */
         d1 = BlkLoc(lp->listhead)->lelem.lslots;
         /*
          * Traverse the element chain for each table bucket.  For each
          *  element, allocate a two-element list and put the table
          *  entry value in the first element and the assigned value in
          *  the second element.  The two-element list is assigned to
          *  the descriptor that d1 points at.  When this is done, the
          *  list of two-element lists is complete, but unsorted.
          */
         for (i = 0; i < TSlots; i++) {
            ep = BlkLoc(bp->table.buckets[i]);
            while (ep != NULL) {
               d1->dword = D_List;
               tp = alclist((word)2);
               BlkLoc(*d1) = (union block *) tp;
               tp->listhead.dword = tp->listtail.dword = D_Lelem;
               BlkLoc(tp->listtail) = (union block *) alclstb((word)2, (word)0,
                  (word)2);
               BlkLoc(tp->listhead) = BlkLoc(tp->listtail);
               BlkLoc(tp->listhead)->lelem.lslots[0] = ep->telem.tref;
               BlkLoc(tp->listhead)->lelem.lslots[1] = ep->telem.tval;
               d1++;
               ep = BlkLoc(ep->telem.clink);
               }
            }
         /*
          * Sort the resulting two-element list using the sorting function
          *  determined by i.
          */
         if (IntVal(Arg2) == 1)
            qsort(BlkLoc(lp->listhead)->lelem.lslots, size,
                  sizeof(struct descrip), trefcmp);
         else
            qsort(BlkLoc(lp->listhead)->lelem.lslots, size,
                  sizeof(struct descrip), tvalcmp);
         break;		/* from cases 1 and 2 */
         }
      /*
       * Cases 3 and 4 were introduced in Version 5.10.
       */
         case 3 :
         case 4 :
                 {
      /*
       * The list resulting from the sort will have twice as many elements as
       *  the table has, so get that value and also make a valid list
       *  block size out of it.
       */
      nelem = size = BlkLoc(Arg1)->table.size * 2;
      if (nelem < MinListSlots)
         nelem = MinListSlots;
      /*
       * Ensure space for: the list header block and a list element
       *  block for the list which is to be returned, and two descriptors for
       *  each table element.
       */
      blkreq(sizeof(struct b_list) + Vsizeof(struct b_lelem) +
            (nelem * sizeof(struct descrip)));
      /*
       * Point bp at the table header block of the table to be sorted
       *  and point lp at a newly allocated list
       *  that will hold the the result of sorting the table.
       */
      bp = BlkLoc(Arg1);
      lp = alclist(size);
      lp->listhead.dword = lp->listtail.dword = D_Lelem;
      BlkLoc(lp->listtail) = (union block *) alclstb(nelem, (word)0, size);
      BlkLoc(lp->listhead) = BlkLoc(lp->listtail);
      /*
       * If the table is empty there's no need to sort anything.
       */
      if (size <= 0)
         break;

         /*
          * Point d1 at the start of the list elements in the new list
          *  element block in preparation for use as an index into the list.
          */
         d1 = BlkLoc(lp->listhead)->lelem.lslots;
         /*
          * Traverse the element chain for each table bucket.  For each
          *  table element copy the the entry descriptor and the value
          *  descriptor into adjacent descriptors in the lslots array
          *  in the list element block.
          *  When this is done we now need to sort this list.
          */
         for (i = 0; i < TSlots; i++) {
            ep = BlkLoc(bp->table.buckets[i]);
            while (ep != NULL) {
               *d1 = ep->telem.tref;
               d1++;
               *d1 = ep->telem.tval;
               d1++;
               ep = BlkLoc(ep->telem.clink);
               }
            }
         /*
          * Sort the resulting two-element list using the sorting function
          *  determined by i.
          */
         if (IntVal(Arg2) == 3)
            qsort(BlkLoc(lp->listhead)->lelem.lslots, size / 2,
                  (2 * sizeof(struct descrip)), trcmp3);
         else
            qsort(BlkLoc(lp->listhead)->lelem.lslots, size / 2,
                  (2 * sizeof(struct descrip)), tvcmp4);
            break; /* from case 3 or 4 */
            }

         default : runerr(205,&Arg2);
         } /* end of switch statement */
      /*
       * Make Arg0 point at the sorted list.
       */
      Arg0.dword = D_List;
      BlkLoc(Arg0) = (union block *) lp;
      }
   else /* Tried to sort something that wasn't a list or a table. */
      runerr(115, &Arg1);
   Return;
   }

/*
 * trefcmp(d1,d2) - compare two-element lists on first field.
 */

trefcmp(d1,d2)
struct descrip *d1, *d2;
   {
   extern anycmp();

#ifdef Debug
   if (d1->dword != D_List || d2->dword != D_List)
      syserr("trefcmp: internal consistency check fails.");
#endif Debug
   return (anycmp(&(BlkLoc(BlkLoc(*d1)->list.listhead)->lelem.lslots[0]),
                  &(BlkLoc(BlkLoc(*d2)->list.listhead)->lelem.lslots[0])));
   }

/*
 * tvalcmp(d1,d2) - compare two-element lists on second field.
 */

tvalcmp(d1,d2)
struct descrip *d1, *d2;
   {
   extern anycmp();

#ifdef Debug
   if (d1->dword != D_List || d2->dword != D_List)
      syserr("tvalcmp: internal consistency check fails.");
#endif Debug
   return (anycmp(&(BlkLoc(BlkLoc(*d1)->list.listhead)->lelem.lslots[1]),
                  &(BlkLoc(BlkLoc(*d2)->list.listhead)->lelem.lslots[1])));
   }

/*
 * The following two routines are used to compare descriptor pairs in the
 *  experimental table sort.
 *
 * trcmp3(dp1,dp2)
 */

trcmp3(dp1,dp2)
struct dpair *dp1,*dp2;
{
   extern anycmp();

   return (anycmp(&((*dp1).dr),&((*dp2).dr)));
}
/*
 * tvcmp4(dp1,dp2)
 */

tvcmp4(dp1,dp2)
struct dpair *dp1,*dp2;

   {
   extern anycmp();

   return (anycmp(&((*dp1).dv),&((*dp2).dv)));
   }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.