tmp
This commit is contained in:
parent
381a803e78
commit
492ab9d13d
4 changed files with 107 additions and 233 deletions
|
|
@ -1,33 +1,48 @@
|
|||
#pragma once
|
||||
|
||||
#include "Tree.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
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 <typename NodeType>
|
||||
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<DirectoryKey, Node*> DirectoryTree;
|
||||
|
||||
public:
|
||||
Directory();
|
||||
~Directory();
|
||||
~Directory() override;
|
||||
|
||||
bool attachNode(const std::vector<Key>& directoryPath, const Key& newKey, Node* newNode);
|
||||
Node* findNode(const std::vector<Key>& path, ui32 currentDepth = 0);
|
||||
void detachNode(Node* node);
|
||||
|
||||
template<typename tFunctor>
|
||||
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<typename tFunctor>
|
||||
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;
|
||||
};
|
||||
49
inc/Tree.hpp
49
inc/Tree.hpp
|
|
@ -1,5 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
|
||||
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 <typename tFunctor>
|
||||
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 <typename tFunctor>
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -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<Key>& directoryPath, const Key& newKey, Node* newNode) {
|
||||
Node* node = findNode(directoryPath, 0);
|
||||
|
|
@ -35,21 +30,21 @@ bool Directory::attachNode(const std::vector<Key>& 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<Key>& 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<Key>& 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<Key>& 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<Key>& 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);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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<bool>& indents) const {
|
||||
void FileSystem::logNode(std::stringstream& ss, const Node* node, const Key& key, int depth, std::vector<bool>& 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<bool>& in
|
|||
void FileSystem::logDirectory(std::stringstream & ss, const Directory* node, int depth, std::vector<bool>& 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<bool>& 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<bool>& indents) const {
|
||||
indent(ss, depth, indents);
|
||||
ss << "link [" << node->key << "] \n";
|
||||
// ss << "link [" << node->key << "] \n";
|
||||
}
|
||||
|
||||
const std::string& FileSystem::getLastError() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue