

// 2D - bit packed array
// fundamental class definitions

#include <stdlib.h>
#include <iostream.h>

enum logical { FALSE, TRUE };

typedef unsigned char BYTE;

template < int XDIM, int YDIM, int NUM_BITS >
class Bit_2D_Array {
    private:
        // You can't initialize NUM_BYTES here, but you can dimension
        // data, so NUM_BYTES = sizeof(data);
        int NUM_BYTES;

        BYTE data[( XDIM * YDIM * NUM_BITS + 7 ) / 8];

        class BIT_TMP {
            public:
                BYTE * byte_ptr;
                BYTE   shift_bits;
                BYTE   value;

                BYTE MASK[8];     // All but bits of interest CLEARED
                BYTE INV_MASK[8]; // All but bits of interest SET

                operator int() {
                    return( value );
                }

                BIT_TMP() {
                    double num_sub_fields;
                    BYTE tmp_mask;
                    int i;

                    // Needed for Cfront3.0
                    cout << " BIT_TMP" << endl;

                    num_sub_fields = 8.0 / NUM_BITS;
                    if ( num_sub_fields * NUM_BITS != 8 ) {
                        cerr << "NUM_BITS must divide evenly into 8" << endl;
                        exit(1);
                    }
                    tmp_mask = 1;
                    for( i=1; i<NUM_BITS; i++) {
                        tmp_mask <<= 1;
                        tmp_mask |= 1;
                    }
                    for( i=0; i<num_sub_fields; i++ ) {
                        MASK[i] = tmp_mask << (i*NUM_BITS);
                        INV_MASK[i] = 255 ^ MASK[i];
                    }
                }

                void operator=( class BIT_TMP input ) {

                    input.value &= MASK[0]; // Mask off any extraneous bits 
                    *(byte_ptr) &= INV_MASK[ shift_bits / NUM_BITS ];
                    *(byte_ptr) |= ( input.value << shift_bits );
                    value = input.value; 
                }

                void operator=( BYTE input_value ) {

                    input_value &= MASK[0]; // Mask off any extraneous bits 
                    *(byte_ptr) &= INV_MASK[ shift_bits / NUM_BITS ];
                    *(byte_ptr) |= ( input_value << shift_bits );
                    value = input_value; 
                }

                logical operator==( class BIT_TMP input ) {
                    return( logical( value == input.value) );
                }
        };

        class BIT_TMP local_rec;  

    public:
        Bit_2D_Array();

        // This should be an overloaded ostream but Cfront3.0 crashes
        void dump() {
            int i, j;

	    cout.width(3);
	    cout << endl ;
	    for( j=0; j<YDIM; j++) {
		cout << j << " ";
	    }
	    cout << endl;
	    cout << "  ";
	    for( j=0; j<YDIM; j++) {
		cout << "----";
            }
            cout << endl;
            for( i=0; i<XDIM; i++) {
                cout << i << "|";
                for( j=0; j<YDIM; j++) {
                    cout << (*this)(i,j) << " ";
                }
                cout << endl;
            }
        }

        class BIT_TMP operator()( int i, int j ) {
            BYTE bit_num, byte_num, sub_bits;

            bit_num  = NUM_BITS * (XDIM*i + j);
            byte_num = bit_num / 8;
            sub_bits = bit_num % 8;

            local_rec.byte_ptr = &data[byte_num];
            local_rec.shift_bits = sub_bits;
            local_rec.value = 
		local_rec.MASK[0] & ( data[byte_num] >> sub_bits );
		cout << " subscript for " << i << ',' << j << endl ;
            return( local_rec );
        };

        logical operator==( Bit_2D_Array< XDIM, YDIM, NUM_BITS > RHS ) {
            int i;

            for( i=0; i< NUM_BYTES; i++) {
                if ( data[i] != RHS.data[i] ) {
                    return( FALSE );
                }
            }
            return( TRUE );
        };

        void operator=( int RHS ) {
            int i, j;

            for( i=0; i< XDIM; i++) {
                for( j=0; j< YDIM; j++) {
                    (*this)(i,j) = RHS;
                }
            }
        };
};

