/* * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #ifndef INDEX_IMPL_H #define INDEX_IMPL_H #include "Index.h" #include "Node.h" #include "NodeListener.h" class AbstractIndexIterator { public: AbstractIndexIterator(); virtual ~AbstractIndexIterator(); virtual bool HasNext() const = 0; virtual Node* Next(void* buffer, size_t* _keyLength) = 0; virtual status_t Suspend(); virtual status_t Resume(); }; template class GenericIndexIterator : public AbstractIndexIterator, public NodeListener { public: typedef typename Policy::Index Index; typedef typename Policy::Value Value; typedef typename Policy::NodeTree NodeTree; typedef typename Policy::TreePolicy TreePolicy; typedef typename NodeTree::Node TreeNode; public: GenericIndexIterator(); virtual ~GenericIndexIterator(); virtual bool HasNext() const; virtual Node* Next(void* buffer, size_t* _keyLength); virtual status_t Suspend(); virtual status_t Resume(); bool SetTo(Index* index, const Value& name, bool ignoreValue = false); inline void NodeChangeBegin(Node* node); inline void NodeChangeEnd(Node* node); virtual void NodeRemoved(Node* node); protected: Index* fIndex; TreeNode* fNextTreeNode; bool fSuspended; }; template GenericIndexIterator::GenericIndexIterator() : AbstractIndexIterator(), fIndex(NULL), fNextTreeNode(NULL), fSuspended(false) { } template GenericIndexIterator::~GenericIndexIterator() { SetTo(NULL, Value()); } template bool GenericIndexIterator::HasNext() const { return fNextTreeNode != NULL; } template Node* GenericIndexIterator::Next(void* buffer, size_t* _keyLength) { if (fSuspended || fNextTreeNode == NULL) return NULL; if (buffer != NULL) TreePolicy::GetTreeNodeValue(fNextTreeNode, buffer, _keyLength); TreeNode* treeNode = fNextTreeNode; fNextTreeNode = Policy::GetNodeTree(fIndex)->Next(fNextTreeNode); return TreePolicy::GetNode(treeNode); } template status_t GenericIndexIterator::Suspend() { if (fSuspended) return B_BAD_VALUE; if (fNextTreeNode != NULL) { fIndex->GetVolume()->AddNodeListener(this, TreePolicy::GetNode(fNextTreeNode)); } fSuspended = true; return B_OK; } template status_t GenericIndexIterator::Resume() { if (!fSuspended) return B_BAD_VALUE; if (fNextTreeNode != NULL) fIndex->GetVolume()->RemoveNodeListener(this); fSuspended = false; return B_OK; } template bool GenericIndexIterator::SetTo(Index* index, const Value& value, bool ignoreValue) { Resume(); fIndex = index; fSuspended = false; fNextTreeNode = NULL; if (fIndex == NULL) return false; if (ignoreValue) fNextTreeNode = TreePolicy::GetFirstTreeNode(fIndex); else fNextTreeNode = TreePolicy::FindClosestTreeNode(fIndex, value); return fNextTreeNode != NULL; } /*! Moves the iterator temporarily off the current node. Called when the node the iterator currently points to has been modified and the index is about to remove it from and reinsert it into the tree. After having done that NodeChangeEnd() must be called. */ template void GenericIndexIterator::NodeChangeBegin(Node* node) { fNextTreeNode = Policy::GetNodeTree(fIndex)->Previous(fNextTreeNode); } /*! Brackets a NodeChangeBegin() call. */ template void GenericIndexIterator::NodeChangeEnd(Node* node) { if (fNextTreeNode != NULL) fNextTreeNode = Policy::GetNodeTree(fIndex)->Next(fNextTreeNode); else fNextTreeNode = TreePolicy::GetFirstTreeNode(fIndex); // If the node is no longer the one we originally pointed to, re-register // the node listener. if (fNextTreeNode == NULL) { fIndex->GetVolume()->RemoveNodeListener(this); } else { Node* newNode = TreePolicy::GetNode(fNextTreeNode); if (newNode != node) { fIndex->GetVolume()->RemoveNodeListener(this); fIndex->GetVolume()->AddNodeListener(this, newNode); } } } template void GenericIndexIterator::NodeRemoved(Node* node) { Resume(); Next(NULL, NULL); Suspend(); } template struct GenericIndexIteratorTreePolicy { typedef typename Policy::Index Index; typedef typename Policy::Value Value; typedef typename Policy::NodeTree NodeTree; typedef typename NodeTree::Node TreeNode; static Node* GetNode(TreeNode* treeNode) { typename Policy::NodeTree::NodeStrategy strategy; return strategy.GetValue(treeNode); } static TreeNode* GetFirstTreeNode(Index* index) { typename NodeTree::Iterator iterator; Policy::GetNodeTree(index)->GetIterator(&iterator); return iterator.CurrentNode(); } static TreeNode* FindClosestTreeNode(Index* index, const Value& value) { typename NodeTree::Iterator iterator; if (Policy::GetNodeTree(index)->FindFirstClosest(value, false, &iterator) == NULL) { return NULL; } return iterator.CurrentNode(); } static void GetTreeNodeValue(TreeNode* treeNode, void* buffer, size_t* _keyLength) { Policy::GetNodeValue(GetNode(treeNode), buffer, _keyLength); } }; #endif // INDEX_IMPL_H