/* -*- mode: c++; c-basic-offset: 4; -*-
 *
 * MICO --- a CORBA implementation
 * Copyright (C) 1997-98 Kay Roemer & Arno Puder
 *
 * simple and fast array object and template
 * Copyright (C) 1999 Andreas Schultz                                 
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Send comments and/or bug reports to:
 *                mico@informatik.uni-frankfurt.de
 *
 * $Id: fast_array.cc,v 1.9 1999/12/14 00:47:20 aschultz Exp $
 *
 */

#define MICO_DEBUG_MODULE MICODebug::Support

#define MICO_CONF_IMR

#include <CORBA-SMALL.h>
#include <mico/impl.h>

// this is a dynamic array with O(1) insertion and O(1) deletion time
// resizing is done only on request
// dynamicily grows, but doesn't shrink
// iterating it no possible
// no error checking for the moment - that means you can overflow the array

MICO::__void_array::__void_array( unsigned int max, unsigned int grow ) {
    _free = _max = max;
    _grow = grow;
    _head = __EMPTY;
    _first_free = _last = 0;
    objs = static_cast<struct item_s*>(malloc( sizeof(struct item_s) * _max ));
}
    
MICO::__void_array::~__void_array() {
    free( objs );
}

unsigned int MICO::__void_array::__fast_insert( void *new_obj ) {
    unsigned int ret;

    MAP_TRACE ( MICODebug::instance()->printer() << "void_array::__fast_insert (" << new_obj << "): " );
    ret = _first_free;

    if (!_free) {
	_max  += _grow;
	_free += _grow;
	assert( objs = static_cast<struct item_s*>(realloc( objs, sizeof(struct item_s) * _max )) );
    }
    _free--;
    if ( _first_free != _last ) {
	_first_free = objs[_first_free].next;
    } else {
	_first_free++;
	_last++;
    }

    // add it to the item ring
    objs[ret].obj = new_obj;
    if (_head == __EMPTY) {
	_head = ret;
	objs[ret].next = objs[ret].prev = ret;
    } else {
	objs[ret].next = _head;
	objs[ret].prev = objs[_head].prev;
	objs[objs[_head].prev].next = ret;
	objs[_head].prev = ret;
    }

    MAP_TRACE( MICODebug::instance()->printer()
      << "   return " << ret << endl );
    return ret;
}


void MICO::__void_array::remove ( unsigned int n ) {
    
    MAP_TRACE( MICODebug::instance()->printer() << "void_array::remove (" << n << ")" << endl );
    _free++;
    // remove it from the item ring
    if ( n == objs[n].prev ) {             // only one object left
	_head = __EMPTY;
    } else {
	objs[objs[n].prev].next = objs[n].next;
	objs[objs[n].next].prev = objs[n].prev;
    }
    if ( n == _head )
	_head = objs[n].next;
    if (n == _last) {
	if (_last == _first_free) _first_free--;
	_last--;
    } else {
	objs[n].next = _first_free;
	_first_free = n;
    }
#ifdef __M_DEBUG
    objs[n].obj = NULL;
    objs[n].prev = 0;
#endif
}

#ifdef __M_DEBUG
void MICO::__void_array::print_stats() {
    __MTSAVE ( {  MICODebug::instance()->printer() << "_max   = " << _max << endl;
		  MICODebug::instance()->printer() << "_first_free = " << _first_free << endl;
		  MICODebug::instance()->printer() << "_last  = " << _last << endl;
		  MICODebug::instance()->printer() << "_head  = " << _head << endl;
		  MICODebug::instance()->printer() << "_free  = " << _free << endl;
    } );
}

void MICO::__void_array::print_data() {
    unsigned int n;
    
    for (n = 0; n < _last; n++) {
	__MTSAVE( MICODebug::instance()->printer() << n << ": " << objs[n].obj
		       << ", next: " << objs[n].next 
		       << ", prev: " << objs[n].prev << endl );
    }
}

void MICO::__void_array::print_holes() {
    unsigned int n;
    
    if (_first_free == _last) {
	__MTSAVE( MICODebug::instance()->printer() << "no holes" << endl );
    } else {
	for (n = _first_free;  n != _last; n = objs[n].next) {
	    __MTSAVE( MICODebug::instance()->printer() << n << ": " << objs[n].next << endl );
	}
    }
}

#endif // __M_DEBUG
