// Generic utility functions -*- c++ -*-

#ifdef __GNUC__
# pragma implementation
#endif // __GNUC__
#include "util.h"

#include <string.h>
#include <assert.h>

/** @file util.C
 * Generic utility functions
 */

/* 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. */

bool
ltstr::operator() (const char* s1, const char* s2) const
{
  return strcmp (s1, s2) < 0;
}

char*
newString (const char* s)
{
  size_t len = strlen (s) + 1;
  return static_cast<char*>(memcpy (new char[len], s, len));
}

unsigned
log16 (card_t num)
{
  assert (num > 0);
#if CARD_T_MAX == 4294967295U
  if (num <= 1) return 0;
  if (num <= 0x10) return 1;
  if (num <= 0x100) return 2;
  if (num <= 0x1000) return 3;
  if (num <= 0x10000) return 4;
  if (num <= 0x100000) return 5;
  if (num <= 0x1000000) return 6;
  if (num <= 0x10000000) return 7;
  return 8;
#else
  assert (!(CARD_T_BIT % 4));
  unsigned low = 0, high = CARD_T_BIT / 4;

  for (;;) {
    unsigned log = (low + high) >> 1;
    card_t exp = card_t (1) << (4 * log);
    if (exp < num) {
      assert (high >= log);
      if (low == high) {
	assert (log == low);
	assert (log == CARD_T_BIT / 4);
	return log;
      }
      low = log + 1;
    }
    else if ((exp >> 4) >= num) {
      assert (low < log);
      high = log - 1;
    }
    else
      return log;
  }
#endif
}

unsigned
log8 (card_t num)
{
  assert (num > 0);
#if CARD_T_MAX == 4294967295U
  if (num <= 1) return 0;
  if (num <= 8) return 1;
  if (num <= 0x40) return 2;
  if (num <= 0x200) return 3;
  if (num <= 0x1000) return 4;
  if (num <= 0x8000) return 5;
  if (num <= 0x40000) return 6;
  if (num <= 0x200000) return 7;
  if (num <= 0x1000000) return 8;
  if (num <= 0x8000000) return 9;
  if (num <= 0x40000000) return 10;
  return 11;
#else
  assert (!(CARD_T_BIT % 4));
  unsigned low = 0, high = CARD_T_BIT / 3;

  if (num > (card_t (1) << (3 * high)))
    return high + 1;

  for (;;) {
    unsigned log = (low + high) >> 1;
    card_t exp = card_t (1) << (3 * log);
    if (exp < num) {
      assert (high >= log);
      if (low == high) {
	assert (log == low);
	assert (log == CARD_T_BIT / 3);
	return log;
      }
      low = log + 1;
    }
    else if ((exp >> 3) >= num) {
      assert (low < log);
      high = log - 1;
    }
    else
      return log;
  }
#endif
}

unsigned
log2 (card_t num)
{
  assert (num > 0);
#if CARD_T_MAX == 4294967295U
  if (num <= 0x2) return num - 1;
  if (num <= 0x4) return 2;
  if (num <= 0x8) return 3;
  if (num <= 0x10) return 4;
  if (num <= 0x20) return 5;
  if (num <= 0x40) return 6;
  if (num <= 0x80) return 7;
  if (num <= 0x100) return 8;
  if (num <= 0x200) return 9;
  if (num <= 0x400) return 10;
  if (num <= 0x800) return 11;
  if (num <= 0x1000) return 12;
  if (num <= 0x2000) return 13;
  if (num <= 0x4000) return 14;
  if (num <= 0x8000) return 15;
  if (num <= 0x10000) return 16;
  if (num <= 0x20000) return 17;
  if (num <= 0x40000) return 18;
  if (num <= 0x80000) return 19;
  if (num <= 0x100000) return 20;
  if (num <= 0x200000) return 21;
  if (num <= 0x400000) return 22;
  if (num <= 0x800000) return 23;
  if (num <= 0x1000000) return 24;
  if (num <= 0x2000000) return 25;
  if (num <= 0x4000000) return 26;
  if (num <= 0x8000000) return 27;
  if (num <= 0x10000000) return 28;
  if (num <= 0x20000000) return 29;
  if (num <= 0x40000000) return 30;
  if (num <= 0x80000000) return 31;
  return 32;
#else
  unsigned low = 0, high = CARD_T_BIT;

  for (;;) {
    unsigned log = (low + high) >> 1;
    card_t exp = card_t (1) << log;
    if (exp < num) {
      assert (high >= log);
      if (low == high) {
	assert (log == low);
	assert (log == CARD_T_BIT);
	return log;
      }
      low = log + 1;
    }
    else if ((exp >> 1) >= num) {
      assert (low < log);
      high = log - 1;
    }
    else
      return log;
  }
#endif
}
