Skip to content

Commit

Permalink
Refactor: PathTree node child hashes separate for leaves and branches
Browse files Browse the repository at this point in the history
If a path tree maintains local child indices for branches, they are
now separated to leaves and branches.
  • Loading branch information
skyjake committed Nov 26, 2012
1 parent 112540e commit ab03707
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 43 deletions.
22 changes: 21 additions & 1 deletion doomsday/libdeng2/include/de/data/pathtree.h
Expand Up @@ -66,6 +66,15 @@ class DENG2_PUBLIC PathTree
typedef QMultiHash<Path::hash_type, Node *> Nodes;
typedef QList<String> FoundPaths;

/**
* Leaves and branches are stored in separate hashes.
* Note that one can always unite the hashes (see QMultiHash).
*/
struct DENG2_PUBLIC NodeHash {
Nodes leaves;
Nodes branches;
};

/**
* Flags that affect the properties of the tree.
*/
Expand Down Expand Up @@ -142,7 +151,7 @@ class DENG2_PUBLIC PathTree
class DENG2_PUBLIC Node
{
public:
typedef PathTree::Nodes Children;
typedef PathTree::NodeHash Children;

protected:
Node(NodeArgs const &args);
Expand All @@ -161,6 +170,16 @@ class DENG2_PUBLIC PathTree
/// have no children -- calling this for leaf nodes is not allowed.
Children const &children() const;

/**
* Returns the children of a branch node. Note that leaf nodes
* have no children -- calling this for leaf nodes is not allowed.
*
* @param type Type of hash to return (leaves or branches).
*
* @return Hash of nodes.
*/
Nodes const &childNodes(NodeType type) const;

/// Determines if the node is at the root level of the tree
/// (no other node is its parent).
bool isAtRootLevel() const;
Expand Down Expand Up @@ -219,6 +238,7 @@ class DENG2_PUBLIC PathTree
SegmentId segmentId() const;
void addChild(Node &node);
void removeChild(Node &node);
Nodes &childNodes(NodeType type);

private:
struct Instance;
Expand Down
10 changes: 4 additions & 6 deletions doomsday/libdeng2/src/data/archive.cpp
Expand Up @@ -121,10 +121,9 @@ dint Archive::listFiles(Archive::Names& names, Path const &folder) const
PathTree::Node const &parent = d->index->find(folder, PathTree::MatchFull | PathTree::NoLeaf);

// Traverse the parent's nodes.
for(PathTreeIterator<PathTree> iter(parent.children()); iter.hasNext(); )
for(PathTreeIterator<PathTree> iter(parent.children().leaves); iter.hasNext(); )
{
PathTree::Node const &node = iter.next();
if(node.isLeaf()) names.insert(node.name());
names.insert(iter.next().name());
}

return names.size();
Expand All @@ -140,10 +139,9 @@ dint Archive::listFolders(Archive::Names &names, Path const &folder) const
PathTree::Node const &parent = d->index->find(folder, PathTree::MatchFull | PathTree::NoLeaf);

// Traverse the parent's nodes.
for(PathTreeIterator<PathTree> iter(parent.children()); iter.hasNext(); )
for(PathTreeIterator<PathTree> iter(parent.children().branches); iter.hasNext(); )
{
PathTree::Node const &node = iter.next();
if(node.isBranch()) names.insert(node.name());
names.insert(iter.next().name());
}

return names.size();
Expand Down
54 changes: 20 additions & 34 deletions doomsday/libdeng2/src/data/pathtree.cpp
Expand Up @@ -45,9 +45,8 @@ struct PathTree::Instance
/// Node that represents the one root branch of all nodes.
PathTree::Node rootNode;

/// Path node hashes.
PathTree::Nodes leafHash;
PathTree::Nodes branchHash;
/// Path node hashes (leaves and branches).
PathTree::NodeHash hash;

Instance(PathTree &d, int _flags)
: self(d), flags(_flags), size(0),
Expand All @@ -61,8 +60,8 @@ struct PathTree::Instance

void clear()
{
clearPathHash(leafHash);
clearPathHash(branchHash);
clearPathHash(hash.leaves);
clearPathHash(hash.branches);
size = 0;
}

Expand All @@ -80,12 +79,13 @@ struct PathTree::Instance
PathTree::Node *nodeForSegment(Path::Segment const &segment, PathTree::NodeType nodeType,
PathTree::Node *parent)
{
PathTree::Nodes const &hash = self.nodes(nodeType);

// Have we already encountered this?
PathTree::SegmentId segmentId = segments.isInterned(segment);
if(segmentId)
{
// The name is known. Perhaps we have.
PathTree::Nodes &hash = (nodeType == PathTree::Leaf? leafHash : branchHash);
Path::hash_type hashKey = segments.userValue(segmentId);
for(PathTree::Nodes::const_iterator i = hash.find(hashKey);
i != hash.end() && i.key() == hashKey; ++i)
Expand Down Expand Up @@ -118,14 +118,7 @@ struct PathTree::Instance
PathTree::Node *node = self.newNode(PathTree::NodeArgs(self, nodeType, segmentId, parent));

// Insert the new node into the hash.
if(nodeType == PathTree::Leaf)
{
leafHash.insert(hashKey, node);
}
else // Branch
{
branchHash.insert(hashKey, node);
}
const_cast<Nodes &>(hash).insert(hashKey, node);

return node;
}
Expand Down Expand Up @@ -193,13 +186,13 @@ struct PathTree::Instance

if(!compFlags.testFlag(NoLeaf))
{
if((found = findInHash(leafHash, hashKey, searchPath, compFlags)) != 0)
if((found = findInHash(hash.leaves, hashKey, searchPath, compFlags)) != 0)
return found;
}

if(!compFlags.testFlag(NoBranch))
{
if((found = findInHash(branchHash, hashKey, searchPath, compFlags)) != 0)
if((found = findInHash(hash.branches, hashKey, searchPath, compFlags)) != 0)
return found;
}
}
Expand Down Expand Up @@ -330,7 +323,7 @@ PathTree::Node *PathTree::newNode(NodeArgs const &args)

PathTree::Nodes const &PathTree::nodes(NodeType type) const
{
return (type == Leaf? d->leafHash : d->branchHash);
return (type == Leaf? d->hash.leaves : d->hash.branches);
}

static void collectPathsInHash(PathTree::FoundPaths &found, PathTree::Nodes const &ph, QChar separator)
Expand All @@ -349,11 +342,11 @@ int PathTree::findAllPaths(FoundPaths &found, ComparisonFlags flags, QChar separ
int numFoundSoFar = found.count();
if(!(flags & NoBranch))
{
collectPathsInHash(found, branchNodes(), separator);
collectPathsInHash(found, d->hash.branches, separator);
}
if(!(flags & NoLeaf))
{
collectPathsInHash(found, leafNodes(), separator);
collectPathsInHash(found, d->hash.leaves, separator);
}
return found.count() - numFoundSoFar;
}
Expand All @@ -372,6 +365,14 @@ static int iteratePathsInHash(PathTree const &pathTree, Path::hash_type hashKey,

PathTree::Nodes const *nodes = &pathTree.nodes(type);

// If the parent is known, we can narrow our search to all the parent's
// children.
if(!pathTree.flags().testFlag(PathTree::NoLocalBranchIndex) &&
flags.testFlag(PathTree::MatchParent) && parent)
{
nodes = &parent->childNodes(type);
}

// Are we iterating nodes with a known hash?
if(hashKey != PathTree::no_hash)
{
Expand All @@ -388,24 +389,9 @@ static int iteratePathsInHash(PathTree const &pathTree, Path::hash_type hashKey,
}
else
{
// No known hash, but if the parent is known, we can narrow our search
// to all the parent's children.
if(!pathTree.flags().testFlag(PathTree::NoLocalBranchIndex) &&
flags.testFlag(PathTree::MatchParent) && parent)
{
nodes = &parent->children();
}

// No known hash -- iterate all potential nodes.
DENG2_FOR_EACH_CONST(PathTree::Nodes, i, *nodes)
{
if(flags.testFlag(PathTree::MatchParent) && (*i)->type() != type)
{
// Wrong kind of node -- branches could maintain separate indexes
// for branches and leaves...
continue;
}

if(!(flags.testFlag(PathTree::MatchParent) && parent != &(*i)->parent()))
{
result = callback(**i, parameters);
Expand Down
16 changes: 14 additions & 2 deletions doomsday/libdeng2/src/data/pathtreenode.cpp
Expand Up @@ -85,6 +85,18 @@ const PathTree::Node::Children &PathTree::Node::children() const
return *d->children;
}

PathTree::Nodes const &PathTree::Node::childNodes(PathTree::NodeType type) const
{
DENG2_ASSERT(d->children != 0);
return (type == PathTree::Leaf? d->children->leaves : d->children->branches);
}

PathTree::Nodes &PathTree::Node::childNodes(PathTree::NodeType type)
{
DENG2_ASSERT(d->children != 0);
return (type == PathTree::Leaf? d->children->leaves : d->children->branches);
}

bool PathTree::Node::isAtRootLevel() const
{
return d->parent == &d->tree.rootBranch();
Expand All @@ -101,7 +113,7 @@ void PathTree::Node::addChild(PathTree::Node &node)
{
DENG2_ASSERT(d->children != 0);

d->children->insert(node.hash(), &node);
childNodes(node.type()).insert(node.hash(), &node);
}
}

Expand All @@ -111,7 +123,7 @@ void PathTree::Node::removeChild(PathTree::Node &node)
{
DENG2_ASSERT(d->children != 0);

d->children->remove(node.hash(), &node);
childNodes(node.type()).remove(node.hash(), &node);
}
}

Expand Down

0 comments on commit ab03707

Please sign in to comment.