/** @file  psBitSet.h
 *
 *  @brief Creates an array of bytes of arbitrary length for storing individual bits.
 *
 *  Bit masks are useful tools for toggling various flags and options. This set of functions module provides
 *  a mechanism to create an array of bits of arbitrary length and manipulate them with basic binary
 *  operations. A print function is also provided to display the entire set of bits in binary format as a
 *  string.
 *
 *  @ingroup BitSet
 *
 *  @author Ross Harman, MHPCC
 *
 *  @version $Revision: 1.15 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2004-10-27 00:57:31 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 */

#ifndef PSBITSET_H
#define PSBITSET_H

#include "psType.h"

/// @addtogroup BitSet
/// @{

/******************************************************************************/
/*  TYPE DEFINITIONS                                                          */
/******************************************************************************/

/** Struct containing array of bytes to hold bit data and corresponding array length.
 *
 *  The bits in the struct are assembled in as an array of bytes with eight bits per byte. The bits are
 *  arranged with the LSB in first (right most) position of the first array element.
 */
typedef struct
{
    psS32 n;                             ///< Number of bytes in the array
    char *bits;                        ///< Aray of bytes holding bits
}
psBitSet;

/*****************************************************************************/
/* FUNCTION PROTOTYPES                                                       */
/*****************************************************************************/

/** Allocate a psBitSet.
 *
 *  Create a psBitSet with the number of bits specified by the user. All bits are set to zero upon
 *  allocation.
 *
 *  @return  psBitSet* : Pointer to struct containing array of bits and size of array.
 */

/*@null@*/
psBitSet* psBitSetAlloc(
    psS32 n                              ///< Number of bits in psBitSet array
);

/** Set a bit.
 *
 *  Sets a bit at a given bit location. The bit is set based on a zero index with the
 *  first bit set in the zero bit slot of the zero element of the byte array. As an example, setting bit 3 in
 *  an array with two elements would result in an psBitSet that looks like 00000000 00001000.
 *
 *  @return  psBitSet* : Pointer to struct containing psBitSet.
 */
psBitSet* psBitSetSet(
    /* @returned@ */
    psBitSet* restrict inMask,         ///< Pointer to psBitSet to be set.
    psS32 bit                            ///< Bit to be set.
);

/** Clear a bit.
 *
 *  Clear a bit at a given bit location. The bit is cleared based on a zero 
 *  index with the first bit set in the zero bit slot of the zero element of 
 *  the byte array. 
 *
 *  @return  psBitSet* : Pointer to struct containing psBitSet.
 */
psBitSet* psBitSetClear(
    /* @returned@ */
    psBitSet* restrict inMask,         ///< Pointer to psBitSet to be cleared.
    psS32 bit                            ///< Bit to be cleared.
);

/** Test the value of a bit.
 *
 *  Prints the value of a bit at a given bit location, either one or zero. The resulting bit is based on a
 *  zero index format with the first bit set in the zero bit slot of the zero element of the byte array
 *  As an example, testing bit 3 in a psBitSet with two bytes that looks like 00000000 00001000 would return a
 *  value of one, since that is the value that was set.
 *
 *  @return  int: Value of bit, either one or zero.
 */

psBool psBitSetTest(
    const psBitSet* restrict inMask,   ///< Pointer psBitSet to be tested.
    psS32 bit                            ///< Bit to be tested.
);

/** Perform a binary operation on two psBitSets
 *
 *  Perform an AND, OR, or XOR on two psBitSets. If the BitMasks are not the same size, the operation will not
 *  be performed and an error message will be logged.
 *
 *  @return  psBitSet* : Pointer to struct containing result of binary operation.
 */
psBitSet* psBitSetOp(
    /* @returned@ */
    psBitSet* restrict outMask,        ///< Resulting psBitSet from binary operation
    const psBitSet* restrict inMask1,  ///< First psBitSet on which to operate
    char *operator,                    ///< Bit operation
    const psBitSet* restrict inMask2   ///< First psBitSet on which to operate
);

/** Perform a not operation on a psBitSet
 *
 *  Toggles bits in a psBitset. All zero bits are set to one and all one bits are set to zero.
 *
 *  @return  psBitSet* : Pointer to struct containing result of operation.
 */

psBitSet* psBitSetNot(
    psBitSet* outBitSet,               ///< Resulting psBitSet from operation
    const psBitSet* restrict inBitSet  ///< Input psBitSet
);

/** Convert the psBitSet to a string of ones and zeros.
 *
 *  Converts the contents of a psBitSet to a string representation of its binary form of ones and zeros. The
 *  LSB is the right-most chracter. Each set of eight characters represents one byte.
 *
 *  @return  char*: Pointer to character array containing string data.
 */

char *psBitSetToString(
    const psBitSet* restrict inMask    ///< psBitSet to convert */
);

/// @}

#endif
