Adds simple_set data structure and hooked it up to the debugger comment system.

[Andrew Gardner]
This commit is contained in:
Andrew Gardner 2013-04-13 20:03:24 +00:00
parent 361f42eff7
commit 7bf57783e7
5 changed files with 1030 additions and 102 deletions

1
.gitattributes vendored
View File

@ -2385,6 +2385,7 @@ src/lib/util/pool.c svneol=native#text/plain
src/lib/util/pool.h svneol=native#text/plain
src/lib/util/sha1.c svneol=native#text/plain
src/lib/util/sha1.h svneol=native#text/plain
src/lib/util/simple_set.h svneol=native#text/plain
src/lib/util/tagmap.h svneol=native#text/plain
src/lib/util/un7z.c svneol=native#text/plain
src/lib/util/un7z.h svneol=native#text/plain

View File

@ -2602,33 +2602,10 @@ void device_debug::comment_add(offs_t addr, const char *comment, rgb_t color)
{
// create a new item for the list
UINT32 crc = compute_opcode_crc32(addr);
dasm_comment *newcomment = auto_alloc(m_device.machine(), dasm_comment(comment, addr, color, crc));
// figure out where to insert it
dasm_comment *prev = NULL;
dasm_comment *curr;
for (curr = m_comment_list.first(); curr != NULL; prev = curr, curr = curr->next())
if (curr->m_address >= addr)
break;
// we could be the new head
if (prev == NULL)
m_comment_list.prepend(*newcomment);
// or else we just insert ourselves here
else
{
newcomment->m_next = prev->m_next;
prev->m_next = newcomment;
}
// scan forward from here to delete any exact matches
for ( ; curr != NULL && curr->m_address == addr; curr = curr->next())
if (curr->m_crc == crc)
{
m_comment_list.remove(*curr);
break;
}
dasm_comment newComment = dasm_comment(comment, addr, color, crc);
if (m_comment_set.contains(newComment))
m_comment_set.remove(newComment);
m_comment_set.insert(newComment);
// force an update
m_comment_change++;
@ -2644,24 +2621,9 @@ bool device_debug::comment_remove(offs_t addr)
{
// scan the list for a match
UINT32 crc = compute_opcode_crc32(addr);
for (dasm_comment *curr = m_comment_list.first(); curr != NULL; curr = curr->next())
{
// if we're past the address, we failed
if (curr->m_address > addr)
break;
// find an exact match
if (curr->m_address == addr && curr->m_crc == crc)
{
// remove it and force an update
m_comment_list.remove(*curr);
m_comment_change++;
return true;
}
}
// failure is an option
return false;
bool success = m_comment_set.remove(dasm_comment("", addr, 0xffffffff, crc));
if (success) m_comment_change++;
return success;
}
@ -2673,19 +2635,9 @@ const char *device_debug::comment_text(offs_t addr) const
{
// scan the list for a match
UINT32 crc = compute_opcode_crc32(addr);
for (dasm_comment *curr = m_comment_list.first(); curr != NULL; curr = curr->next())
{
// if we're past the address, we failed
if (curr->m_address > addr)
break;
// find an exact match
if (curr->m_address == addr && curr->m_crc == crc)
return curr->m_text;
}
// failure is an option
return NULL;
dasm_comment* comment = m_comment_set.find(dasm_comment("", addr, 0, crc));
if (comment == NULL) return NULL;
return comment->m_text;
}
@ -2698,14 +2650,15 @@ bool device_debug::comment_export(xml_data_node &curnode)
{
// iterate through the comments
astring crc_buf;
for (dasm_comment *curr = m_comment_list.first(); curr != NULL; curr = curr->next())
simple_set_iterator<dasm_comment> iter(m_comment_set);
for (dasm_comment* item = iter.first(); item != iter.last(); item = iter.next())
{
xml_data_node *datanode = xml_add_child(&curnode, "comment", xml_normalize_string(curr->m_text));
xml_data_node *datanode = xml_add_child(&curnode, "comment", xml_normalize_string(item->m_text));
if (datanode == NULL)
return false;
xml_set_attribute_int(datanode, "address", curr->m_address);
xml_set_attribute_int(datanode, "color", curr->m_color);
crc_buf.printf("%08X", curr->m_crc);
xml_set_attribute_int(datanode, "address", item->m_address);
xml_set_attribute_int(datanode, "color", item->m_color);
crc_buf.printf("%08X", item->m_crc);
xml_set_attribute(datanode, "crc", crc_buf);
}
return true;
@ -2725,41 +2678,17 @@ bool device_debug::comment_import(xml_data_node &cpunode)
// extract attributes
offs_t address = xml_get_attribute_int(datanode, "address", 0);
rgb_t color = xml_get_attribute_int(datanode, "color", 0);
UINT32 crc;
sscanf(xml_get_attribute_string(datanode, "crc", 0), "%08X", &crc);
// add the new comment; we assume they were saved ordered
m_comment_list.append(*auto_alloc(m_device.machine(), dasm_comment(datanode->value, address, color, crc)));
m_comment_set.insert(dasm_comment(datanode->value, address, color, crc));
}
return true;
}
//-------------------------------------------------
// comment_dump - logs comments to the error.log
// at a given address
//-------------------------------------------------
void device_debug::comment_dump(offs_t addr)
{
// determine the CRC at the given address (if valid)
UINT32 crc = (addr == ~0) ? 0 : compute_opcode_crc32(addr);
// dump everything that matches
bool found = false;
for (dasm_comment *curr = m_comment_list.first(); curr != NULL; curr = curr->next())
if (addr == ~0 || (curr->m_address == addr && curr->m_crc == crc))
{
found = true;
logerror("%08X %08X - %s\n", curr->m_address, curr->m_crc, curr->m_text.cstr());
}
// if nothing found, indicate as much
if (!found)
logerror("No comment exists for address : 0x%x\n", addr);
}
//-------------------------------------------------
// compute_opcode_crc32 - determine the CRC of
// the opcode bytes at the given address

View File

@ -43,6 +43,7 @@
#define __DEBUGCPU_H__
#include "express.h"
#include "simple_set.h"
//**************************************************************************
@ -243,11 +244,10 @@ public:
void comment_add(offs_t address, const char *comment, rgb_t color);
bool comment_remove(offs_t addr);
const char *comment_text(offs_t addr) const;
UINT32 comment_count() const { return m_comment_list.count(); }
UINT32 comment_count() const { return m_comment_set.size(); }
UINT32 comment_change_count() const { return m_comment_change; }
bool comment_export(xml_data_node &node);
bool comment_import(xml_data_node &node);
void comment_dump(offs_t addr = ~0);
UINT32 compute_opcode_crc32(offs_t address) const;
// history
@ -286,11 +286,11 @@ private:
static void set_state(symbol_table &table, void *ref, UINT64 value);
// basic device information
device_t & m_device; // device we are attached to
device_execute_interface *m_exec; // execute interface, if present
device_memory_interface *m_memory; // memory interface, if present
device_state_interface *m_state; // state interface, if present
device_disasm_interface *m_disasm; // disasm interface, if present
device_t & m_device; // device we are attached to
device_execute_interface * m_exec; // execute interface, if present
device_memory_interface * m_memory; // memory interface, if present
device_state_interface * m_state; // state interface, if present
device_disasm_interface * m_disasm; // disasm interface, if present
// global state
UINT32 m_flags; // debugging flags for this CPU
@ -375,9 +375,16 @@ private:
rgb_t m_color; // color to use
UINT32 m_crc; // CRC of code
astring m_text; // text
bool operator < (const dasm_comment& rhs) const // required to be included in a simple_set
{
if (m_address == rhs.m_address)
return m_crc < rhs.m_crc;
return (m_address < rhs.m_address);
}
};
simple_list<dasm_comment> m_comment_list; // list of comments
UINT32 m_comment_change; // change counter for comments
simple_set<dasm_comment> m_comment_set; // collection of comments
UINT32 m_comment_change; // change counter for comments
// internal flag values
static const UINT32 DEBUG_FLAG_OBSERVING = 0x00000001; // observing this CPU

View File

@ -100,10 +100,6 @@ debug_view_disasm::debug_view_disasm(running_machine &machine, debug_view_osd_up
total_comments += dasmsource.m_device.debug()->comment_count();
}
// initialize
if (total_comments > 0)
m_right_column = DASM_RIGHTCOL_COMMENTS;
// configure the view
m_total.y = DEFAULT_DASM_LINES;
m_supports_cursor = true;

995
src/lib/util/simple_set.h Normal file
View File

@ -0,0 +1,995 @@
/*********************************************************************
simple_set.h
A STL-like set class.
Copyright Nicola Salmoria and the MAME Team.
Visit http://mamedev.org for licensing and usage restrictions.
*********************************************************************/
#pragma once
#ifndef __SIMPLE_SET_H__
#define __SIMPLE_SET_H__
#ifdef SIMPLE_SET_DEBUG
#include <iostream>
#endif
// Predeclarations
template <class T> class avl_tree_node;
template <class T> class simple_set_iterator;
//
// ======================> simple_set
// A shiny stl-like set interface wrapping an AVL tree
//
// PUBLIC OPERATIONS:
// size, empty, clear, insert, remove, find, contains, merge, & assignment.
//
template <class T>
class simple_set
{
friend class simple_set_iterator<T>;
typedef avl_tree_node<T> tree_node;
public:
// Construction
simple_set(resource_pool &pool = global_resource_pool())
: m_root(NULL),
m_pool(pool)
{ }
simple_set(const simple_set& rhs)
: m_root(NULL)
{
*this = rhs;
}
~simple_set()
{
clear();
}
// A reference to the resource pool
resource_pool &pool() const { return m_pool; }
// Returns number of elements in the tree -- O(n)
int size() const
{
if (empty()) return 0;
const tree_node* currentNode = m_root;
const int nodeCount = sizeRecurse(currentNode);
return nodeCount;
}
// Test for emptiness -- O(1).
bool empty() const
{
return m_root == NULL;
}
// Empty the tree -- O(n).
void clear()
{
clearRecurse(m_root);
}
// Insert x into the avl tree; duplicates are ignored -- O(log n).
bool insert(const T& x)
{
bool retVal = insert(x, m_root);
// Whether the node was successfully inserted or not (i.e. wasn't a duplicate)
return retVal;
}
// Remove x from the tree. Nothing is done if x is not found -- O(n).
bool remove(const T& x)
{
// First find the node in the tree
tree_node* currNode = find(x, m_root);
// Only do this when the current node is valid
if (currNode)
{
// See if it's a leaf
if (currNode->isLeaf())
{
// If we're a leaf and we have no parent, then the tree will be emptied
if (!currNode->parent)
{
m_root = NULL;
}
// If it's a leaf node, simply remove it
removeNode(currNode);
pool_free(m_pool, currNode);
}
else
{
// Get the parent object
tree_node* parentNode = currNode->parent;
// Remove the child and reconnect the smallest node in the right sub tree
// (in order successor)
tree_node* replaceNode = findMin(currNode->right);
// See if there's even a right-most node
if (!replaceNode)
{
// Get the largest node on the left (because the right doesn't exist)
replaceNode = findMax(currNode->left);
}
// Disconnect the replacement node's branch
removeNode(replaceNode);
// Disconnect the current node
removeNode(currNode);
// Get the current node's left and right branches
tree_node* left = currNode->left;
tree_node* right = currNode->right;
// We no longer need this node
pool_free(m_pool, currNode);
// Check to see if we removed the root node
if (!parentNode)
{
// Merge the branches into the parent node of what we deleted
merge(replaceNode, parentNode);
merge(left, parentNode);
merge(right, parentNode);
// Now we're the the root
m_root = parentNode;
}
else
{
// Merge the branches into the parent node of what we
// deleted, we let the merge algorithm decide where to
// put the branches
merge(replaceNode, parentNode);
merge(left, parentNode);
merge(right, parentNode);
}
}
// Balance the tree
balanceTree();
// The node was found and removed successfully
return true;
}
else
{
// The node was not found
return false;
}
}
// Find item x in the tree. Returns a pointer to the matching item
// or NULL if not found -- O(log n)
T* find(const T& x) const
{
tree_node* found = find(x, m_root);
if (found == NULL) return NULL;
return &found->element;
}
// Is the data present in the set? -- O(log n)
bool contains(const T& x) const
{
if (find(x) != NULL)
return true;
else
return false;
}
// Merge a different tree with ours -- O(n).
bool merge(const simple_set<T>& b)
{
tree_node* c = b->clone();
bool retVal = merge(c->m_root, m_root);
// Re-balance the tree if the merge was successful
if (retVal)
{
balanceTree();
}
else
{
pool_free(m_pool, c);
}
return retVal;
}
// Replace this set with another -- O(n)
const simple_set& operator=(const simple_set& rhs)
{
// Don't clone if it's the same pointer
if (this != &rhs)
{
clear();
m_root = clone(rhs.m_root);
}
return *this;
}
#ifdef SIMPLE_SET_DEBUG
// Debug -- O(n log n)
void printTree(std::ostream& out = std::cout) const
{
if(empty())
{
out << "Empty tree" << std::endl;
}
else
{
printTree(out, m_root);
}
}
#endif
private:
// The AVL tree's root
tree_node* m_root;
// Resource pool where objects are freed
resource_pool& m_pool;
// Find a node in the tree
tree_node* findNode(const T& x) const
{
tree_node* node = find(x, m_root);
if (node)
{
return node;
}
else
{
return NULL;
}
}
// Insert item x into a subtree t (root) -- O(log n)
bool insert(const T& x, tree_node*& t)
{
if (t == NULL)
{
t = pool_alloc(m_pool, tree_node(x, NULL, NULL, NULL));
// An empty sub-tree here, insertion successful
return true;
}
else if (x < t->element)
{
// O(log n)
bool retVal = insert(x, t->left);
if (retVal)
{
t->left->setParent(t);
if(t->balanceFactor() < -1)
{
// See if it went left of the left
if(x < t->left->element)
{
rotateWithLeftChild(t);
}
else
{
// The element goes on the right of the left
doubleWithLeftChild(t);
}
}
}
return retVal;
}
else if (t->element < x)
{
bool retVal = insert(x, t->right);
// Only do this if the insertion was successful
if (retVal)
{
t->right->setParent(t);
if (t->balanceFactor() > 1)
{
// See if it went right of the right
if(t->right->element < x)
{
rotateWithRightChild(t);
}
else
{
// The element goes on the left of the right
doubleWithRightChild(t);
}
}
}
return retVal;
}
else
{
return false; // Duplicate
}
}
// Recursively free all nodes in the tree -- O(n).
void clearRecurse(tree_node*& t) const
{
if(t != NULL)
{
clearRecurse(t->left);
clearRecurse(t->right);
pool_free(m_pool, t);
}
t = NULL;
}
// Merge a tree with this one. Private because external care is required.
bool merge(tree_node* b, tree_node*& t)
{
if (!b)
{
return false;
}
else
{
bool retVal = false;
if (t == NULL)
{
// Set this element to that subtree
t = b;
// The parent here should be NULL anyway, but we
// set it just to be sure. This pointer will be
// used as a flag to indicate where in the call
// stack the tree was actually set.
//
// The middle layers of this method's call will
// all have their parent references in tact since
// no operations took place there.
//
//t->parent = NULL;
t->setParent(NULL);
// We were successful in merging
retVal = true;
}
else if (b->element < t->element)
{
retVal = merge(b, t->left);
// Only do this if the insertion actually took place
if (retVal && !t->left->parent)
{
t->left->setParent(t);
}
}
else if (t->element < b->element)
{
retVal = merge(b, t->right);
// Only do this if the insertion was successful
if (retVal && !t->right->parent)
{
t->right->setParent(t);
}
return retVal;
}
return retVal;
}
}
// Find the smallest item's node in a subtree t -- O(log n).
tree_node* findMin(tree_node* t) const
{
if(t == NULL)
{
return t;
}
while(t->left != NULL)
{
t = t->left;
}
return t;
}
// Find the smallest item's node in a subtree t -- O(log n).
tree_node* findMax(tree_node* t) const
{
if(t == NULL)
{
return t;
}
while(t->right != NULL)
{
t = t->right;
}
return t;
}
// Find item x's node in subtree t -- O(log n)
tree_node* find(const T& x, tree_node* t) const
{
while(t != NULL)
{
if (x < t->element)
{
t = t->left;
}
else if (t->element < x)
{
t = t->right;
}
else
{
return t; // Match
}
}
return NULL; // No match
}
// Clone a subtree -- O(n)
tree_node* clone(const tree_node* t) const
{
if(t == NULL)
{
return NULL;
}
else
{
// Create a node with the left and right nodes and a parent set to NULL
tree_node* retVal = pool_alloc(m_pool, tree_node(t->element, NULL, clone(t->left), clone(t->right)));
// Now set our children's parent node reference
if (retVal->left) { retVal->left->setParent(retVal); }
if (retVal->right) { retVal->right->setParent(retVal); }
return retVal;
}
}
// Rotate binary tree node with left child.
// Single rotation for case 1 -- O(1).
void rotateWithLeftChild(tree_node*& k2) const
{
tree_node* k1 = k2->left;
tree_node* k2Parent = k2->parent;
k2->setLeft(k1->right);
if (k2->left) { k2->left->setParent(k2); }
k1->setRight(k2);
if (k1->right) { k1->right->setParent(k1); }
k2 = k1;
k2->setParent(k2Parent);
}
// Rotate binary tree node with right child.
// Single rotation for case 4 -- O(1).
void rotateWithRightChild(tree_node*& k1) const
{
tree_node* k2 = k1->right;
tree_node* k1Parent = k1->parent;
k1->setRight(k2->left);
if (k1->right) { k1->right->setParent(k1); }
k2->setLeft(k1);
if (k2->left) { k2->left->setParent(k2); }
k1 = k2;
k1->setParent(k1Parent);
}
// Double rotate binary tree node: first left child
// with its right child; then node k3 with new left child.
// Double rotation for case 2 -- O(1).
void doubleWithLeftChild(tree_node*& k3) const
{
rotateWithRightChild(k3->left);
rotateWithLeftChild(k3);
}
// Double rotate binary tree node: first right child
// with its left child; then node k1 with new right child.
// Double rotation for case 3 -- O(1).
void doubleWithRightChild(tree_node*& k1) const
{
rotateWithLeftChild(k1->right);
rotateWithRightChild(k1);
}
// Removes a node. Returns true if the node was on the left side of its parent -- O(1).
void removeNode(tree_node*& node)
{
// It is a leaf, simply remove the item and disconnect the parent
if (node->isLeft())
{
node->parent->setLeft(NULL);
}
else // (node == node->parent->right)
{
if (node->parent) { node->parent->setRight(NULL); }
}
node->setParent(NULL);
}
// Swap one node with another -- O(1).
void replaceNode(tree_node*& node1, tree_node*& node2)
{
// Save both parent references
simple_set<T>* node1Parent = node1->parent;
simple_set<T>* node2Parent = node2->parent;
// First move node2 into node1's place
if (node1Parent)
{
if (isLeft(node1))
{
node1Parent->setLeft(node2);
}
else // node1 is on the right
{
node1Parent->setRight(node2);
}
}
node2->setParent(node1Parent);
// Now move node1 into node2's place
if (node2Parent)
{
if (isLeft(node2))
{
node2Parent->setLeft(node1);
}
else // node2 is on the right
{
node2Parent->setRight(node1);
}
}
node1->setParent(node2Parent);
}
// Balances the tree starting at the root node
void balanceTree() { balanceTree(m_root); }
// Balance the tree starting at the given node -- O(n).
void balanceTree(tree_node*& node)
{
if (node)
{
// First see what the balance factor for this node is
int balFactor = node->balanceFactor();
if (balFactor < -1)
{
// See if we're heavy left of the left
if(node->left->balanceFactor() < 0)
{
rotateWithLeftChild(node);
}
else // if (node->left->balanceFactor() > 0)
{
// We're heavy on the right of the left
doubleWithLeftChild(node);
}
}
else if (balFactor > 1)
{
// See if it we're heavy right of the right
if(node->right->balanceFactor() > 0)
{
rotateWithRightChild(node);
}
else // if (node->right->balanceFactor() < 0)
{
// The element goes on the left of the right
doubleWithRightChild(node);
}
}
else // if (balFactor >= -1 && balFactor <= 1)
{
// We're balanced here, but are our children balanced?
balanceTree(node->left);
balanceTree(node->right);
}
}
}
// Recursive helper function for public size()
int sizeRecurse(const tree_node* currentNode) const
{
int nodeCount = 1;
if (currentNode->left != NULL)
nodeCount += sizeRecurse(currentNode->left);
if (currentNode->right != NULL)
nodeCount += sizeRecurse(currentNode->right);
return nodeCount;
}
#ifdef SIMPLE_SET_DEBUG
// Debug. Print from the start node, down -- O(n log n).
void printTree(std::ostream& out, tree_node* t=NULL, int numTabs=0, char lr='_') const
{
if(t != NULL)
{
for (int i =0; i < numTabs; i++) { out << " "; } out << "|_" << lr << "__ ";
out << t->element << " {h = " << t->height() << ", b = " << t->balanceFactor() << "} ";
// TODO: Reinstate out << std::hex << t << " (p = " << t->parent << ")" << std::dec;
out << std::endl;
printTree(out, t->left, numTabs + 1, '<');
printTree(out, t->right, numTabs + 1, '>');
}
}
#endif
};
//
// ======================> avl_tree_node
// Member nodes of the simple_set's AVL tree
//
template <class T> class avl_tree_node
{
friend class simple_set<T>;
friend class simple_set_iterator<T>;
typedef avl_tree_node<T> tree_node;
public:
// Construction
avl_tree_node(const T& theElement, avl_tree_node* p, avl_tree_node* lt, avl_tree_node* rt)
: element(theElement),
parent(p),
left(lt),
right(rt),
m_height(1),
m_balanceFactor(0)
{ }
// Are we to our parent's left?
bool isLeft()
{
if (parent && this == parent->left)
{
return true;
}
else
{
return false;
}
}
// Are we a leaf node?
bool isLeaf() { return !left && !right; }
// Set the parent pointer
void setParent(tree_node* p)
{
// Set our new parent
parent = p;
// If we have a valid parent, set its height
if (parent)
{
// Set the parent's height to include this tree. If the parent
// already has a tree that is taller than the one we're attaching
// then the parent's height remains unchanged
int rightHeight = (parent->right ? parent->right->m_height : 0);
int leftHeight = (parent->left ? parent->left->m_height : 0);
// The height of the tallest branch + 1
parent->m_height = maxInt(rightHeight, leftHeight) + 1;
// Also set the balance factor
parent->m_balanceFactor = rightHeight - leftHeight;
}
}
// Set the left child pointer
void setLeft(tree_node* l)
{
// Set our new left node
left = l;
// Set the height and balance factor
int rightHeight = (right ? right->m_height : 0);
int leftHeight = (left ? left->m_height : 0);
m_height = maxInt(rightHeight, leftHeight) + 1;
m_balanceFactor = (right ? right->m_height : 0) - (left ? left->m_height : 0);
}
// Set the right child pointer
void setRight(tree_node* r)
{
// Set our new right node
right = r;
// Set the height and balance factor
int rightHeight = (right ? right->m_height : 0);
int leftHeight = (left ? left->m_height : 0);
m_height = maxInt(rightHeight, leftHeight) + 1;
m_balanceFactor = (right ? right->m_height : 0) - (left ? left->m_height : 0);
}
// Recover the height
int height() const
{
// The height is equal to the maximum of the right or left side's height plus 1
// Trading memory for operation time can be done O(n) like this =>
// return max(left ? left->height() : 0, right ? right->height() : 0) + 1;
return m_height;
}
// Recover the balance factor
int balanceFactor() const
{
// The weight of a node is equal to the difference between
// the weight of the left subtree and the weight of the
// right subtree
//
// O(n) version =>
// return (right ? right->height() : 0) - (left ? left->height() : 0);
//
return m_balanceFactor;
}
private:
// Calculates all of the heights for this node and its ancestors -- O(log n).
void calcHeights()
{
// Calculate our own height -- O(1)
m_height = maxInt(left ? left->m_height : 0, right ? right->m_height : 0) + 1;
// And our parent's height (and recurse) -- O(log n)
if (parent)
{
parent->calcHeights();
}
}
// Utility function - TODO replace
int maxInt(const int& lhs, const int& rhs) const
{
return lhs > rhs ? lhs : rhs;
}
private:
T element;
avl_tree_node* parent;
avl_tree_node* left;
avl_tree_node* right;
int m_height;
int m_balanceFactor;
};
//
// ======================> simple_set_iterator
// Iterator that allows for various set (AVL tree) navigation methods
// Points to elements of the set, rather than AVL tree nodes.
//
// PUBLIC OPERATIONS:
// current, first, last, next, count, indexof, byindex
//
template <class T>
class simple_set_iterator
{
typedef avl_tree_node<T> tree_node;
public:
enum TraversalType { PRE_ORDER, IN_ORDER, POST_ORDER, LEVEL_ORDER };
public:
// construction
simple_set_iterator(simple_set<T>& set, const TraversalType& tt=IN_ORDER)
: m_set(&set),
m_traversalType(tt),
m_currentNode(NULL),
m_endNode(NULL) { }
~simple_set_iterator() { }
// getters
T* current() const { return m_currentNode; }
// reset and return first item
T* first()
{
m_currentNode = m_set->m_root;
switch (m_traversalType)
{
case IN_ORDER:
{
// The current node is the smallest value
m_currentNode = m_set->findMin(m_set->m_root);
// The end case is the largest value
m_endNode = m_set->findMax(m_set->m_root);
return &m_currentNode->element;
}
default:
{
// TODO (better error message):
printf("simple_set_iterator: Traversal type not yet supported.\n");
return NULL;
}
}
return NULL;
}
T* last()
{
return NULL;
}
// advance according to current state and traversal type
T* next()
{
if (m_currentNode == NULL) return NULL;
switch (m_traversalType)
{
case IN_ORDER:
{
// You are at the end
if (m_currentNode == m_endNode)
return NULL;
if (m_currentNode->right != NULL)
{
// Gather the furthest left node of right subtree
m_currentNode = m_currentNode->right;
while (m_currentNode->left != NULL)
{
m_currentNode = m_currentNode->left;
}
}
else
{
// No right subtree? Move up the tree, looking for a left child link.
tree_node* p = m_currentNode->parent;
while (p != NULL && m_currentNode == p->right)
{
m_currentNode = p;
p = p->parent;
}
m_currentNode = p;
}
return &m_currentNode->element;
}
default:
{
// TODO (better error message):
printf("simple_set_iterator: Traversal type not yet supported.\n");
return NULL;
}
}
return NULL;
}
// return the number of items available
int count()
{
return m_set->size();
}
// return the index of a given item in the virtual list
// note: this function is destructive to any in-progress iterations!
int indexof(T inData)
{
int index = 0;
for (T* data = first(); data != last(); data = next(), index++)
if (!(*data < inData) && !(inData < *data))
return index;
return -1;
}
// return the indexed item in the list
// note: this function is destructive to any in-progress iterations!
T* byindex(int index)
{
int count = 0;
for (T* data = first(); data != last(); data = next(), count++)
if (count == index)
return data;
return NULL;
}
private:
simple_set<T>* m_set;
TraversalType m_traversalType;
tree_node* m_currentNode;
tree_node* m_endNode;
};
#endif