mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-08 02:42:34 +00:00
1c69696a9a
Test built for Symbian and run on P910i without any major problems. Test built for MSVC6. Changed parts seems to compile ok but there are some problems with MSVC6 and some of the targets which the EPOC build does n't support (KYRA,SAGA). svn-id: r18430
288 lines
6.8 KiB
C++
288 lines
6.8 KiB
C++
/* ScummVM - Scumm Interpreter
|
|
* Copyright (C) 2002-2005 The ScummVM project
|
|
*
|
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* $Header$
|
|
*/
|
|
|
|
#ifndef COMMON_MAP_H
|
|
#define COMMON_MAP_H
|
|
|
|
#include "common/scummsys.h"
|
|
|
|
namespace Common {
|
|
|
|
/**
|
|
* Default comparison functor: compares to objects using their </==/> operators.
|
|
* Comparison functors ('comparators') are used by the Map template to
|
|
* compare keys. A non-standard comparator might e.g. be implemented to
|
|
* compare strings, ignoring the case.
|
|
*/
|
|
template <class T>
|
|
struct DefaultComparator {
|
|
int operator()(const T& x, const T& y) const { return (x < y) ? -1 : (y < x) ? +1 : 0; }
|
|
};
|
|
|
|
|
|
/**
|
|
* Template based map (aka dictionary) class which uniquely maps elements of
|
|
* class Key to elements of class Value.
|
|
*
|
|
* @todo This implementation is fairly limited. In particular, the tree is not
|
|
* balanced. Ultimately this template should be reimplemented, e.g. using
|
|
* a red-black tree. Or if one day using Std C++ lib becomes acceptable,
|
|
* we can use that.
|
|
* @todo Having unit tests for this class would be very desirable. There are a
|
|
* big number of things which can go wrong in this code.
|
|
*/
|
|
template <class Key, class Value, class Comparator = DefaultComparator<Key> >
|
|
class Map {
|
|
protected:
|
|
struct Node {
|
|
Node *_parent;
|
|
Node *_left, *_right;
|
|
Key _key;
|
|
Value _value;
|
|
Node() : _parent(0), _left(0), _right(0) {}
|
|
Node(const Key &key, Node *parent) : _parent(parent), _left(0), _right(0), _key(key) {}
|
|
};
|
|
|
|
Node *_root;
|
|
Node *_header;
|
|
|
|
private:
|
|
Map<Key, Value, Comparator>(const Map<Key, Value, Comparator> &map);
|
|
Map<Key, Value, Comparator> &operator =(const Map<Key, Value, Comparator> &map);
|
|
|
|
public:
|
|
class const_iterator {
|
|
friend class Map<Key, Value, Comparator>;
|
|
protected:
|
|
Node *_node;
|
|
const_iterator(Node *node) : _node(node) {}
|
|
|
|
public:
|
|
const_iterator() : _node(0) {}
|
|
|
|
Node &operator *() { assert(_node != 0); return *_node; }
|
|
const Node &operator *() const { assert(_node != 0); return *_node; }
|
|
const Node *operator->() const { assert(_node != 0); return _node; }
|
|
bool operator !=(const const_iterator &iter) const { return _node != iter._node; }
|
|
void operator ++() {
|
|
if (!_node)
|
|
return;
|
|
if (_node->_right) {
|
|
_node = _node->_right;
|
|
while (_node->_left)
|
|
_node = _node->_left;
|
|
} else {
|
|
Node *parent = _node->_parent;
|
|
while (_node == parent->_right) {
|
|
_node = parent;
|
|
parent = _node->_parent;
|
|
}
|
|
|
|
if (_node->_right != parent)
|
|
_node = parent;
|
|
}
|
|
|
|
if (_node->_parent == 0)
|
|
_node = 0;
|
|
}
|
|
};
|
|
|
|
public:
|
|
Map<Key, Value, Comparator>() : _root(0) {
|
|
_header = new Node();
|
|
_header->_right = _header->_left = _header;
|
|
}
|
|
|
|
#ifndef __SYMBIAN32__
|
|
virtual ~Map<Key, Value, Comparator>()
|
|
#else
|
|
~Map()
|
|
#endif
|
|
{
|
|
clearNodes(_root);
|
|
delete _header;
|
|
_root = _header = 0;
|
|
}
|
|
|
|
/*
|
|
* Return the object for the given key. If no match is found, a new entry
|
|
* with the given key and the default data value is inserted.
|
|
*/
|
|
Value &operator [](const Key &key) {
|
|
Node *node;
|
|
if (!_root)
|
|
node = _root = new Node(key, _header);
|
|
else
|
|
node = findOrCreateNode(_root, key);
|
|
return node->_value;
|
|
}
|
|
|
|
const Value &operator [](const Key &key) const {
|
|
Node *node = findNode(_root, key);
|
|
assert(node != 0);
|
|
return node->_value;
|
|
}
|
|
|
|
bool contains(const Key &key) const {
|
|
return (findNode(_root, key) != 0);
|
|
}
|
|
|
|
void clear() {
|
|
clearNodes(_root);
|
|
_root = 0;
|
|
}
|
|
|
|
bool isEmpty() const {
|
|
return (_root == 0);
|
|
}
|
|
|
|
Value &addKey(const Key &key) {
|
|
Node *node;
|
|
if (!_root)
|
|
node = _root = new Node(key, _header);
|
|
else
|
|
node = findOrCreateNode(_root, key);
|
|
return node->_value;
|
|
}
|
|
|
|
void remove(const Key &key) {
|
|
// TODO - implement efficiently. Indeed, maybe switch to using red-black trees?
|
|
// For now, just a lame, bad remove algorithm. Rule: don't remove elements
|
|
// from one of our maps if you need to be efficient :-)
|
|
Node *node = findNode(_root, key);
|
|
if (!node)
|
|
return;
|
|
|
|
// Now we have to remove 'node'. There are two simple cases and one hard.
|
|
Node *parent = node->_parent;
|
|
Node *rep;
|
|
if (!node->_left) {
|
|
rep = node->_right;
|
|
} else if (!node->_right) {
|
|
rep = node->_left;
|
|
} else {
|
|
// We have to do it the hard way since both children are present.
|
|
Node *n2;
|
|
|
|
n2 = rep = node->_right;
|
|
|
|
// Now insert the left child leftmost into our right child
|
|
while (n2->_left)
|
|
n2 = n2->_left;
|
|
n2->_left = node->_left;
|
|
n2->_left->_parent = n2;
|
|
}
|
|
|
|
// Replace this node with node 'rep'
|
|
if (rep)
|
|
rep->_parent = parent;
|
|
if (parent == _header) // Root node?
|
|
_root = rep;
|
|
else if (parent->_left == node)
|
|
parent->_left = rep;
|
|
else
|
|
parent->_right = rep;
|
|
|
|
// Finally free the allocated memory
|
|
delete node;
|
|
}
|
|
|
|
void merge(const Map<Key, Value, Comparator> &map) {
|
|
merge(map._root);
|
|
}
|
|
|
|
const_iterator begin() const {
|
|
Node *node = _root;
|
|
if (node) {
|
|
while (node->_left)
|
|
node = node->_left;
|
|
}
|
|
return const_iterator(node);
|
|
}
|
|
|
|
const_iterator end() const {
|
|
return const_iterator();
|
|
}
|
|
|
|
protected:
|
|
/** Merge the content of the given tree into this tree. */
|
|
void merge(const Node *node) {
|
|
if (!node)
|
|
return;
|
|
(*this)[node->_key] = node->_value;
|
|
merge(node->_left);
|
|
merge(node->_right);
|
|
}
|
|
|
|
/** Find and return the node matching the given key, if any. */
|
|
Node *findNode(Node *node, const Key &key) const {
|
|
Comparator cmp;
|
|
while (node) {
|
|
int val = cmp(key,node->_key);
|
|
if (val == 0)
|
|
return node;
|
|
else if (val < 0)
|
|
node = node->_left;
|
|
else
|
|
node = node->_right;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Node *findOrCreateNode(Node *node, const Key &key) {
|
|
Comparator cmp;
|
|
Node *prevNode = 0;
|
|
bool left = true;
|
|
while (node) {
|
|
int val = cmp(key, node->_key);
|
|
prevNode = node;
|
|
if (val == 0) {
|
|
return node;
|
|
} else if (val < 0) {
|
|
left = true;
|
|
node = node->_left;
|
|
} else {
|
|
left = false;
|
|
node = node->_right;
|
|
}
|
|
}
|
|
node = new Node(key, prevNode);
|
|
if (left) {
|
|
prevNode->_left = node;
|
|
} else {
|
|
prevNode->_right = node;
|
|
}
|
|
return node;
|
|
}
|
|
|
|
void clearNodes(Node *node) {
|
|
if (!node)
|
|
return;
|
|
|
|
clearNodes(node->_left);
|
|
clearNodes(node->_right);
|
|
delete node;
|
|
}
|
|
};
|
|
|
|
} // End of namespace Common
|
|
|
|
#endif
|