/*___INFO__MARK_BEGIN__*/
/*************************************************************************
 *
 *  The Contents of this file are made available subject to the terms of
 *  the Sun Industry Standards Source License Version 1.2
 *
 *  Sun Microsystems Inc., March, 2001
 *
 *
 *  Sun Industry Standards Source License Version 1.2
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.2 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *   The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *   Copyright: 2001 by Sun Microsystems, Inc.
 *
 *   All Rights Reserved.
 *
 ************************************************************************/
/*___INFO__MARK_END__*/

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

#include "sge_bitfield.h"

/****** uti/bitfield/--Bitfield ****************************************
*  NAME
*     Bitfield -- A variable size bitfield implementation
*
*  SYNOPSIS
*     bitfield sge_bitfield_new(unsigned int size)
*
*  FUNCTION
*     This module provides variable size bitfields.
*     The size of a bitfield can be defined when the bitfield is created.
*     Individual bits can be set, read and cleared.
*     The contents of a bitfield can be printed to stdout or any
*     file handle.
*
*  EXAMPLE
*     See main program (module test) in libs/uti/sge_bitfield.c
*
*  NOTES
*     MT-NOTE: this module is MT safe
*
*  SEE ALSO
*     uti/bitfield/sge_bitfield_new()
*     uti/bitfield/sge_bitfield_free()
*     uti/bitfield/sge_bitfield_set()
*     uti/bitfield/sge_bitfield_get()
*     uti/bitfield/sge_bitfield_clear()
*     uti/bitfield/sge_bitfield_reset()
*     uti/bitfield/sge_bitfield_copy()
*     uti/bitfield/sge_bitfield_bitwise_copy()
*     uti/bitfield/sge_bitfield_print()
*******************************************************************************/

/****** uti/bitfield/-Bitfield_Typedefs ****************************************
*  NAME
*     Bitfield_Typedefs -- type definitions for the Bitfield module
*
*  SYNOPSIS
*     typedef struct {
*        unsigned int size;
*        union {
*           char fix[sizeof(char *)];
*           char *dyn;
*        } bf;
*     } bitfield;
*     
*     typedef _bitfield *bitfield;
*
*  FUNCTION
*     The _bitfield structure is the internal representation of a bitfield.
*     All operations on bitfields use the bitfield type.
*
*     For small bitfields, no memory is allocated, but the space available in
*     bf.fix is used (depending on the architecture, this suffices for 32 or 64
*     bit bitfields).
*     This saves a considerable amount of memory and above all processing time.
*******************************************************************************/

/****** uti/bitfield/sge_bitfield_new() ****************************************
*  NAME
*     sge_bitfield_new() -- create a new bitfield
*
*  SYNOPSIS
*     bitfield *
*     sge_bitfield_new(unsigned int size) 
*
*  FUNCTION
*     Allocates and initializes the necessary memory.
*     It is in the responsibility of the caller to free the bitfield
*     once it is no longer needed.
*
*  INPUTS
*     unsigned int size - size in bits
*
*  RESULT
*     bitfield - a new bitfield or NULL, if the creation of the bitfield 
*                failed
*
*  NOTES
*     MT-NOTE: sge_bitfield_new() is MT safe
*
*  SEE ALSO
*     uti/bitfield/sge_bitfield_free()
*******************************************************************************/
bitfield *
sge_bitfield_new(unsigned int size)
{
   bitfield *bf;

   /* allocate storage for bitfield object */
   bf = (bitfield *) malloc(sizeof(bitfield));
   if (bf != NULL) {
      /* initialize bitfield, on errors, free bitfield */
      if (!sge_bitfield_init(bf, size)) {
         free(bf);
         bf = NULL;
      }
   }

   return bf;
}

/****** uti/bitfield/sge_bitfield_init() ***************************************
*  NAME
*     sge_bitfield_init() -- initialize a bitfield object
*
*  SYNOPSIS
*     bool 
*     sge_bitfield_init(bitfield *bf, unsigned int size) 
*
*  FUNCTION
*     Initializes a bitfield object.
*     Storage for the bits is allocated if necessary (size of the bitfield is 
*     bigger than the preallocated storage) and the size is stored.
*
*  INPUTS
*     bitfield *bf      - the bitfield to initialize
*     unsigned int size - the targeted size of the bitfield
*
*  RESULT
*     bool - true on success, else false
*
*  NOTES
*     MT-NOTE: sge_bitfield_init() is MT safe 
*******************************************************************************/
bool
sge_bitfield_init(bitfield *bf, unsigned int size)
{
   bool ret = true;

   if (bf == NULL) {
      ret = false;
   } else {
      unsigned int char_size = sge_bitfield_get_size_bytes(size);

      /* malloc bitfield buffer only if char * has less bits than required */
      if (size <= fixed_bits) {
         /* clear buffer */
         bf->bf.dyn = (char *)0;
      } else {
         bf->bf.dyn = (char *)malloc(char_size);
         if (bf->bf.dyn == NULL) {
            ret = false;
         } else {
            /* clear buffer */
            memset(bf->bf.dyn, 0, char_size);
         }
      }

      bf->size = size;
   }
   
   return ret;
}

/****** sge_bitfield/sge_bitfield_copy() ***************************************
*  NAME
*     sge_bitfield_copy() -- copies a bitfield into another one. 
*
*  SYNOPSIS
*     bool
*     sge_bitfield_copy(const bitfield *source, bitfield *target) 
*
*  FUNCTION
*     The memory has to be allocated before, and source and target has to have
*     the same size. Otherwise it will return false and does not copy anything.
*
*  INPUTS
*     const bitfield *source  - source bitfield
*     bitfield *target        - target bitfield
*
*  RESULT
*     bool - false, if one of the bitfields is NULL or 
*                   the bitfield sizes are different
*
*  NOTES
*     MT-NOTE: sge_bitfield_copy() is MT safe 
*
*******************************************************************************/
bool 
sge_bitfield_copy(const bitfield *source, bitfield *target)
{
   bool ret = true;

   if (source == NULL || target == NULL) {
      ret = false;
   }

   if (ret && source->size != target->size) {
      ret = false;
   }
   if (ret) {
      unsigned int char_size = sge_bitfield_get_size_bytes(source->size);
      if (source->size <= fixed_bits) {
         target->bf.dyn = source->bf.dyn;
      } else {
         memcpy(target->bf.dyn, source->bf.dyn, char_size);
      }
   }
   
   return ret;
}


/****** sge_bitfield/sge_bitfield_bitwise_copy() *******************************
*  NAME
*     sge_bitfield_copy() -- copies a bitfield into another one. 
*
*  SYNOPSIS
*     bool 
*     sge_bitfield_bitwise_copy(const bitfield *source, bitfield *target) 
*
*  FUNCTION
*     The memory has to be allocated before, but the bitfields can have
*     different sizes.  If the source is longer than the target, only the bits
*     up to target's length are copied.
*
*  INPUTS
*     const bitfield *source  - source bitfield
*     bitfield *target        - target bitfield
*
*  RESULT
*     bool - false, if one of the bitfields is NULL
*
*  NOTES
*     MT-NOTE: sge_bitfield_bitwise_copy() is MT safe 
*
*******************************************************************************/
bool 
sge_bitfield_bitwise_copy(const bitfield *source, bitfield *target)
{
   bool ret = true;

   if (source == NULL || target == NULL) {
      ret = false;
   }

   if (ret) {
      unsigned int char_size = 0;
      const char *source_buffer = sge_bitfield_get_buffer(source);
      char *target_buffer = sge_bitfield_get_buffer(target);
     
      if (source->size > target->size) {
         /* This may result in the target getting a few more bits than it wants
          * (if target->size isn't a multiple of 8), but that shouldn't matter
          * because sge_bitfield_get() guards against accessing those extra
          * bits. */
         char_size = sge_bitfield_get_size_bytes(target->size);
      } else {
         char_size = sge_bitfield_get_size_bytes(source->size);
      }
      
      memcpy(target_buffer, source_buffer, char_size);
   }
   
   return ret;
}

/****** sge_bitfield/sge_bitfield_changed() ************************************
*  NAME
*     sge_bitfield_changed() -- figures out if something was changed.
*
*  SYNOPSIS
*     bool 
*     sge_bitfield_changed(const bitfield *source) 
*
*  FUNCTION
*
*  INPUTS
*     bitfield *source - bitfield to analyze
*
*  RESULT
*     bool - true, if the bitfield has a changed bit set.
*
*  NOTES
*     MT-NOTE: sge_bitfield_copy() is MT safe 
*
*******************************************************************************/
bool 
sge_bitfield_changed(const bitfield *bf) 
{
   bool ret = false;

   if (bf != NULL) {
      const char *buf = sge_bitfield_get_buffer(bf);
      unsigned int char_size = sge_bitfield_get_size_bytes(bf->size);
      unsigned int i;

      for (i = 0; i < char_size; i++) {
         if (buf[i] != 0) {
            ret = true;
            break;
         }
      }
   }
   
   return ret;
}

/****** sge_bitfield/sge_bitfield_reset() ***************************************
*  NAME
*     sge_bitfield_reset() -- clears a bitfield
*
*  SYNOPSIS
*     bool 
*     sge_bitfield_reset(bitfield *bf) 
*
*  FUNCTION
*
*  INPUTS
*     bitfield *bf - bitfield to reset
*
*  RESULT
*     bool - false, if bf is NULL
*
*  NOTES
*     MT-NOTE: sge_bitfield_copy() is MT safe 
*
*******************************************************************************/
bool 
sge_bitfield_reset(bitfield *bf)
{
   if (bf != NULL) {
      if (bf->size > fixed_bits) {
         unsigned int char_size = sge_bitfield_get_size_bytes(bf->size);
         memset(bf->bf.dyn, 0, char_size);
      } else {
         bf->bf.dyn = (char *)0;
      }

      return true;    
   }
   
   return false;
}


/****** uti/bitfield/sge_bitfield_free() ***************************************
*  NAME
*     sge_bitfield_free() -- destroy a bitfield
*
*  SYNOPSIS
*     bitfield sge_bitfield_free(bitfield *bf) 
*
*  FUNCTION
*     Destroys a bitfield. Frees all memory allocated by the bitfield.
*
*  INPUTS
*     bitfield *bf - the bitfield to destroy
*
*  NOTES
*     MT-NOTE: sge_bitfield_free() is MT safe
*
*  RESULT
*     bitfield * - NULL
*******************************************************************************/
bitfield *sge_bitfield_free(bitfield *bf)
{
   if (bf != NULL) {
      if (bf->size > fixed_bits) {
         if (bf->bf.dyn != NULL) {
            free(bf->bf.dyn);
         }
      }

      free(bf);
   }

   return NULL;
}

/****** uti/bitfield/sge_bitfield_free_data() **********************************
*  NAME
*     sge_bitfield_free_data() -- free the bitfield data
*
*  SYNOPSIS
*     bool 
*     sge_bitfield_free_data(bitfield *bf) 
*
*  FUNCTION
*     Frees the data part of a bitfield.
*     The bitfield itself is not freed.
*
*  INPUTS
*     bitfield *bf - the bitfield to work on
*
*  RESULT
*     bool - true on success, else false
*
*  NOTES
*     MT-NOTE: sge_bitfield_free_data() is MT safe 
*******************************************************************************/
bool
sge_bitfield_free_data(bitfield *bf)
{
   bool ret = true;

   if (bf == NULL) {
      ret = false;
   } else {
      if (bf->size > fixed_bits) {
         if (bf->bf.dyn != NULL) {
            free(bf->bf.dyn);
            bf->bf.dyn = NULL;
         }
      }
   }

   return ret;
}

/****** uti/bitfield/sge_bitfield_set() ****************************************
*  NAME
*     sge_bitfield_set() -- set a bit
*
*  SYNOPSIS
*     bool
*     sge_bitfield_set(bitfield *bf, unsigned int bit) 
*
*  FUNCTION
*     Sets a certain bit in a bitfield to 1.
*
*  INPUTS
*     bitfield *bf - the bitfield to manipulate
*     unsigned int bit     - the bit to set
*
*  NOTES
*     MT-NOTE: sge_bitfield_set() is MT safe
*
*  RESULT
*     bool - true on success, 
*           false on error
*******************************************************************************/
bool
sge_bitfield_set(bitfield *bf, unsigned int bit)
{
   bool ret = true;

   if(bf == NULL || bit >= bf->size) {
      ret = false;
   }

   if (ret) {
      char *buf = sge_bitfield_get_buffer(bf);
      unsigned int byte_offset = bit / 8;
      unsigned int bit_offset  = bit % 8;

      buf[byte_offset] |= 1 << bit_offset;
   }

   return ret;
}

/****** uti/bitfield/sge_bitfield_get() ****************************************
*  NAME
*     sge_bitfield_get() -- read a bit 
*
*  SYNOPSIS
*     bool
*     sge_bitfield_get(const bitfield *bf, unsigned int bit) 
*
*  FUNCTION
*     Reads a certain bit of a bitfield and returns it's contents.
*
*  INPUTS
*     bitfield *bf - the bitfield to read from
*     unsigned int bit     - the bit to read
*
*  NOTES
*     MT-NOTE: sge_bitfield_get() is MT safe
*
*  RESULT
*     bool - false, if bit is not set (or input params invalid),
*            true, if bit is set
*******************************************************************************/
bool
sge_bitfield_get(const bitfield *bf, unsigned int bit)
{
   bool ret = false;

   if (bf != NULL && bit < bf->size) {
      const char *buf = sge_bitfield_get_buffer(bf);
      unsigned int byte_offset = bit / 8;
      unsigned int bit_offset  = bit % 8;

      if ((buf[byte_offset] & (1 << bit_offset)) > 0) {
         ret = true;
      }
   }

   return ret;
}

/****** uti/bitfield/sge_bitfield_clear() **************************************
*  NAME
*     sge_bitfield_clear() -- clear a bit
*
*  SYNOPSIS
*     bool
*     sge_bitfield_clear(bitfield *bf, unsigned int bit) 
*
*  FUNCTION
*     Clears a certain bit in a bitfield (sets its content to 0).
*
*  INPUTS
*     bitfield *bf - the bitfield to manipulate
*     unsigned int bit     - the bit to clear
*
*  NOTES
*     MT-NOTE: sge_bitfield_clear() is MT safe
*
*  RESULT
*     bool - true on success,
*            false on error
*******************************************************************************/
bool
sge_bitfield_clear(bitfield *bf, unsigned int bit)
{
   bool ret = true;

   if(bf == NULL || bit >= bf->size) {
      ret = false;
   }

   if (ret) {
      char *buf = sge_bitfield_get_buffer(bf);
      unsigned int byte_offset = bit / 8;
      unsigned int bit_offset  = bit % 8;

      buf[byte_offset] &= 0xff ^ (1 << bit_offset);
   }

   return ret;
}

/****** uti/bitfield/sge_bitfield_print() **************************************
*  NAME
*     sge_bitfield_print() -- print contents of a bitfield
*
*  SYNOPSIS
*     void sge_bitfield_print(bitfield *bf, FILE *fd) 
*
*  FUNCTION
*     Prints the contents of a bitfield.
*     For each bit one digit (0/1) is printed.
*     If NULL is passed as file descriptor, output is sent to stdout.
*
*  NOTES
*     MT-NOTE: sge_bitfield_print() is MT safe
*
*  INPUTS
*     bitfield  bf - the bitfield to output
*     FILE *fd     - filehandle or NULL
*******************************************************************************/
void sge_bitfield_print(const bitfield  *bf, FILE *fd)
{
   unsigned int i;

   if (bf == NULL) {
      return;
   }

   if (fd == NULL) {
      fd = stdout;
   }

   for (i = 0; i < bf->size; i++) {
      int value = sge_bitfield_get(bf, i) ? 1 : 0;
      fprintf(fd, "%d ", value);
   }
}

