// Copyright 1996 by Jon Dart.  All Rights Reserved.
#ifndef _BITMAP_H
#define _BITMAP_H

#include "types.h"


#define FAST_SHIFT_R(data,n) \
    (n>=32) ? Bitmap(data.hivalue()>>(n)-32) \
         : Bitmap((uint32)data.value() >> (n))

class Bitmap
{
    public:	

    Bitmap()
    : data(0)
    {
    }
    
    Bitmap(uint64 n)
    : data(n)
    {
    }
    
    uint64 value() const
    {
       return data;
    }
    
    void *addr() const
    {
       return (void*)&data;
    }
    
    byte byte_value() const
    {
       // PC is little-endian
       return *((byte*)&data);
    }
    
    uint32 hivalue() const
    {
       struct ints
       {
          uint32 loval,hival;
       };
       union conv
       {
          uint64 val1;
          ints val2;
       };
       return ((conv*)(this))->val2.hival;
    }
    
    uint32 lovalue() const
    {
       struct ints
       {
          uint32 loval,hival;
       };
       union conv
       {
          uint64 val1;
          ints val2;
       };
       return ((conv*)(this))->val2.loval;
    }
    
    void clear()
    {
       data = 0;
    }
    void set(int n)
    {
       data |= mask[n];
    }
    void clear(int n)
    {
       data &= not_mask[n];
    }
    void setR90(int n)
    {
        data |= maskR90[n];
    }
    void clearR90(int n)
    {
        data &= not_maskR90[n];
    }
    void setDa1(int n)
    {
        data |= maskDa1[n];
    }
    void clearDa1(int n)
    {
        data &= not_maskDa1[n];
    }
    void setDa8(int n)
    {
        data |= maskDa8[n];
    }
    void clearDa8(int n)
    {
        data &= not_maskDa8[n];
    }
    int is_set(int n) const;
    int is_clear()const
    {
        return (data == (uint64)0);
    }
    static Bitmap and( const Bitmap &src1, const Bitmap &src2)
    {
       return Bitmap(src1.data & src2.data);
    }
    void and( const Bitmap &b)
    {
        data &= b.data;
    }
    void andNot(const Bitmap &b)
    {
       data &= ~b.data;
    }
    static Bitmap andNot( const Bitmap &src1, const Bitmap &src2)
    {
       return Bitmap(src1.data & ~src2.data);
    }
    void orNot(const Bitmap &b)
    {
       data |= ~b.data;
    }
    static Bitmap orNot( const Bitmap &src1, const Bitmap &src2)
    {
       return Bitmap(src1.data | ~src2.data);
    }
    static Bitmap or( const Bitmap &src1, const Bitmap &src2)
    {
       return Bitmap(src1.data | src2.data);
    }
    void or( const Bitmap &b)
    {
        data |= b.data;
    }
    static Bitmap shr(const Bitmap &src, int n)
    {
        return Bitmap(src.data >> n);
    }
    void shr(int n)
    {
        data = data >> n;    
    }
    static Bitmap shl(const Bitmap &src, int n)
    {
        return Bitmap(src.data << n);
    }
    void shl(int n)
    {
        data = data << n;    
    }
    void shl_byte(int n)
    {
        // shift lowest 8 bits left by n bytes
        char *p = (char*)&data;
        p[n] = *p;
        if (n>0) *p = 0;
    }
    static Bitmap Bitmap::shl_byte(byte b, int n)
    {
        // shift lowest 8 bits left by n bytes
        uint64 new_data = 0;
        char *p = (char*)&new_data;
        p[n] = b;
        if (n>0) *p = 0;
        return Bitmap(new_data);
    }
    
    int operator == (const Bitmap &b)
    {
       return b.data == data;
    }

    int operator != (const Bitmap &b)
    {
       return b.data != data;
    }

    // return the index of the first bit set, 127 if none.
    int FirstOne() const;
    
    // return the number of bits set
    int bit_count() const;
    
    static void init();
    
    static void cleanup();

    static int unrot90[64];
    static uint64 mask[64];
    static uint64 not_mask[64];
    static uint64 maskR90[64];
    static uint64 not_maskR90[64];
    static uint64 maskDa1[64];
    static uint64 not_maskDa1[64];
    static uint64 maskDa8[64];
    static uint64 not_maskDa8[64];
    static int R90[64];
    static int da1[64];
    static int unrot_da1[64];
    static int da1_mask[64];
    static int da8[64];
    static int unrot_da8[64];
    static int da8_mask[64];

    protected:

    uint64 data;
};
#endif
