/** @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.28 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2007-01-23 22:47:23 $
 *
 *  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.
 */
psBitSet* psBitSetAlloc(
    long nalloc                        ///< 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(
    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  psBitSet* : Pointer to struct containing psBitSet.
 */
psBitSet* 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
