Logo Search packages:      
Sourcecode: lebiniou version File versions  Download package

shuffler.c

/*
 *  Copyright 1994-2011 Olivier Girondel
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou 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.
 *
 *  lebiniou 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 lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

#include "shuffler.h"
#include "brandom.h"


Shuffler_t *
Shuffler_new(const u_short size)
{
  Shuffler_t *s = xcalloc(1, sizeof(Shuffler_t));

  s->size = size;

  if (size) {
    s->used = xcalloc(size, sizeof(char));
    s->disabled = xcalloc(size, sizeof(char));
  }

  s->current = -1;
  s->mode = BS_SHUFFLE;

  return s;
}


void
Shuffler_delete(Shuffler_t *s)
{
  assert(s != NULL);

  if (s->size) {
    xfree(s->used);
    xfree(s->disabled);
  }
  
  xfree(s);
}


void
Shuffler_verbose(Shuffler_t *s)
{
  s->verbose = 1;
}


static void
Shuffler_display(const Shuffler_t *s)
{
  u_short c;
  u_char one = 0;

  assert(s != NULL);
  if (!s->size)
    return;
  
  printf("[S] Shuffler(%d): Available= [", s->size);
  for (c = 0; c < s->size; c++) {
    if (!s->used[c] && !s->disabled[c]) {
      if (one)
      printf(", ");
      printf("%d", c);
      one = 1;
    }
  }
  printf("]\n");

  one = 0;
  printf("[S] Shuffler: Disabled= [");
  for (c = 0; c < s->size; c++) {
    if (s->disabled[c]) {
      if (one)
      printf(", ");
      printf("%d", c);
      one = 1;
    }
  }
  printf("]\n");
}


static u_short
Shuffler_next_available(Shuffler_t *s, long start, u_char want_unused)
{
  assert(start >= 0);
  assert(start <= s->size);
  
  if (start == s->size)
    start = 0;

  while (s->disabled[start] || (want_unused && s->used[start])) {
    if (++start == s->size)
      start = 0;
  }

  s->current = start;
  s->used[start] = 1;

  return start;
}


static u_short
Shuffler_get_shuffle(Shuffler_t *s)
{
  long rnd = b_rand_int_range(0, s->size - 1);
  
  return Shuffler_next_available(s, rnd, 1);
}


static u_short
Shuffler_get_cycle(Shuffler_t *s)
{
  return Shuffler_next_available(s, s->current+1, 1);
}


static u_short
Shuffler_get_random(Shuffler_t *s)
{
  long rnd = b_rand_int_range(0, s->size - 1);
  
  return Shuffler_next_available(s, rnd, 0);
}


static void
Shuffler_clean(Shuffler_t *s)
{
  u_short c;

  assert(s != NULL);
  assert(s->size);

  for (c = 0; (c < s->size) && (s->used[c] || s->disabled[c]); c++);

  if (c == s->size) {
    if (s->verbose)
      printf("[S] Shuffler_clean(%p)\n", s);
    memset((void *)s->used, 0, s->size*sizeof(char));
  }
}


u_short
Shuffler_get(Shuffler_t *s)
{
  u_short new = 0;
  
  if ((NULL == s) || (s->size == 1))
    return 0;
  
  if (!s->size)
    xerror("Attempt to get a value from an empty shuffler\n");

  switch (s->mode) {
  case BS_NONE:
    printf("[!] WARNING tried to get a value from a shuffler in BS_NONE mode\n");
    new = 0;
    break;

  case BS_SHUFFLE:
    new = Shuffler_get_shuffle(s);
    break;

  case BS_CYCLE:
    new = Shuffler_get_cycle(s);
    break;

  case BS_RANDOM:
    new = Shuffler_get_random(s);
    break;

  default:
    xerror("Bad shuffler mode %d\n", s->mode);
    break;
  }

  if (s->verbose) {
    printf("[S] Shuffler_get(%p): %d\n", s, new);
    Shuffler_display(s);
  }
  Shuffler_clean(s);

  return new;
}


void
Shuffler_set_mode(Shuffler_t *s, const enum ShufflerMode mode)
{
  assert(s != NULL);

  s->mode = mode;
}


void
Shuffler_next_mode(Shuffler_t *s)
{
  assert(s != NULL);

  s->mode = (enum ShufflerMode)((s->mode+1) & 2);
  /* TODO human printable shuffler mode (None, Shuffle, ...) */
  printf("[S] Shuffler mode set to: %d\n", (int)s->mode);
}


void
Shuffler_enable(Shuffler_t *s, const u_short i)
{
  assert(s != NULL);
  assert(s->size);
  assert(i < s->size);

  s->disabled[i] = 0;
}


void
Shuffler_disable(Shuffler_t *s, const u_short i)
{
  assert(s != NULL);
  assert(s->size);
  assert(i < s->size);

  s->disabled[i] = 1;
}


void
Shuffler_used(Shuffler_t *s, const u_short i)
{
  assert(s != NULL);
  assert(s->size);
  assert(i < s->size);

  s->used[i] = 1;
  Shuffler_clean(s);
}


void
Shuffler_restart(Shuffler_t *s)
{
  assert(s != NULL);
  assert(s->size);

  memset((void *)s->used, 0, s->size*sizeof(char));
  Shuffler_set_mode(s, BS_SHUFFLE);
  s->current = -1;
}


void
Shuffler_reinit(Shuffler_t *s)
{
  Shuffler_restart(s);
  memset((void *)s->disabled, 0, s->size*sizeof(char));
}


void
Shuffler_grow_one_left(Shuffler_t *s)
{
  /*
   * do a realloc but on the left of the array
   * this one is needed since we preprend sequences
   * to the list
   */

  char *nused = NULL;
  char *ndisabled = NULL;
  u_short new_size;

  assert(s != NULL);
  new_size = s->size + 1;

  nused = xcalloc(new_size, sizeof(char));
  ndisabled = xcalloc(new_size, sizeof(char));

  memcpy((void *)(nused+sizeof(char)), s->used, s->size*sizeof(char));
  memcpy((void *)(ndisabled+sizeof(char)), s->disabled, s->size*sizeof(char));

  s->size = new_size;

  if (s->used != NULL)
    xfree(s->used);
  if (s->disabled != NULL)
    xfree(s->disabled);
  
  s->used = nused;
  s->disabled = ndisabled;
}


u_char
Shuffler_ok(const Shuffler_t *s)
{
  u_short c = 0;

  assert(s != NULL);
  assert(s->size);

  while ((c < s->size) && s->disabled[c])
    c++;

  return (c != s->size);
}

Generated by  Doxygen 1.6.0   Back to index