/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2003, 2004, 2005  Gabor Csardi <csardi@rmki.kfki.hu>
   MTA RMKI, Konkoly-Thege Miklos st. 29-33, Budapest 1121, Hungary
   
   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., 51 Franklin Street, Fifth Floor, Boston, MA 
   02110-1301 USA

*/

#include "types.h"
#include "memory.h"
#include "random.h"
#include "error.h"

#include <assert.h>
#include <string.h> 		/* memcpy & co. */
#include <stdlib.h>

/**
 * \ingroup stack
 * \brief Initializes a stack (constructor).
 *
 * @return Error code:
 *         - <b>IGRAPH_ENOMEM</b>: out of memory
 */

int igraph_stack_init       (igraph_stack_t* s, long int size) {
        long int alloc_size= size > 0 ? size : 1;
	assert (s != NULL);
	if (size < 0) { size=0; }
	s->stor_begin=Calloc(alloc_size, igraph_real_t);
	if (s->stor_begin==0) {
	  IGRAPH_ERROR("stack init failed", IGRAPH_ENOMEM);
	}
	s->stor_end=s->stor_begin + alloc_size;
	s->end=s->stor_begin;
	
	return 0;
}

/**
 * \ingroup stack
 * \brief Destroys a stack object.
 */

void igraph_stack_destroy    (igraph_stack_t* s) {
  assert( s != NULL);
  if (s->stor_begin != 0) {
    Free(s->stor_begin);
    s->stor_begin=NULL;
  }
}

/**
 * \ingroup stack
 * \brief Reserves memory for a stack object.
 *
 * @return Error code:
 *         - <b>IGRAPH_ENOMEM</b>: out of memory
 */

int igraph_stack_reserve    (igraph_stack_t* s, long int size) {
  long int actual_size=igraph_stack_size(s);
  igraph_real_t *tmp;
  assert(s != NULL);
  assert(s->stor_begin != NULL);
  
  if (size <= igraph_stack_size(s)) { return 0; }
  
  tmp=Realloc(s->stor_begin, size, igraph_real_t);
  if (tmp==0) {
    IGRAPH_ERROR("stack reserve failed", IGRAPH_ENOMEM);
  }
  s->stor_begin=tmp; 
  s->stor_end=s->stor_begin + size;
  s->end=s->stor_begin+actual_size;
  
  return 0;
}

/**
 * \ingroup stack
 * \brief Decides whether a stack object is empty.
 */

igraph_bool_t igraph_stack_empty      (igraph_stack_t* s) {
	assert (s != NULL);
	assert (s->stor_begin != NULL);
	assert (s->end != NULL);
	return s->stor_begin == s->end;
}

/**
 * \ingroup stack
 * \brief Returns the number of elements in a stack.
 */

long int igraph_stack_size       (igraph_stack_t* s) {
	assert (s != NULL);
	assert (s->stor_begin != NULL);
	return s->end - s->stor_begin;
}

/**
 * \ingroup stack
 * \brief Removes all elements from a stack.
 */

void igraph_stack_clear      (igraph_stack_t* s) {
	assert (s != NULL);
	assert (s->stor_begin != NULL);
	s->end = s->stor_begin;
}

/**
 * \ingroup stack
 * \brief Places an element on the top of a stack.
 *
 * @return Error code:
 *         - <b>IGRAPH_ENOMEM</b>: out of memory
 */

int igraph_stack_push       (igraph_stack_t* s, igraph_real_t elem) {
	assert (s != NULL);
	assert (s->stor_begin != NULL);
	if (s->end == s->stor_end) {
		/* full, allocate more storage */
		
	        igraph_real_t *bigger=NULL, *old=s->stor_begin;
		
		bigger = Calloc(2*igraph_stack_size(s)+1, igraph_real_t);
		if (bigger==0) {
		  IGRAPH_ERROR("stack push failed", IGRAPH_ENOMEM);
		}
		memcpy(bigger, s->stor_begin, 
		       igraph_stack_size(s)*sizeof(igraph_real_t));

		s->end        = bigger + (s->stor_end - s->stor_begin);
		s->stor_end   = bigger + 2*(s->stor_end - s->stor_begin)+1;
		s->stor_begin = bigger;
		
		*(s->end) = elem;
		(s->end) += 1;

		Free(old);
	} else {
		*(s->end) = elem;
		(s->end) += 1;
	}
	return 0;
}

/**
 * \ingroup stack
 * \brief Removes and returns an element from the top of a stack.
 */

igraph_real_t igraph_stack_pop        (igraph_stack_t* s) {

	assert (s != NULL);
	assert (s->stor_begin != NULL);
	assert (s->end != NULL);
	assert (s->end != s->stor_begin);
		
	(s->end)--;
	
	return *(s->end);
}

/**
 * \ingroup stack
 * \brief Returns an element from the top of a stack.
 */

igraph_real_t igraph_stack_top        (const igraph_stack_t* s) {

	assert (s != NULL);
	assert (s->stor_begin != NULL);
	assert (s->end != NULL);
	assert (s->end != s->stor_begin);

	return *(s->end-1);
}


syntax highlighted by Code2HTML, v. 0.9.1