class ref name: flag
class name: flag
category-group: flags
layer: 0
header file: z_flag.h

synopsis.
The flag object provides a facility for setting, unsetting, and getting bits, which logically represents flags (items that can have only 2 values, which we call "on" and "off"). The major operations are simply to set, clear, and test a flag. To reference a particular flag, an offset is used, just like an index into an array.

When you make a flag object, you need to specify in advance how many you need. The number of flags can be increased later, but this is a relatively "expensive" operation.

Besides operations on individual bits ("flags"), you can combine two flag objects to do logical OR, AND, XOR operations between 2 flag objects. There are 2 sets of these operators: those that affect the current object - the operators are of the form "=?", where '?' is the operator ("&=", "|=", "^="); and those that create a new flag object, combining the current object with another.

description.
The flag class object provides for atomic flag operations on a set of bits. Only 1 flag is operated on at a time. You can set, clear, and test a flag. when you need to keep to the status of something such as 'was the operation done?'; 'was the outcome a success?', you can create an integer, char, or similar variable to hold the answer, but there are problems with this approach: you may have a proliferation of variables scattered about; the types can be arbitrary; and it [minor point] wastes space. You can use a single bit to do the job of an entire variable. Use flag_o to economize space!

To reference a flag, an offset is used, just like you use an index to access an array member. Internally in the flag object, the offset is transformed into an index value of an internal array and a bit offset. Thus, for all getters & setters, use the "bit number", starting from 0, for these functions:

  • is_set()
  • is_clear()
  • set()
  • clear(), unset()

For example, set(3) will turn on the 4th flag; clear(0) will turn off ("clear") the first flag, or bit. You don't want to use the numeric value of the bit! "is_set(256);" does not check the 10th bit! ["is_set(9);" does]

When you make a flag object, you can specify in advance how many bits you need. The number of bits used can be increased later. If you don't specify the number of bits, you get a "small" bit object (containing 1 word).

For more advanced applications, you can optionally use your own buffer. This is done by providing a pointer as a parameter to the flag object during construction time or via a call to:
reset_size (u_long *, size_t)
this gives user control as to the source of memory.

SUMMARY OF OVERLOAD OPERATORS:

& ....: AND
| ....: OR
~ ....: XOR
&= ..: AND with assignment
|= ...: OR with assignment
~= ...: XOR with assignment

member functions (primary)

flag_o()
SIGNATURE: flag_o ()
SYNOPSIS: instantiaate a simple flag instance. By default, it creates 16 bits (eg flags).
 

flag_o(flag_o)
SIGNATURE: flag_o (const flag_o &rhs)
SYNOPSIS: makes an exact copy of the RHS object ("rhs")
 

operator = (flag_o)
SIGNATURE: flag_o &operator = (const flag_o &rhs)
SYNOPSIS: copies exactly the object "rhs"; previous contents lost
 

destructor
SIGNATURE: ~flag_o ()
 

flag_o(<args>)
SIGNATURE: flag_o (int val)
SYNOPSIS:
instantiaate a simple flag instance with the default number of bits. In this constructor variation, you give the bitmask value of all the bits:

    flag_o f(11);       // sets bits 0,1,3 (ie, 8+2+1)

PARAMETERS
  • val: the net total value of the flags to set. if this value exceeds the maximum value possible by the default set of bits, excess high values will be discarded.
  • DESCRIPTION: if the default number of bits is 16, and val = 262,145 (== 2^18 + 1), only the first (0th) bit will be set.
     

    flag_o(<args>)
    SIGNATURE: flag_o (size_t n, int value)
    SYNOPSIS:
    instantiaates a flag object instance. In this variation, one specifies the number of bits to create (given by 'n'), and the initial value of all the bits. This constructor allows the application to set the initial value. With this c-tor, given a function "void foo(flag_o)", you can do "foo(flag_o(32,13);", thus automatically setting the desired flag bits in one shot.
    PARAMETERS

    • n: the number of flags to create. This is typically the size of a long integer (in bits) - 32 is a good value.
    • value: the initial value to set all the flag-bits. This value must be less than 2^n. If "value" is greater than 2^(n) - 1, excess bit values will be ignored. Thus, if n == 4, the maximum value of "value" is 15 (==0xF, or 111 in binary).
     

    flag_o(<args>)
    SIGNATURE: flag_o (u_long *my_buf, size_t n)
    SYNOPSIS: supply your own buffer for bit storage in "my_buf", and the size in "n"
     

    is_set()
    SIGNATURE: boolean is_set (int) const
    SYNOPSIS: test if a particular flag is set.
    RETURNS:
    TRUE: flag is set
    FALSE: flag is not set
     

    is_clear()
    SIGNATURE: boolean is_clear(int) const
    SYNOPSIS: test if a particular flag is not set (cleared). The inverse of "is_set()"
    RETURNS:
    TRUE: flag is NOT set
    FALSE: flag IS set
     

    size()
    SIGNATURE: size_t size() const
    SYNOPSIS: returns the total number of flags in the object. This number has nothing to do with whether a flag is set or not.
    RETURNS: returns the total number of flags in the object, eg, its capacity.
     

    size_t cast operator()
    SIGNATURE: operator size_t () const
    SYNOPSIS:
    returns the full value of the bits, as a type size_t. This is equivalent to calling the member function as_number().
    RETURNS: [n >= 0]: the value of all the set bits
     

    as_number()
    SIGNATURE: size_t as_number (int *pi = NULL) const
    SYNOPSIS:
    returns the full value of the bits, as a type size_t. Thus, if bit 0 (value: 1) and bit 3 (value: 8) are set, the number 9 will be returned.
    RETURNS: [n >= 0]: the value of all the set bits
     

    set()
    SIGNATURE: int set (int n)
    SYNOPSIS: set a specific flag; bit "n" turned on
     

    set()
    SIGNATURE: int set (int, boolean)
    SYNOPSIS: set a flag on or off, depending on the 2nd parameter
    TRAITS:
    do not use. this function is marked for termination, because the name - parameter combo is confusing (the original intent was probably to "set-on" or "set-off", depending on the 2nd parameter).
     

    clear()
    SIGNATURE: int clear (int n)
    SYNOPSIS: clear a specific flag; bit "n" turned off
     

    unset()
    SIGNATURE: int unset (int n)
    SYNOPSIS: clear a specific flag. an alias for "clear()"
     

    reset()
    SIGNATURE: int reset (size_t)
    SYNOPSIS: set the old bits, set fresh bits
     

    reset()
    SIGNATURE: int reset()
    SYNOPSIS: same as "clear_all()"
     

    operator ~()
    SIGNATURE: flag_o operator ~ () const
    SYNOPSIS: returns the inverse of the flag values, in a flag object
     

    operator |()
    SIGNATURE: flag_o operator | (const flag_o &) const
    SYNOPSIS:
    logical OR current object (x) with RHS object (y), return a new object whos flags are or'd (x | y). # of flags in resultant object is the smaller of the two
     

    operator &()
    SIGNATURE: flag_o operator | (const flag_o &) const
    SYNOPSIS:
    logical AND current object (x) with RHS object (y), return a new object whos flags are and'd (x & y). # of flags in resultant object is the smaller of the two
     

    operator ^()
    SIGNATURE: flag_o operator | (const flag_o &) const
    SYNOPSIS:
    logical AND current object (x) with RHS object (y), return a new object whos flags are xor'd (x ^ y). # of flags in resultant object is the smaller of the two
     

    operator &=()
    SIGNATURE: void operator &= (const flag_o &)
    SYNOPSIS: AND current object with another flag object. results saved in the current object.
     

    operator |=()
    SIGNATURE: void operator |= (const flag_o &)
    SYNOPSIS: AND current object with another flag object
     

    operator ^=()
    SIGNATURE: void operator ^= (const flag_o &)
    SYNOPSIS: XOR current object w. another flag object
     

    operator =()
    SIGNATURE: flag_o &operator = (int)
    SYNOPSIS:
    set all the bits. this is useful when you know exactly what the numeric equivalent of all the bits are. example:
    flag_o f;
    f = 11; // sets bits 0, 1, and 3 (eg, 1 + 2 + 8 = 11)
    f = 25; // sets bits 0, 3, and 4 (eg, 1 + 8 + 16 = 25)
     

    reset_size()
    SIGNATURE: int reset_size(const size_t)
    SYNOPSIS: expand/contract # bits
     

    reset_size()
    SIGNATURE: u_long *reset_size(u_long *, const size_t)
    SYNOPSIS: set a new buffer (user-supplied), and set-reset the size
     

    clear_all()
    SIGNATURE: int clear_all()
    SYNOPSIS: wipe out - clears all bits, eg sets all flags to 0 (FALSE).
     

    examples.
    The following example uses 2 flag objects 'x' and 'y'. In the main double-loop of the program, we display which bits are set in 'x'. We do this loop twice. The first time, we just dump x's set flags. The second time around, we reset the number of flags in x, chopping it from 22 to 9. Then we invert x with the "~" operator, reversing the values of all the flags.

    #include "z_flag.h"
    #include <iostream>
    
    int main ()
    {
        flag_o x, y(22);            // x has 16 flags; y has 22 flags
        int i = 7, j = 11;
    
        if (i + j == 20)            // if 7 + 11 = 20, set 3rd bit
            y.set (2);
        else if (i + j == 18)       // if 7 + 11 = 18, clear 3rd bit, set 4th bit
            { y.clear (2); y.set (3); }
    
        x = y;                      // wholesale copy of all flags
        if (x.is_set (3))           // test if a flag is set
            std::cout << "7 + 11 = 18!\n";
        else
            std::cout << "7 + 11 != 18!\n";
    
        std::cout << "how many flags x has?: " << x.size() << std::endl;
    
        y.reset_size (6);
        std::cout << "how many flags y has?: " << y.size() << std::endl;
    
        if (y.set(7))
            std::cout << "failed to set '7th bit' in y [no surprise]\n";
    
        y.set (1);                  // set 2nd bit
        y.set (2);                  // set 3rd bit
        x |= y;                     // OR y with x; results saved in x
    
        y.clear(0);                 // use y's 1st bit as flag - found a flag in x?
    
        for (j = 0; j < 2; j++)
        {
            if (j == 0)
                std::cout << "bits that are set in 'x': ";
            else if (j == 1)
            {
                std::cout << "\nlet's limit # of bits in x to 9,\nand invert x: ";
                std::cout << "\"x = ~x\". Now see what bits are set:\n    ";
    
                y.clear(0);
                x.reset_size(9);
                x = ~x;
            }
    
            for (i = 0; i < x.size(); i++)
            {
                if (x.is_set(i))
                {
                    if (y.is_set(0))
                        std::cout << ", ";
                    std::cout << i; y.set(0);
                }
            }
        }
    
        std::cout << std::endl;
        return (0);
    }
    
    OUTPUT:
        7 + 11 = 18!
        how many flags x has?: 22
        how many flags y has?: 6
        failed to set '7th bit' in y [no surprise]
        bits that are set in 'x': 1, 2, 3
        let's limit # of bits in x to 9,
        and invert x: "x = ~x". Now see what bits are set:
        0, 4, 5, 6, 7, 8
    

    history.

    ??? 01/03/1994: class interface rewritten, to meet the canonical format
    ??? 01/04/1994: added "|", "&", "~"
    ??? 03/20/1994: class renamed, from 'bit_o' to 'flag_o'
    ??? 04/09/1994: realization: more work for user-supplied buffering.
    ??? 04/14/1994: added functionality: user can supply buffer space
    ??? 09/25/1995: "get_size()" -> "size()"; added XOR capability
    ??? 12/23/1997: added "init()"
    ??? 12/24/1997: made sure the < # bits in long works
    ??? 06/05/2002: some validation code added for AND, OR, XOR operations
    Mon 02/07/2011: fixed some mismatches in signitures of internal