/**
 * \file AllocateurMemoire.cpp
 * Classe de gestion d'un allocateur de bancs memoire.
 * 
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "AllocateurMemoire.h"

#define UNREFERENCED_PARAMETER(P) (P)

/**
 * Constructeur pour un objet AllocateurMemoire.
 *
 * @param size La taille d'allocation pour les bancs memoire.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
AllocateurMemoire::AllocateurMemoire(int size) {
  this->size = size;
  nb = 0;
  sp = -1;
  spt = -1;
  lsp = -1;
  lspt = -1;
  t = NULL;
  tm = NULL;
  bck = 0;
}

/**
 * Destructeur pour un objet AllocateurMemoire.
 *
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
AllocateurMemoire::~AllocateurMemoire(void) {
  liberation();
}

/**
 * Allocation d'un banc memoire.
 *
 * @param taille La taille du banc memoire a allouer.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
void *AllocateurMemoire::myalloc(int taille) {
  void *p;
  if ( !t ) {
    lsp = -1;
    lspt = -1;
    spt = 0;
    t =(char **) calloc((spt+1),sizeof(void *));
    t[spt] =(char *) calloc(( taille > size ) ? taille : size,sizeof(char));
    p = t[spt];
    nb++; 
    sp = taille;
    tm =(size_t *) calloc((spt+1),sizeof(size_t));
    tm[spt] = sp;
   // printf("%10d [%d %d] [%d %d]\n",taille,spt,sp,lspt,lsp);
    bck = 1; }
    else {
    if ( sp+taille < size ) {
      lsp = sp;
      lspt = spt;
      //t[spt] =(char *) realloc(t[spt],sp+taille);
      p = &t[spt][sp];
      nb++;
      sp += taille;
      tm[spt] = sp;
   //   printf("%10d [%d %d] [%d %d]\n",taille,spt,sp,lspt,lsp);
      bck = 1; }
      else {
//    printf("???????????? %p\n",this);
      lsp = sp;
      lspt = spt;
      spt++;
   //   printf("%p %p %d\n",t,t[0],spt);
      t =(char **) realloc(t,(spt+1)*sizeof(char *));
   //   printf("%p %p %d\n",t,t[0],(spt+1)*sizeof(char *));
      t[spt] =(char *) calloc(( taille > size ) ? taille : size,sizeof(char));
      p = t[spt];
      nb++; 
      sp = taille;
      tm =(size_t *) realloc(tm,(spt+1)*sizeof(size_t));
      tm[spt] = sp;
   //   printf("%10d [%d %d] [%d %d]\n",taille,spt,sp,lspt,lsp);
      bck = 1; } }
  return(p);
}

/**
 * Allocation d'un banc memoire.
 *
 * @param nbe Le nombre d'elements a allouer.
 * @param taille La taille de chaque element a allouer.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
void *AllocateurMemoire::cyalloc(int nbe,int taille) {
  taille *= nbe;
  char *p =(char *) myalloc(taille);
  memset(p,0,taille);
  return(p);
}

/**
 * Desallocation du dernier banc memoire alloue.
 *
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
int AllocateurMemoire::stepBack(void) {
  if ( !bck )
    return(0);
  if ( ( lspt == -1 ) && ( lsp == -1 ) ) {
    nb = 0;
    liberation();
    sp = lsp;
    spt = lspt;
    lsp = -1;
    lspt = -1;
//    printf("Back       [%d %d] [%d %d]\n",spt,sp,lspt,lsp);
    bck = 0; }
    else {
    if ( lspt == spt ) {
//      t[spt] =(char *) realloc(t[spt],lsp);
      tm[spt] = lsp;
      sp = lsp;
      spt = lspt;
      nb--;
//      printf("Back       [%d %d] [%d %d]\n",spt,sp,lspt,lsp);
      bck = 0; }
      else {
      free(t[spt]);
      t =(char **) realloc(t,spt*sizeof(char *));
      tm =(size_t *) realloc(tm,spt*sizeof(size_t));
      sp = lsp;
      spt = lspt;
      nb--;
//      printf("Back       [%d %d] [%d %d]\n",spt,sp,lspt,lsp);
      bck = 0; } }
  return(1);
}

/**
 * Retour du nombre de bancs memoire alloues.
 *
 * @return Le nombre de bancs memoire alloues.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
int AllocateurMemoire::getNombreAllocations(void) {
  return(nb);
}

/**
 * Retour de la quantite de memoire occupee par this.
 *
 * @return La quantite de memoire occupee par this.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
size_t AllocateurMemoire::getUsedMemory(void) {
  size_t mem = 0;
  for ( int i = 0 ; i <= spt ; i++ )
    mem += tm[i];
  mem += (spt+1)*sizeof(size_t);
  mem += (spt+1)*sizeof(void *);
  mem += sizeof(AllocateurMemoire);
  return(mem);
}

/**
 * Retour du nombre de handle memoire occupes par this.
 *
 * @return Le nombre de handle memoire occupes par this.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
long AllocateurMemoire::getUsedHandles(void) {
  return(4+spt);
}

void AllocateurMemoire::liberation(void) {
  if ( t ) {
    for ( int i = 0 ; i <= spt ; i++ )
      free(t[i]);
    free(t);
    t = NULL; }
  if ( tm ) {
    free(tm);
    tm = NULL; }
}
