diff --git a/inc/DirectoryTree.hpp b/inc/DirectoryTree.hpp index e68950d..eaf8c36 100644 --- a/inc/DirectoryTree.hpp +++ b/inc/DirectoryTree.hpp @@ -1,33 +1,48 @@ #pragma once +#include "Tree.hpp" + #include +#include #include -typedef unsigned long long ui64; -typedef unsigned long ui32; - -typedef std::string Key; extern std::string gError; +typedef std::string Key; + +struct DirectoryKey { + DirectoryKey() = default; + explicit DirectoryKey(Key val) : val(std::move(val)) {} + + [[nodiscard]] inline bool descentRight(const DirectoryKey& in) const { return in.val > val; } + [[nodiscard]] inline bool descentLeft(const DirectoryKey& in) const { return in.val < val; } + [[nodiscard]] inline bool exactNode(const DirectoryKey& in) const { return in.val == val; } + + [[nodiscard]] inline const DirectoryKey& getFindKey() const { return *this; } + static inline const DirectoryKey& keyInRightSubtree(const DirectoryKey& in) { return in; } + static inline const DirectoryKey& keyInLeftSubtree(const DirectoryKey& in) { return in; } + + template + inline void updateTreeCacheCallBack(const NodeType&) { + // TODO : update incoming links + } + +public: + Key val; + + ui32 incomingLinksHard = 0; + ui32 incomingLinksDynamic = 0; +}; class Node { public: - enum Type : ui32 { NONE, DIRECTORY, FILE, LINK }; - - Key key; - - Node* parent = nullptr; - Node* left = nullptr; - Node* right = nullptr; - - ui32 height = 0; - ui32 incomingLinksHard = 0; - ui32 incomingLinksDynamic = 0; - - Type type = NONE; - - void updateTreeCache(); + enum Type : ui32 { NONE, DIRECTORY, FILE, LINK } ; +public: + virtual void dump(const Node* node, const Key& key) const = 0; virtual ~Node(); + +public: + Type mType = NONE; }; class File : public Node { @@ -38,47 +53,35 @@ public: class Link : public Node { public: Link(); + [[nodiscard]] Node* getLink() const; - Node* link = nullptr; - bool hard = false; +private: + Node* mLink = nullptr; + bool mIsHard = false; }; class Directory : public Node { + typedef AvlTree DirectoryTree; + public: Directory(); - ~Directory(); + ~Directory() override; bool attachNode(const std::vector& directoryPath, const Key& newKey, Node* newNode); Node* findNode(const std::vector& path, ui32 currentDepth = 0); void detachNode(Node* node); - template - void traverseInorder(tFunctor functor) const { - traverseInorderUtil(members, functor); - } - - [[nodiscard]] Node* maxNode() const; [[nodiscard]] ui32 getMaxDepth() const; -private: - Node* treeSearch(const Key& key); - void updateTreeLinkCount(Node* node); - void treeInsert(const Key& newKey, Node* newNode); - Node* insertUtil(Node* head, const Key& key, Node* aNode); - Node* rotateLeft(Node* pivot); - Node* rotateRight(Node* pivot); - static inline ui32 getNodeHeight(const Node* node); - void getMaxDepthUtil(ui32 depth, ui32& maxDepth) const; - template - void traverseInorderUtil(Node* node, tFunctor functor) const { - if (!node) return; - traverseInorderUtil(node->left, functor); - functor(node); - traverseInorderUtil(node->right, functor); + void traverseInorder(tFunctor functor) const { + mMembers.traverseInorder(mMembers.getRoot(), functor); } +private: + void updateTreeLinkCount(Node* node); + void getMaxDepthUtil(ui32 depth, ui32& maxDepth) const; + public: - Node* members = nullptr; - ui32 size = 0; + DirectoryTree mMembers; }; \ No newline at end of file diff --git a/inc/Tree.hpp b/inc/Tree.hpp index dae4841..cc0abfe 100644 --- a/inc/Tree.hpp +++ b/inc/Tree.hpp @@ -1,5 +1,8 @@ #pragma once +#include +#include + typedef unsigned long long ui64; typedef unsigned long ui32; typedef long long i64; @@ -63,12 +66,12 @@ public: }; public: - AvlTree() {} + AvlTree() = default; ~AvlTree() { removeAll(); } [[nodiscard]] ui64 size() const { return mSize; } - Node* head() const { return this->mRoot; } + Node* getRoot() const { return this->mRoot; } void insert(KeyArg key, DataArg data) { mRoot = insertUtil(mRoot, key, data); @@ -102,10 +105,10 @@ public: if (!iter) return nullptr; if (iter->exactNode(key)) return iter; if (iter->descentLeft(key)) { - key = iter->keyInLeftSubtree(key); + // key = iter->keyInLeftSubtree(key); iter = iter->mLeft; } else { - key = iter->keyInRightSubtree(key); + // key = iter->keyInRightSubtree(key); iter = iter->mRight; } } @@ -152,7 +155,7 @@ public: } if (head->mLeft && head->mRight) { - if (max(head->mLeft->mHeight, head->mRight->mHeight) != head->mHeight - 1) return head; + if (std::max(head->mLeft->mHeight, head->mRight->mHeight) != head->mHeight - 1) return head; } int balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft); @@ -166,14 +169,22 @@ public: return findInvalidNode(head->mLeft); } - bool isValid() { return findInvalidNode(head()) == nullptr; } + bool isValid() { return findInvalidNode(getRoot()) == nullptr; } template - void traverse(Node* node, bool after, tFunctor functor) { - if (!after) functor(node); - if (node->mLeft) traverse(node->mLeft, after, functor); - if (node->mRight) traverse(node->mRight, after, functor); - if (after) functor(node); + void traverseInorder(Node* node, tFunctor functor) { + if (!node) return; + traverseInorder(node->mLeft, functor); + functor(node); + traverseInorder(node->mRight, functor); + } + + template + void traverseInorder(const Node* node, tFunctor functor) const { + if (!node) return; + traverseInorder(node->mLeft, functor); + functor(node); + traverseInorder(node->mRight, functor); } void removeAll() { @@ -207,7 +218,7 @@ private: // returns new head Node* rotateLeft(Node* pivot) { - DEBUG_ASSERT(pivot); + assert(pivot); Node* const head = pivot; Node* const right = pivot->mRight; @@ -224,8 +235,8 @@ private: right->mLeft = head; // heights - head->mHeight = 1 + max(getNodeHeight(head->mLeft), getNodeHeight(head->mRight)); - right->mHeight = 1 + max(getNodeHeight(right->mLeft), getNodeHeight(right->mRight)); + head->mHeight = 1 + std::max(getNodeHeight(head->mLeft), getNodeHeight(head->mRight)); + right->mHeight = 1 + std::max(getNodeHeight(right->mLeft), getNodeHeight(right->mRight)); // cache head->updateTreeCacheCallBack(); @@ -235,7 +246,7 @@ private: } Node* rotateRight(Node* pivot) { - DEBUG_ASSERT(pivot); + assert(pivot); Node* const head = pivot; Node* const left = pivot->mLeft; @@ -252,8 +263,8 @@ private: left->mRight = head; // heights - head->mHeight = 1 + max(getNodeHeight(head->mLeft), getNodeHeight(head->mRight)); - left->mHeight = 1 + max(getNodeHeight(left->mLeft), getNodeHeight(left->mRight)); + head->mHeight = 1 + std::max(getNodeHeight(head->mLeft), getNodeHeight(head->mRight)); + left->mHeight = 1 + std::max(getNodeHeight(left->mLeft), getNodeHeight(left->mRight)); // cache head->updateTreeCacheCallBack(); @@ -285,7 +296,7 @@ private: } // update height - head->mHeight = 1 + max(getNodeHeight(head->mRight), getNodeHeight(head->mLeft)); + head->mHeight = 1 + std::max(getNodeHeight(head->mRight), getNodeHeight(head->mLeft)); i64 balance = i64(getNodeHeight(head->mRight) - getNodeHeight(head->mLeft)); @@ -342,7 +353,7 @@ private: if (head == nullptr) return head; - head->mHeight = 1 + max(getNodeHeight(head->mRight), getNodeHeight(head->mLeft)); + head->mHeight = 1 + std::max(getNodeHeight(head->mRight), getNodeHeight(head->mLeft)); i64 balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft); if (balance < -1) { diff --git a/src/DirectoryTree.cpp b/src/DirectoryTree.cpp index ae01ae6..88bed33 100644 --- a/src/DirectoryTree.cpp +++ b/src/DirectoryTree.cpp @@ -3,30 +3,25 @@ std::string gError; -void Node::updateTreeCache() { - // TODO update cache -} - -Node::~Node() { - delete left; - delete right; -} +Node::~Node() = default; File::File() { - type = Type::FILE; + mType = Type::FILE; } Link::Link() { - type = LINK; + mType = LINK; +} + +Node *Link::getLink() const { + return mLink; } Directory::Directory() { - type = DIRECTORY; + mType = DIRECTORY; } -Directory::~Directory() { - delete members; -} +Directory::~Directory() = default; bool Directory::attachNode(const std::vector& directoryPath, const Key& newKey, Node* newNode) { Node* node = findNode(directoryPath, 0); @@ -35,21 +30,21 @@ bool Directory::attachNode(const std::vector& directoryPath, const Key& new return false; } - if (node->type != DIRECTORY) { + if (node->mType != DIRECTORY) { gError = "given path is not a directory"; return false; } auto directory = ((Directory*) node); - Node* existingNode = directory->treeSearch(newKey); + Node* existingNode = directory->mMembers.find(DirectoryKey(newKey))->data; if (existingNode) { - if (existingNode->type == newNode->type) return false; // exit silently + if (existingNode->mType == newNode->mType) return false; // exit silently gError = "Cant add node"; return false; } - directory->treeInsert(newKey, newNode); + directory->mMembers.insert(DirectoryKey(newKey), newNode); updateTreeLinkCount(newNode); return true; @@ -61,7 +56,7 @@ Node* Directory::findNode(const std::vector& path, ui32 currentDepth) { } const Key& key = path[currentDepth]; - Node* node = treeSearch(key); + Node* node = mMembers.find(DirectoryKey(key))->data; if (!node) { return nullptr; @@ -69,7 +64,7 @@ Node* Directory::findNode(const std::vector& path, ui32 currentDepth) { // link on link is not allowed while (true) { - switch (node->type) { + switch (node->mType) { case Node::FILE: if (currentDepth == path.size() - 1) return node; return nullptr; @@ -78,7 +73,7 @@ Node* Directory::findNode(const std::vector& path, ui32 currentDepth) { return ((Directory*)node)->findNode(path, ++currentDepth); case Node::LINK: - node = ((Link*)node)->link; + node = ((Link*)node)->getLink(); break; default: @@ -87,158 +82,19 @@ Node* Directory::findNode(const std::vector& path, ui32 currentDepth) { } } -Node* Directory::treeSearch(const Key& key) { - if (!members) return nullptr; - Node* iterator = members; - while (iterator) { - if (key > iterator->key) { - iterator = iterator->right; - } else if (key < iterator->key) { - iterator = iterator->left; - } else { - return iterator; - } - } - return nullptr; -} - void Directory::updateTreeLinkCount(Node* node) { // TODO : update all caches all the way up to '/' } void Directory::detachNode(Node* node) { - // TODO : remove util from avl tree - // TODO : update all cache all the way up to the root (due to the links) - // TODO : dont relocate nodes (due existing links to the nodes), only change tree pointers - members->parent = nullptr; -} - -// TODO : user avl tree insertion -// TODO : check for existing file -// TODO : return true if successful (node inserted) -// TODO : dont relocate nodes (due existing links to the nodes), only change tree pointers -void Directory::treeInsert(const Key& newKey, Node* newNode) { - newNode->key = newKey; - members = insertUtil(members, newKey, newNode); - members->parent = nullptr; -} - -// recursively returns valid isLeft or isRight child or root -Node* Directory::insertUtil(Node* head, const Key& key, Node* aNode) { - - Node* insertedNode; - - if (head == nullptr) { - size++; - aNode->updateTreeCache(); - return aNode; - } else if (head->key == key) { - return head; - } else if (key > head->key) { - insertedNode = insertUtil(head->right, key, aNode); - head->right = insertedNode; - insertedNode->parent = head; - } else { - insertedNode = insertUtil(head->left, key, aNode); - head->left = insertedNode; - insertedNode->parent = head; - } - - // update height - head->height = 1 + std::max(getNodeHeight(head->right), getNodeHeight(head->left)); - - int balance = int(getNodeHeight(head->right) - getNodeHeight(head->left)); - - if (balance > 1) { - if (key > head->right->key) { - return rotateLeft(head); - } else { - head->right = rotateRight(head->right); - return rotateLeft(head); - } - } else if (balance < -1) { - if (key < head->left->key) { - return rotateRight(head); - } else { - head->left = rotateLeft(head->left); - return rotateRight(head); - } - } - - head->updateTreeCache(); - - return head; -} - -// returns new head -Node* Directory::rotateLeft(Node* pivot) { - Node* const head = pivot; - Node* const right = pivot->right; - Node* const right_left = right->left; - Node* const parent = pivot->parent; - - // parents - if (right_left) right_left->parent = head; - head->parent = right; - right->parent = parent; - - // children - head->right = right_left; - right->left = head; - - // heights - head->height = 1 + std::max(getNodeHeight(head->left), getNodeHeight(head->right)); - right->height = 1 + std::max(getNodeHeight(right->left), getNodeHeight(right->right)); - - // cache - head->updateTreeCache(); - right->updateTreeCache(); - - return right; -} - -Node* Directory::rotateRight(Node* pivot) { - Node* const head = pivot; - Node* const left = pivot->left; - Node* const left_right = left->right; - Node* const parent = pivot->parent; - - // parents - if (left_right) left_right->parent = head; - head->parent = left; - left->parent = parent; - - // children - head->left = left_right; - left->right = head; - - // heights - head->height = 1 + std::max(getNodeHeight(head->left), getNodeHeight(head->right)); - left->height = 1 + std::max(getNodeHeight(left->left), getNodeHeight(left->right)); - - // cache - head->updateTreeCache(); - left->updateTreeCache(); - - return left; -} - -ui32 Directory::getNodeHeight(const Node* node) { return node ? node->height : -1; } - -Node* Directory::maxNode() const { - Node* head = members; - if (!head) return nullptr; - while (head->right != nullptr) { - head = head->right; - } - return head; + // mMembers.remove(); } void Directory::getMaxDepthUtil(ui32 depth, ui32& maxDepth) const { - if (!members) return; + if (!mMembers.getRoot()) return; maxDepth = std::max(depth, maxDepth); - traverseInorderUtil(members, [&](Node* node){ - if (node->type == DIRECTORY) { + mMembers.traverseInorder(mMembers.getRoot(), [&](const DirectoryTree::Node* node){ + if (node->data->mType == DIRECTORY) { ((Directory*)node)->getMaxDepthUtil(++depth, maxDepth); } }); diff --git a/src/FileSystem.cpp b/src/FileSystem.cpp index f4f25ae..8956d3d 100644 --- a/src/FileSystem.cpp +++ b/src/FileSystem.cpp @@ -6,7 +6,6 @@ FileSystem::FileSystem() { root = new Directory(); currentDirectory = root; - root->key = "/"; initializeTransitions(); } @@ -64,7 +63,10 @@ void FileSystem::log() const { } -void FileSystem::logNode(std::stringstream& ss, const Node* node, int depth, std::vector& indents) const { +void FileSystem::logNode(std::stringstream& ss, const Node* node, const Key& key, int depth, std::vector& indents) const { + indent(ss, depth, indents); + ss << key << "\n"; + switch (node->type) { case Node::DIRECTORY: return logDirectory(ss, (Directory*) node, depth, indents); @@ -86,24 +88,26 @@ void FileSystem::indent(std::stringstream & ss, int depth, std::vector& in void FileSystem::logDirectory(std::stringstream & ss, const Directory* node, int depth, std::vector& indents) const { ss << (node == currentDirectory ? "* " : " "); indent(ss, depth, indents); - ss << node->key << "\n"; + // ss << node->key << "\n"; indents[depth] = true; depth++; + /* auto lastNode = node->maxNode(); node->traverseInorder([&](const Node* iterNode){ if (lastNode == iterNode) indents[depth - 1] = false; logNode(ss, iterNode, depth, indents); }); + */ } void FileSystem::logFile(std::stringstream& ss, const File* node, int depth, std::vector& indents) const { indent(ss, depth, indents); - ss << node->key << "\n"; + // ss << node->key << "\n"; } void FileSystem::logLink(std::stringstream & ss, const Link* node, int depth, std::vector& indents) const { indent(ss, depth, indents); - ss << "link [" << node->key << "] \n"; + // ss << "link [" << node->key << "] \n"; } const std::string& FileSystem::getLastError() {