/** @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.
 *
 *  @author PAP, EAM, IfA
 *  @author Ross Harman, MHPCC
 *
 *  @version $Revision: 1.31 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2007-08-09 01:40:08 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
 */

#ifndef PSBITSET_H
#define PSBITSET_H

#include "psType.h"

/// @addtogroup DataContainer Data Containers
/// @{

/******************************************************************************/
/*  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
{
    long n;                            ///< Number of bytes in the array
    psU8 *bits;                        ///< Aray of bytes holding bits
    void *lock;                        ///< Optional lock for thread safety
}
psBitSet;

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

/** Checks the type of a particular pointer.
 *
 *  Uses the appropriate deallocation function in psMemBlock to check the ptr
 *  datatype.
 *
 *  @return bool:     True if the pointer matches a psBitSet structure, false otherwise.
 */
bool psMemCheckBitSet(
    psPtr ptr                          ///< the pointer whose type to check
);


/** 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.
 */
#ifdef DOXYGEN
psBitSet* psBitSetAlloc(
    long nalloc                        ///< Number of bits in psBitSet array
);
#else // ifdef DOXYGEN
psBitSet* p_psBitSetAlloc(
    const char *file,                   ///< File of caller
    unsigned int lineno,                ///< Line number of caller
    const char *func,                   ///< Function name of caller
    long nalloc                        ///< Number of bits in psBitSet array
) PS_ATTR_MALLOC;
#define psBitSetAlloc(nalloc) \
      p_psBitSetAlloc(__FILE__, __LINE__, __func__, nalloc)
#endif // ifdef DOXYGEN




/** 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  bool : Successful operation?
 */
bool psBitSetSet(
    psBitSet* bitSet,                  ///< Pointer to psBitSet to be set.
    long 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  bool : Successful operation?
 */
bool psBitSetClear(
    psBitSet* bitSet,                  ///< Pointer to psBitSet to be cleared.
    long 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  bool:      True if successful, otherwise false
 */
bool psBitSetTest(
    const psBitSet* bitSet,            ///< Pointer psBitSet to be tested.
    long 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(
    psBitSet* outBitSet,               ///< Resulting psBitSet from binary operation
    const psBitSet* inBitSet1,         ///< First psBitSet on which to operate
    const char *operator,              ///< Bit operation
    const psBitSet* inBitSet2          ///< Second 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* 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  psString:      Pointer to character array containing string data.
 */
psString psBitSetToString(
    const psBitSet* bitSet             ///< psBitSet to convert
);


/// @}
#endif // #ifndef PSBITSET_H
