// $Id$
// Map template

// Copyright (C) 1995 Technische Universitaet Braunschweig, Germany.
// Written by Dorothea Luetkehaus <luetke@ips.cs.tu-bs.de>.
// 
// This file is part of DDD.
// 
// DDD 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 3 of the License, or (at your option) any later version.
// 
// DDD 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 DDD -- see the file COPYING.
// If not, see <http://www.gnu.org/licenses/>.
// 
// DDD is the data display debugger.
// For details, see the DDD World-Wide-Web page, 
// `http://www.gnu.org/software/ddd/',
// or send a mail to the DDD developers <ddd@gnu.org>.

//-----------------------------------------------------------------------------
// A Map Template
// The Key should not be 0, since this value has special meaning for
// first() and next().  Also, '==' must be defined for Key.
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
#ifndef _DDD_Map_h
#define _DDD_Map_h

#include "bool.h"
#include "assert.h"

typedef void *MapRef;

template <class Key, class Contents>
class Map {
    // Internal list node
    struct MapNode {
	Key key;
	Contents *cont;
	MapNode *_next;
    };

private:
    MapNode *_first;
    int _length;

    // Search K; return 0 if not found
    MapNode *search(Key k) const
    {
	MapNode *ln;
	
	ln = _first;
	while (ln != 0 && !(ln->key == k)) 
	    ln = ln->_next;
	return ln;
    }

public:
    // Create empty map
    Map()
	: _first(0), _length(0) 
    {}

    // Remove all elements
    void clear()
    {
	MapNode *ln;
	MapNode *prev;

	ln = _first;
	while (ln != 0) {
	    prev = ln;
	    ln = ln->_next;
	    delete prev;
	}
	_first = 0;
	_length = 0;
    }

    // Remove all elements, delete'ing each content
    void delete_all_contents()
    {
	MapNode *ln   = _first;
	MapNode *prev = 0;
	while (ln != 0)
	{
	    prev = ln;
	    ln = ln->_next;
	    delete prev->cont;
	    delete prev;
	}
	_first = 0;
	_length = 0;
    }

    
    // Destructor
    ~Map()
    {
	clear();
    }
    
    // Insert or overwrite
    int insert(Key k, Contents* c)
    {
	if (c == 0) // Don't add empty stuff
	    return 0;

	MapNode *ln = search(k);
	if (ln == 0)
	{
	    // Insert
	    ln = new MapNode;
	    ln->key = k;
	    ln->cont = c;

	    ln->_next = _first;
	    _first = ln;
	    _length++;
	}
	else
	{
	    // Overwrite
	    ln->cont = c;
	}
	return 1;
    }
    
    // Delete K if found
    void del(Key k)
    {
	if (_first == 0)
	    return;
    
	MapNode *prev = 0;
	MapNode *ln = _first;
    
	while (ln != 0 && !(ln->key == k))
	{
	    prev = ln;
	    ln = ln->_next;
	}

	if (ln == 0)
	    return; // not found
		       
	if (prev == 0)
	{
	    // delete first element
	    assert(_first == ln);
	    _first = _first->_next;
	    delete ln;
	    _length--;
	}
	else
	{
	    prev->_next = ln->_next;
	    delete ln;
	    _length--;
	}
	assert(!contains(k));
    }

    // Get contents of K; return 0 if not found
    Contents *get(Key k) const
    {
	MapNode *ln = search(k);
	if (ln == 0)
	    return 0;
	else 
	    return ln->cont;
    }
    
    // true if K is contained
    bool contains(Key k) const
    {
	return search (k) != 0;
    }
    
    // Return first key, or 0 if not found.
    // This simulates a 0-terminated list.
    Key first_key(MapRef& ref) const
    {
	if (_first == 0)
	{
	    ref = 0;
	    return 0;
	}
	else
	{
	    ref = _first->_next;
	    return _first->key;
	}
    }

    static Key next_key(MapRef& ref)
    {
	if (ref == 0)
	{
	    // at the end
	    return 0;
	}
	else
	{
	    MapNode *current_ln = (MapNode *) ref;
	    ref = current_ln->_next;
	    return current_ln->key;
	}
    }

    // Return first contents, or 0 if not found
    Contents *first(MapRef& ref) const
    {
	if (_first == 0)
	{
	    ref = 0;
	    return 0;
	}
	else
	{
	    ref = _first->_next;
	    return _first->cont;
	}
    }

    static Contents *next(MapRef& ref)
    {
	if (ref == 0)
	{
	    // at the end
	    return 0;
	}
	else
	{
	    MapNode *current_ln = (MapNode *) ref;
	    ref = current_ln->_next;
	    return current_ln->cont;
	}
    }

    inline int length()  const { return _length; }

private:
    // No copy constructor
    Map(const Map<Key, Contents>&);

    // No assignment
    Map<Key, Contents>& operator = (const Map<Key, Contents>&);
};

#endif // _DDD_Map_h
// DON'T ADD ANYTHING BEHIND THIS #endif
