// Buffer for packing bits and values -*- c++ -*-

#ifdef __GNUC__
# pragma implementation
#endif // __GNUC__
#include "BitBuffer.h"
#include "StructValue.h"
#include "StructType.h"
#include "UnionValue.h"
#include "UnionType.h"
#include "VectorValue.h"
#include "VectorType.h"
#include "BufferValue.h"
#include "BufferType.h"
#include "LeafValue.h"

/** @file BitBuffer.C
 * Encoding and decoding numbers and values in bit strings
 */

/* Copyright © 1999-2002 Marko Mäkelä (msmakela@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. */

void
BitPacker::append (const class Value& value)
{
  card_t numValues = value.getType ().getNumValues ();
  assert (numValues);
  if (numValues == 1)
    return;
  if (numValues < CARD_T_MAX)
    append (value.getType ().convert (value), log2 (numValues));
  else {
    switch (value.getKind ()) {
    case Value::vStruct:
      {
	const class StructValue& s =
	  static_cast<const class StructValue&>(value);
	for (unsigned i = 0; i < s.getSize (); i++)
	  append (s[i]);
      }
      break;
    case Value::vUnion:
      {
	const class UnionValue& u =
	  static_cast<const class UnionValue&>(value);
	if (unsigned bits = log2 (static_cast<const class UnionType&>
				  (u.getType ()).getSize ()))
	  append (u.getIndex (), bits);
	append (u.getValue ());
      }
      break;
    case Value::vVector:
      {
	const class VectorValue& v =
	  static_cast<const class VectorValue&>(value);
	for (unsigned i = 0; i < v.getSize (); i++)
	  append (v[i]);
      }
      break;
    case Value::vBuffer:
      {
	const class BufferValue& b =
	  static_cast<const class BufferValue&>(value);
	card_t i = b.getCapacity ();
	append (i, log2 (static_cast<const class BufferType&>(b.getType ())
			 .getSize () + 1));
	while (i--)
	  append (*b[i]);
      }
      break;
    case Value::vLeaf:
      append (card_t (static_cast<const class LeafValue&>(value)), CARD_T_BIT);
      break;
    }
  }
}

class Value*
BitUnpacker::extract (const class Type& type)
{
  card_t numValues = type.getNumValues ();
  assert (numValues);
  if (numValues == 1)
    return type.convert (card_t (0));
  if (numValues < CARD_T_MAX)
    return type.convert (extract (log2 (numValues)));
  else {
    switch (type.getKind ()) {
    case Type::tStruct:
      {
	const class StructType& s =
	  static_cast<const class StructType&>(type);
	class StructValue* sv = new class StructValue (type);
	for (unsigned i = 0; i < s.getSize (); i++)
	  (*sv)[i] = extract (s[i]);
	return sv;
      }
    case Type::tUnion:
      {
	const class UnionType& u =
	  static_cast<const class UnionType&>(type);
	card_t i = u.getSize () > 1 ? extract (log2 (u.getSize ())) : 0;
	return new class UnionValue (type, i, *extract (u[i]));
      }
    case Type::tVector:
      {
	const class VectorType& v =
	  static_cast<const class VectorType&>(type);
	class VectorValue* vv = new class VectorValue (type);
	for (unsigned i = 0; i < v.getSize (); i++)
	  (*vv)[i] = extract (v.getItemType ());
	return vv;
      }
    case Type::tBuffer:
      {
	const class BufferType& b =
	  static_cast<const class BufferType&>(type);
	class BufferValue* bv = new class BufferValue (type);
	for (card_t i = extract (log2 (b.getSize () + 1)); i--; )
	  (*bv)[i] = extract (b.getItemType ());
	return bv;
      }
    default:
      return new class LeafValue (type, extract (CARD_T_BIT));
    }
  }
}
