/* This is -*- C -*- */
/* vim: set sw=2: */
/* $Id: guppi-hash.c,v 1.5 2002/01/14 05:01:23 trow Exp $ */

/*
 * guppi-hash.c
 *
 * Copyright (C) 2001 The Free Software Foundation, Inc.
 *
 * Developed by Jon Trowbridge <trow@gnu.org>
 */

/*
 * This program 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 of the
 * License, or (at your option) any later version.
 * 
 * This program 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.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA.
 */

#include <config.h>
#include "guppi-hash.h"

#include <string.h>
#include <guppi-memory.h>

struct _GuppiHash {
  guint32 x;
  guint32 y;
};

GuppiHash *
guppi_hash_new (void)
{
  GuppiHash *hash = guppi_new (GuppiHash, 1);
  guppi_hash_reset (hash);
  return hash;
}

GuppiHash *
guppi_hash_copy (GuppiHash *hash)
{
  if (hash == NULL) {
    return NULL;
  } else {
    GuppiHash *new_hash = g_new (GuppiHash, 1);
    new_hash->x = hash->x;
    new_hash->y = hash->y;
    return new_hash;
  }
}

void
guppi_hash_free (GuppiHash *hash)
{
  if (hash) {
    guppi_free (hash);
  }
}

/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */

void
guppi_hash_reset (GuppiHash *hash)
{
  g_return_if_fail (hash != NULL);
  hash->x = 0x27182818;
  hash->y = 0x31415926;
}

void
guppi_hash_raw (GuppiHash *hash, gconstpointer ptr, gsize N)
{
  const guchar *p = ptr;
  gsize N4 = N>>2, N1 = N & 3;
  guint32 xx, yy, q;
  gint i;
  
  g_return_if_fail (hash != NULL);

  for (i = 0; i < N4; ++i) {
    xx = hash->x;
    yy = hash->y;

    q = *(guint32 *)p;
    p += 4;

    hash->x = (xx ^ q) + yy * q;
    hash->y = (yy ^ q) - xx * q;
  }

  for (i = 0; i < N1; ++i) {
    xx = hash->x;
    yy = hash->y;

    q = (guint) *p;
    ++p;
    
    hash->x = 17 * xx + 19 * yy + (guint) q;
    hash->y = 23 * xx + 29 * yy + (guint) q;
  }
}

void
guppi_hash_string (GuppiHash *hash, const gchar *str)
{
  g_return_if_fail (hash != NULL);
  guppi_hash_raw (hash, str, strlen (str));
}

void
guppi_hash_double (GuppiHash *hash, double x)
{
  g_return_if_fail (hash != NULL);
  guppi_hash_raw (hash, &x, sizeof (double));
}

void
guppi_hash_int (GuppiHash *hash, gint x)
{
  g_return_if_fail (hash != NULL);
  guppi_hash_raw (hash, &x, sizeof (gint));
}

void
guppi_hash_uint (GuppiHash *hash, guint x)
{
  g_return_if_fail (hash != NULL);
  guppi_hash_raw (hash, &x, sizeof (guint));
}

void
guppi_hash_boolean (GuppiHash *hash, gboolean x)
{
    if (x) {

      gboolean hi_x = hash->x & (1<<31);
      gboolean hi_y = hash->y & (1<<31);
      hash->x = hash->x << 1;
      hash->y = hash->y << 1;
      if (hi_x)
	hash->x = hash->x | 1;
      if (hi_y)
	hash->y = hash->y | 1;

    } else {

      gboolean lo_x = hash->x & 1;
      gboolean lo_y = hash->y & 1;
      hash->x = hash->x >> 1;
      hash->y = hash->y >> 1;
      if (lo_x)
	hash->x = hash->x | (1<<31);
      if (lo_y)
	hash->y = hash->y | (1<<31);

    }
}

/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */

gint
guppi_hash_cmp (GuppiHash *a, GuppiHash *b)
{
  g_return_val_if_fail (a != NULL, 0);
  g_return_val_if_fail (b != NULL, 0);

  if (a->x == b->x) {
    return (a->y > b->y) - (a->y < b->y);
  } else {
    return (a->x > b->x) - (a->x < b->x);
  }
}

gboolean
guppi_hash_eq (GuppiHash *a, GuppiHash *b)
{
  g_return_val_if_fail (a != NULL, FALSE);
  g_return_val_if_fail (b != NULL, FALSE);

  return a->x == b->x && a->y == b->y;
}

gboolean
guppi_hash_neq (GuppiHash *a, GuppiHash *b)
{
  g_return_val_if_fail (a != NULL, FALSE);
  g_return_val_if_fail (b != NULL, FALSE);

  return a->x != b->x || a->y != b->y;
}

guint
guppi_hash_to_uint (GuppiHash *hash)
{
  g_return_val_if_fail (hash != NULL, 0);

  return hash->x ^ hash->y;
}


syntax highlighted by Code2HTML, v. 0.9.1