/** @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.24 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2005-09-15 21:22:22 $
 *
 *  Copyright 2004-2005 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
{
    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            ///< 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* 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.
 */

psString psBitSetToString(
    const psBitSet* bitSet             ///< psBitSet to convert */
);

/// @}

#endif // #ifndef PSBITSET_H
