// List of sets -*- c++ -*-

#ifdef __GNUC__
# pragma implementation
#endif // __GNUC__
#include "SetList.h"
#include "BitVector.h"
#include <string.h>

/** @file SetList.C
 * A collection of sets of numbers
 */

/* Copyright © 2000-2002 Marko Mäkelä (msmakela@tcs.hut.fi).
   Copyright © 2000 Timo Latvala (timo@tcs.hut.fi).

   This file is part of MARIA, a reachability analyzer and model checker
   for high-level Petri nets.

   MARIA is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   MARIA is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   The GNU General Public License is often shipped with GNU software, and
   is generally kept in a file called COPYING or LICENSE.  If you do not
   have a copy of the license, write to the Free Software Foundation,
   59 Temple Place, Suite 330, Boston, MA 02111 USA. */

SetList::SetList (unsigned numSets) :
  myNumSets (numSets), myAllocatedSets (0), mySets (0)
{
  for (myAllocatedSets = 1; myAllocatedSets < numSets; myAllocatedSets <<= 1);
  mySets = new unsigned*[myAllocatedSets];
  memset (mySets, 0, myAllocatedSets * sizeof *mySets);
}

SetList::~SetList ()
{
  for (unsigned i = myNumSets; i--; )
    delete[] mySets[i];
  delete[] mySets;
}

void
SetList::assign (unsigned i, unsigned* array)
{
  assert (i < myNumSets && array && *array);
  if (!mySets[i])
    mySets[i] = array;
  else {
    unsigned* sets = new unsigned[*mySets[i] + *array + 1];
    memcpy (sets, mySets[i], (*mySets[i] + 1) * sizeof *sets);
    memcpy (sets + *sets + 1, array + 1, *array * sizeof *sets);
    *sets += *array;
    delete[] mySets[i];
    delete[] array;
    mySets[i] = sets;
  }
}

void
SetList::assign (unsigned i,
		 const class BitVector& bv,
		 unsigned offset,
		 bool complement)
{
  assert(i < myNumSets);

  if (!bv.getSize())
    return;

  unsigned numTrue = 0, b;
  for (b = bv.getSize(); b--; )
    if(bv[b] != complement) numTrue++;
  if (!numTrue)
    return;
  unsigned* s = new unsigned[numTrue + 1];
  *s = numTrue;

  for (b = bv.getSize();; )
    if(bv[--b] != complement)
      if ((s[numTrue] = b + offset), !--numTrue)
	break;
  assign (i, s);
}

void
SetList::copy (unsigned i, const unsigned* array)
{
  assert (i < myNumSets && array && *array);
  if (!mySets[i]) {
    mySets[i] = new unsigned[*array + 1];
    memcpy (mySets[i], array, (*array + 1) * sizeof *array);
  }
  else {
    unsigned* sets = new unsigned[*mySets[i] + *array + 1];
    memcpy (sets, mySets[i], (*mySets[i] + 1) * sizeof *sets);
    memcpy (sets + *sets + 1, array + 1, *array * sizeof *sets);
    *sets += *array;
    delete[] mySets[i];
    mySets[i] = sets;
  }
}

void
SetList::grow (unsigned numSets)
{
  assert (numSets > myNumSets);
  if (numSets <= myAllocatedSets) {
    memset (mySets + myNumSets, 0, (numSets - myNumSets) * sizeof *mySets);
    myNumSets = numSets;
    return;
  }
  for (; myAllocatedSets < numSets; myAllocatedSets <<= 1);
  unsigned** sets = new unsigned*[myAllocatedSets];
  memcpy (sets, mySets, myNumSets * sizeof *sets);
  memset (sets + myNumSets, 0, (numSets - myNumSets) * sizeof *sets);
  delete[] mySets;
  mySets = sets;
  myNumSets = numSets;
}

void
SetList::shrink (unsigned numSets)
{
  assert (numSets <= myNumSets);
  while (myNumSets > numSets)
    delete[] mySets[--myNumSets];
}
