///
/// \file
/// Contains the C implementation of ANTLR3 bitsets as adapted from Terence Parr's
/// Java implementation.
///

// [The "BSD licence"]
// Copyright (c) 2005-2009 Jim Idle, Temporal Wave LLC
// http://www.temporal-wave.com
// http://www.linkedin.com/in/jimidle
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. The name of the author may not be used to endorse or promote products
//    derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include    <antlr3bitset.h>

// External interface
//

static  pANTLR3_BITSET  antlr3BitsetClone               (pANTLR3_BITSET inSet);
static  pANTLR3_BITSET  antlr3BitsetOR                  (pANTLR3_BITSET bitset1, pANTLR3_BITSET bitset2);
static  void                    antlr3BitsetORInPlace   (pANTLR3_BITSET bitset, pANTLR3_BITSET bitset2);
static  ANTLR3_UINT32   antlr3BitsetSize                (pANTLR3_BITSET bitset);
static  void                    antlr3BitsetAdd                 (pANTLR3_BITSET bitset, ANTLR3_INT32 bit);
static  ANTLR3_BOOLEAN  antlr3BitsetEquals              (pANTLR3_BITSET bitset1, pANTLR3_BITSET bitset2);
static  ANTLR3_BOOLEAN  antlr3BitsetMember              (pANTLR3_BITSET bitset, ANTLR3_UINT32 bit);
static  ANTLR3_UINT32   antlr3BitsetNumBits             (pANTLR3_BITSET bitset);
static  void                    antlr3BitsetRemove              (pANTLR3_BITSET bitset, ANTLR3_UINT32 bit);
static  ANTLR3_BOOLEAN  antlr3BitsetIsNil               (pANTLR3_BITSET bitset);
static  pANTLR3_INT32   antlr3BitsetToIntList   (pANTLR3_BITSET bitset);

// Local functions
//
static  void                    growToInclude           (pANTLR3_BITSET bitset, ANTLR3_INT32 bit);
static  void                    grow                            (pANTLR3_BITSET bitset, ANTLR3_INT32 newSize);
static  ANTLR3_UINT64   bitMask                         (ANTLR3_UINT32 bitNumber);
static  ANTLR3_UINT32   numWordsToHold          (ANTLR3_UINT32 bit);
static  ANTLR3_UINT32   wordNumber                      (ANTLR3_UINT32 bit);
static  void                    antlr3BitsetFree        (pANTLR3_BITSET bitset);

static void
antlr3BitsetFree(pANTLR3_BITSET bitset)
{
    if  (bitset->blist.bits != NULL)
    {
                ANTLR3_FREE(bitset->blist.bits);
                bitset->blist.bits = NULL;
    }
    ANTLR3_FREE(bitset);

    return;
}

ANTLR3_API pANTLR3_BITSET
antlr3BitsetNew(ANTLR3_UINT32 numBits)
{
        pANTLR3_BITSET  bitset;

        ANTLR3_UINT32   numelements;

        // Allocate memory for the bitset structure itself
        //
        bitset  = (pANTLR3_BITSET) ANTLR3_MALLOC((size_t)sizeof(ANTLR3_BITSET));

        if      (bitset == NULL)
        {
                return  NULL;
        }

        // Avoid memory thrashing at the up front expense of a few bytes
        //
        if      (numBits < (8 * ANTLR3_BITSET_BITS))
        {
                numBits = 8 * ANTLR3_BITSET_BITS;
        }

        // No we need to allocate the memory for the number of bits asked for
        // in multiples of ANTLR3_UINT64.
        //
        numelements     = ((numBits -1) >> ANTLR3_BITSET_LOG_BITS) + 1;

        bitset->blist.bits    = (pANTLR3_BITWORD) ANTLR3_MALLOC((size_t)(numelements * sizeof(ANTLR3_BITWORD)));
        if      (bitset->blist.bits == NULL)
        {
                ANTLR3_FREE(bitset);
                return  NULL;
        }
        memset(bitset->blist.bits, 0, (size_t)(numelements * sizeof(ANTLR3_BITWORD)));
        bitset->blist.length  = numelements;

        antlr3BitsetSetAPI(bitset);


        // All seems good
        //
        return  bitset;
}

ANTLR3_API void
antlr3BitsetSetAPI(pANTLR3_BITSET bitset)
{
    bitset->clone               =    antlr3BitsetClone;
    bitset->bor                 =    antlr3BitsetOR;
    bitset->borInPlace  =    antlr3BitsetORInPlace;
    bitset->size                =    antlr3BitsetSize;
    bitset->add                 =    antlr3BitsetAdd;
    bitset->grow                =    grow;
    bitset->equals              =    antlr3BitsetEquals;
    bitset->isMember    =    antlr3BitsetMember;
    bitset->numBits             =    antlr3BitsetNumBits;
    bitset->remove              =    antlr3BitsetRemove;
    bitset->isNilNode           =    antlr3BitsetIsNil;
    bitset->toIntList   =    antlr3BitsetToIntList;

    bitset->free                =    antlr3BitsetFree;
}

ANTLR3_API pANTLR3_BITSET
antlr3BitsetCopy(pANTLR3_BITSET_LIST blist)
{
    pANTLR3_BITSET  bitset;
        int                             numElements;

    // Allocate memory for the bitset structure itself
    //
    bitset  = (pANTLR3_BITSET) ANTLR3_MALLOC((size_t)sizeof(ANTLR3_BITSET));

    if  (bitset == NULL)
    {
                return  NULL;
    }

        numElements = blist->length;

    // Avoid memory thrashing at the expense of a few more bytes
    //
    if  (numElements < 8)
    {
                numElements = 8;
    }

    // Install the length in ANTLR3_UINT64 units
    //
    bitset->blist.length  = numElements;

    bitset->blist.bits    = (pANTLR3_BITWORD)ANTLR3_MALLOC((size_t)(numElements * sizeof(ANTLR3_BITWORD)));

    if  (bitset->blist.bits == NULL)
    {
                ANTLR3_FREE(bitset);
                return  NULL;
    }

        ANTLR3_MEMCPY(bitset->blist.bits, blist->bits, (ANTLR3_UINT64)(numElements * sizeof(ANTLR3_BITWORD)));

    // All seems good
    //
    return  bitset;
}

static pANTLR3_BITSET
antlr3BitsetClone(pANTLR3_BITSET inSet)
{
    pANTLR3_BITSET  bitset;

    // Allocate memory for the bitset structure itself
    //
    bitset  = antlr3BitsetNew(ANTLR3_BITSET_BITS * inSet->blist.length);

    if  (bitset == NULL)
    {
                return  NULL;
    }

    // Install the actual bits in the source set
    //
    ANTLR3_MEMCPY(bitset->blist.bits, inSet->blist.bits, (ANTLR3_UINT64)(inSet->blist.length * sizeof(ANTLR3_BITWORD)));

    // All seems good
    //
    return  bitset;
}


ANTLR3_API pANTLR3_BITSET
antlr3BitsetList(pANTLR3_HASH_TABLE list)
{
    pANTLR3_BITSET              bitSet;
    pANTLR3_HASH_ENUM   en;
    pANTLR3_HASH_KEY    key;
    ANTLR3_UINT64               bit;

    // We have no idea what exactly is in the list
    // so create a default bitset and then just add stuff
    // as we enumerate.
    //
    bitSet  = antlr3BitsetNew(0);

    en          = antlr3EnumNew(list);

    while   (en->next(en, &key, (void **)(&bit)) == ANTLR3_SUCCESS)
    {
                bitSet->add(bitSet, (ANTLR3_UINT32)bit);
    }
    en->free(en);

    return NULL;
}

///
/// \brief
/// Creates a new bitset with at least one 64 bit bset of bits, but as
/// many 64 bit sets as are required.
///
/// \param[in] bset
/// A variable number of bits to add to the set, ending in -1 (impossible bit).
///
/// \returns
/// A new bit set with all of the specified bitmaps in it and the API
/// initialized.
///
/// Call as:
///  - pANTLR3_BITSET = antlrBitsetLoad(bset, bset11, ..., -1);
///  - pANTLR3_BITSET = antlrBitsetOf(-1);  Create empty bitset
///
/// \remarks
/// Stdargs function - must supply -1 as last paremeter, which is NOT
/// added to the set.
///
///
ANTLR3_API pANTLR3_BITSET
antlr3BitsetLoad(pANTLR3_BITSET_LIST inBits)
{
        pANTLR3_BITSET  bitset;
        ANTLR3_UINT32  count;

        // Allocate memory for the bitset structure itself
        // the input parameter is the bit number (0 based)
        // to include in the bitset, so we need at at least
        // bit + 1 bits. If any arguments indicate a
        // a bit higher than the default number of bits (0 means default size)
        // then Add() will take care
        // of it.
        //
        bitset  = antlr3BitsetNew(0);

        if      (bitset == NULL)
        {
                return  NULL;
        }

        if      (inBits != NULL)
        {
                // Now we can add the element bits into the set
                //
                count=0;
                while (count < inBits->length)
                {
                        if  (bitset->blist.length <= count)
                        {
                                bitset->grow(bitset, count+1);
                        }

                        bitset->blist.bits[count] = *((inBits->bits)+count);
                        count++;
                }
        }

        // return the new bitset
        //
        return  bitset;
}

///
/// \brief
/// Creates a new bitset with at least one element, but as
/// many elements are required.
///
/// \param[in] bit
/// A variable number of bits to add to the set, ending in -1 (impossible bit).
///
/// \returns
/// A new bit set with all of the specified elements added into it.
///
/// Call as:
///  - pANTLR3_BITSET = antlrBitsetOf(n, n1, n2, -1);
///  - pANTLR3_BITSET = antlrBitsetOf(-1);  Create empty bitset
///
/// \remarks
/// Stdargs function - must supply -1 as last paremeter, which is NOT
/// added to the set.
///
///
ANTLR3_API pANTLR3_BITSET
antlr3BitsetOf(ANTLR3_INT32 bit, ...)
{
    pANTLR3_BITSET  bitset;

    va_list ap;

    // Allocate memory for the bitset structure itself
    // the input parameter is the bit number (0 based)
    // to include in the bitset, so we need at at least
    // bit + 1 bits. If any arguments indicate a
    // a bit higher than the default number of bits (0 menas default size)
    // then Add() will take care
    // of it.
    //
    bitset  = antlr3BitsetNew(0);

    if  (bitset == NULL)
    {
                return  NULL;
    }

    // Now we can add the element bits into the set
    //
    va_start(ap, bit);
    while   (bit != -1)
    {
                antlr3BitsetAdd(bitset, bit);
                bit = va_arg(ap, ANTLR3_UINT32);
    }
    va_end(ap);

    // return the new bitset
    //
    return  bitset;
}

static pANTLR3_BITSET
antlr3BitsetOR(pANTLR3_BITSET bitset1, pANTLR3_BITSET bitset2)
{
    pANTLR3_BITSET  bitset;

    if  (bitset1 == NULL)
    {
                return antlr3BitsetClone(bitset2);
    }

    if  (bitset2 == NULL)
    {
                return  antlr3BitsetClone(bitset1);
    }

    // Allocate memory for the newly ordered bitset structure itself.
    //
    bitset  = antlr3BitsetClone(bitset1);

    antlr3BitsetORInPlace(bitset, bitset2);

    return  bitset;

}

static void
antlr3BitsetAdd(pANTLR3_BITSET bitset, ANTLR3_INT32 bit)
{
    ANTLR3_UINT32   word;

    word    = wordNumber(bit);

    if  (word   >= bitset->blist.length)
    {
                growToInclude(bitset, bit);
    }

    bitset->blist.bits[word] |= bitMask(bit);

}

static void
grow(pANTLR3_BITSET bitset, ANTLR3_INT32 newSize)
{
    pANTLR3_BITWORD   newBits;

    // Space for newly sized bitset - TODO: come back to this and use realloc?, it may
    // be more efficient...
    //
    newBits = (pANTLR3_BITWORD) ANTLR3_CALLOC(1, (size_t)(newSize * sizeof(ANTLR3_BITWORD)));
    if  (bitset->blist.bits != NULL)
    {
                // Copy existing bits
                //
                ANTLR3_MEMCPY((void *)newBits, (const void *)bitset->blist.bits, (size_t)(bitset->blist.length * sizeof(ANTLR3_BITWORD)));

                // Out with the old bits... de de de derrr
                //
                ANTLR3_FREE(bitset->blist.bits);
    }

    // In with the new bits... keerrrang.
    //
    bitset->blist.bits      = newBits;
    bitset->blist.length    = newSize;
}

static void
growToInclude(pANTLR3_BITSET bitset, ANTLR3_INT32 bit)
{
        ANTLR3_UINT32   bl;
        ANTLR3_UINT32   nw;

        bl = (bitset->blist.length << 1);
        nw = numWordsToHold(bit);

        if      (bl > nw)
        {
                bitset->grow(bitset, bl);
        }
        else
        {
                bitset->grow(bitset, nw);
        }
}

static void
antlr3BitsetORInPlace(pANTLR3_BITSET bitset, pANTLR3_BITSET bitset2)
{
    ANTLR3_UINT32   minimum;
    ANTLR3_UINT32   i;

    if  (bitset2 == NULL)
    {
                return;
    }


    // First make sure that the target bitset is big enough
    // for the new bits to be ored in.
    //
    if  (bitset->blist.length < bitset2->blist.length)
    {
                growToInclude(bitset, (bitset2->blist.length * sizeof(ANTLR3_BITWORD)));
    }

    // Or the miniimum number of bits after any resizing went on
    //
    if  (bitset->blist.length < bitset2->blist.length)
        {
                minimum = bitset->blist.length;
        }
        else
        {
                minimum = bitset2->blist.length;
        }

    for (i = minimum; i > 0; i--)
    {
                bitset->blist.bits[i-1] |= bitset2->blist.bits[i-1];
    }
}

static ANTLR3_UINT64
bitMask(ANTLR3_UINT32 bitNumber)
{
    return  ((ANTLR3_UINT64)1) << (bitNumber & (ANTLR3_BITSET_MOD_MASK));
}

static ANTLR3_UINT32
antlr3BitsetSize(pANTLR3_BITSET bitset)
{
    ANTLR3_UINT32   degree;
    ANTLR3_INT32   i;
    ANTLR3_INT8    bit;

    // TODO: Come back to this, it may be faster to & with 0x01
    // then shift right a copy of the 4 bits, than shift left a constant of 1.
    // But then again, the optimizer might just work this out
    // anyway.
    //
    degree  = 0;
    for (i = bitset->blist.length - 1; i>= 0; i--)
    {
                if  (bitset->blist.bits[i] != 0)
                {
                        for     (bit = ANTLR3_BITSET_BITS - 1; bit >= 0; bit--)
                        {
                                if  ((bitset->blist.bits[i] & (((ANTLR3_BITWORD)1) << bit)) != 0)
                                {
                                        degree++;
                                }
                        }
                }
    }
    return degree;
}

static ANTLR3_BOOLEAN
antlr3BitsetEquals(pANTLR3_BITSET bitset1, pANTLR3_BITSET bitset2)
{
    ANTLR3_INT32   minimum;
    ANTLR3_INT32   i;

    if  (bitset1 == NULL || bitset2 == NULL)
    {
        return  ANTLR3_FALSE;
    }

    // Work out the minimum comparison set
    //
    if  (bitset1->blist.length < bitset2->blist.length)
    {
                minimum = bitset1->blist.length;
    }
    else
    {
                minimum = bitset2->blist.length;
    }

    // Make sure explict in common bits are equal
    //
    for (i = minimum - 1; i >=0 ; i--)
    {
                if  (bitset1->blist.bits[i] != bitset2->blist.bits[i])
                {
                        return  ANTLR3_FALSE;
                }
    }

    // Now make sure the bits of the larger set are all turned
    // off.
    //
    if  (bitset1->blist.length > (ANTLR3_UINT32)minimum)
    {
                for (i = minimum ; (ANTLR3_UINT32)i < bitset1->blist.length; i++)
                {
                        if      (bitset1->blist.bits[i] != 0)
                        {
                                return  ANTLR3_FALSE;
                        }
                }
    }
    else if (bitset2->blist.length > (ANTLR3_UINT32)minimum)
    {
                for (i = minimum; (ANTLR3_UINT32)i < bitset2->blist.length; i++)
                {
                        if      (bitset2->blist.bits[i] != 0)
                        {
                                return  ANTLR3_FALSE;
                        }
                }
    }

    return  ANTLR3_TRUE;
}

static ANTLR3_BOOLEAN
antlr3BitsetMember(pANTLR3_BITSET bitset, ANTLR3_UINT32 bit)
{
    ANTLR3_UINT32    wordNo;

    wordNo  = wordNumber(bit);

    if  (wordNo >= bitset->blist.length)
    {
                return  ANTLR3_FALSE;
    }

    if  ((bitset->blist.bits[wordNo] & bitMask(bit)) == 0)
    {
                return  ANTLR3_FALSE;
    }
    else
    {
                return  ANTLR3_TRUE;
    }
}

static void
antlr3BitsetRemove(pANTLR3_BITSET bitset, ANTLR3_UINT32 bit)
{
    ANTLR3_UINT32    wordNo;

    wordNo  = wordNumber(bit);

    if  (wordNo < bitset->blist.length)
    {
                bitset->blist.bits[wordNo] &= ~(bitMask(bit));
    }
}
static ANTLR3_BOOLEAN
antlr3BitsetIsNil(pANTLR3_BITSET bitset)
{
   ANTLR3_INT32    i;

   for  (i = bitset->blist.length -1; i>= 0; i--)
   {
       if   (bitset->blist.bits[i] != 0)
       {
                        return ANTLR3_FALSE;
       }
   }

   return   ANTLR3_TRUE;
}

static ANTLR3_UINT32
numWordsToHold(ANTLR3_UINT32 bit)
{
    return  (bit >> ANTLR3_BITSET_LOG_BITS) + 1;
}

static  ANTLR3_UINT32
wordNumber(ANTLR3_UINT32 bit)
{
    return  bit >> ANTLR3_BITSET_LOG_BITS;
}

static ANTLR3_UINT32
antlr3BitsetNumBits(pANTLR3_BITSET bitset)
{
    return  bitset->blist.length << ANTLR3_BITSET_LOG_BITS;
}

/** Produce an integer list of all the bits that are turned on
 *  in this bitset. Used for error processing in the main as the bitset
 *  reresents a number of integer tokens which we use for follow sets
 *  and so on.
 *
 *  The first entry is the number of elements following in the list.
 */
static  pANTLR3_INT32
antlr3BitsetToIntList   (pANTLR3_BITSET bitset)
{
    ANTLR3_UINT32   numInts;        // How many integers we will need
    ANTLR3_UINT32   numBits;        // How many bits are in the set
    ANTLR3_UINT32   i;
    ANTLR3_UINT32   index;

    pANTLR3_INT32  intList;

    numInts = bitset->size(bitset) + 1;
    numBits = bitset->numBits(bitset);

    intList = (pANTLR3_INT32)ANTLR3_MALLOC(numInts * sizeof(ANTLR3_INT32));

    if  (intList == NULL)
    {
                return NULL;    // Out of memory
    }

    intList[0] = numInts;

    // Enumerate the bits that are turned on
    //
    for (i = 0, index = 1; i<numBits; i++)
    {
                if  (bitset->isMember(bitset, i) == ANTLR3_TRUE)
                {
                        intList[index++]    = i;
                }
    }

    // Result set
    //
    return  intList;
}
