Skip to content

Commit

Permalink
add get relative directory method
Browse files Browse the repository at this point in the history
  • Loading branch information
ggeorgiev committed Jun 4, 2016
1 parent 1500f6e commit a4e09e5
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 57 deletions.
58 changes: 40 additions & 18 deletions src/doim/fs/fs_directory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,15 @@ FsDirectorySPtr traceDirectory(Trace&& trace,
if (next != pos || parent == nullptr)
{
string name(pos, next);
if (name == kParentDirectoryString)
if (name.empty())
{
if (parent == nullptr)
{
const auto& current = FsDirectory::make(parent, name);
parent = trace(current);
}
}
else if (name == kParentDirectoryString)
{
if (parent == nullptr)
return nullptr;
Expand Down Expand Up @@ -89,35 +97,49 @@ FsDirectorySPtr FsDirectory::corresponding(const FsDirectorySPtr& directory,
return obtain(parent, directory->name());
}

FsDirectorySPtr FsDirectory::commonAncestor(const FsDirectorySPtr& directory) const
FsRelativeDirectorySPtr FsDirectory::relative(const FsDirectorySPtr& directory) const
{
if (directory == nullptr)
if (directory.get() == this)
return nullptr;

FsDirectorySPtr line1 = directory;
FsRelativeDirectorySPtr current;
FsDirectorySPtr fca = firstCommonAncestor(directory);

if (fca != nullptr)
{
if (fca->parent() == nullptr && fca != directory)
{
current = FsRelativeDirectory::unique(nullptr, "");
}
else
{
auto levels = (directory != nullptr ? directory->level() : 0) - fca->level();
for (auto i = 0; i < levels; ++i)
current = FsRelativeDirectory::unique(current, "..");
}
}

while (line1->level() > level())
line1 = line1->parent();
if (fca.get() == this)
return current;

if (line1.get() == this)
return line1;
return relative(fca, current);
}

FsDirectoryRCPtr line2 = this;
while (line1->level() < line2->level())
line2 = line2->parent().get();
FsRelativeDirectorySPtr FsDirectory::relative(
const FsDirectorySPtr& directory, const FsRelativeDirectorySPtr& current) const
{
if (parent() == nullptr)
return FsRelativeDirectory::unique(nullptr, "");

while (line1.get() != line2)
{
line1 = line1->parent();
line2 = line2->parent().get();
}
if (parent() == directory)
return FsRelativeDirectory::unique(current, name());

return line1;
return FsRelativeDirectory::unique(parent()->relative(directory, current), name());
}

string FsDirectory::path(const FsDirectorySPtr& directory) const
{
FsDirectorySPtr base = commonAncestor(directory);
FsDirectorySPtr base = firstCommonAncestor(directory);

string path;
if (base != nullptr)
Expand Down
7 changes: 5 additions & 2 deletions src/doim/fs/fs_directory.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include "doim/fs/fs_relative_directory.h"
#include "doim/tree/string_tree_node.hpp"
#include "doim/element.hpp"
#include "doim/set.hpp"
Expand All @@ -24,6 +25,7 @@ typedef shared_ptr<FsDirectorySet> FsDirectorySetSPtr;
class FsDirectory : public StringTreeNode<FsDirectory, '/'>
{
public:
using StringTreeNode<FsDirectory, '/'>::find;
static FsDirectorySPtr find(const FsDirectorySPtr& base,
const string_view& directory);

Expand All @@ -43,16 +45,17 @@ class FsDirectory : public StringTreeNode<FsDirectory, '/'>
return ancestor();
}

using StringTreeNode<FsDirectory, '/'>::find;
FsRelativeDirectorySPtr relative(const FsDirectorySPtr& directory) const;

FsDirectorySPtr commonAncestor(const FsDirectorySPtr& directory) const;
string path(const FsDirectorySPtr& directory = nullptr) const;

// This is almost the same as path, but in case the current and the root directories
// are the same instead of empty string it will return '.'
string nonEmptyPath(const FsDirectorySPtr& directory) const;

private:
FsRelativeDirectorySPtr relative(const FsDirectorySPtr& directory,
const FsRelativeDirectorySPtr& relative) const;
void calculate(FsDirectoryRPtr directory, size_t length, string& path) const;
};
}
11 changes: 0 additions & 11 deletions src/doim/fs/fs_relative_directory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,4 @@

namespace doim
{
FsRelativeDirectory::FsRelativeDirectory()
: TreeNode(FsRelativeDirectorySPtr(), string())
{
}

FsRelativeDirectory::FsRelativeDirectory(const FsRelativeDirectorySPtr& parent,
const string& name)
: TreeNode(parent, name)
{
ASSERT(parent->isUnique());
}
}
14 changes: 3 additions & 11 deletions src/doim/fs/fs_relative_directory.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#pragma once

#include "doim/tree/tree_node.hpp"
#include "doim/tree/string_tree_node.hpp"
#include "doim/element.hpp"
#include "doim/set.hpp"
#include <memory>
Expand All @@ -17,17 +17,9 @@ namespace doim
class FsRelativeDirectory;
typedef shared_ptr<FsRelativeDirectory> FsRelativeDirectorySPtr;

class FsRelativeDirectory : public TreeNode<FsRelativeDirectory, string>
class FsRelativeDirectory : public StringTreeNode<FsRelativeDirectory, '/'>
{
public:
using TreeNode<FsRelativeDirectory, string>::find;

FsRelativeDirectory();
FsRelativeDirectory(const FsRelativeDirectorySPtr& parent, const string& name);

const string& name() const
{
return std::get<1>(mArgs);
}
using StringTreeNode<FsRelativeDirectory, '/'>::StringTreeNode;
};
}
25 changes: 13 additions & 12 deletions src/doim/gtest/fs/fs_directory-utest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ TEST(FsDirectoryTest, level)
TEST(FsDirectoryTest, commonAncestor)
{
auto root = doim::FsDirectory::unique(nullptr, "");
ASSERT_EQ(root, root->commonAncestor(root));
ASSERT_EQ(root, root->firstCommonAncestor(root));

auto foo = doim::FsDirectory::make(root, "foo");
ASSERT_EQ(root, root->commonAncestor(foo));
ASSERT_EQ(root, foo->commonAncestor(root));
ASSERT_EQ(root, root->firstCommonAncestor(foo));
ASSERT_EQ(root, foo->firstCommonAncestor(root));

auto bar = doim::FsDirectory::make(root, "bar");
ASSERT_EQ(root, bar->commonAncestor(foo));
ASSERT_EQ(root, bar->firstCommonAncestor(foo));
}

TEST(FsDirectoryTest, obtainEmpty)
Expand Down Expand Up @@ -123,19 +123,20 @@ TEST(FsDirectoryTest, obtain)

for (const auto& test : tests)
{
SCOPED_TRACE("root:" + test.root);
SCOPED_TRACE("dir:" + test.dir);
SCOPED_TRACE("absolute:" + test.absolute);
SCOPED_TRACE("relative:" + test.relative);
SCOPED_TRACE("relative: \"" + test.relative + "\"");
SCOPED_TRACE("absolute: \"" + test.absolute + "\"");
SCOPED_TRACE("dir: \"" + test.dir + "\"");
SCOPED_TRACE("root: \"" + test.root + "\"");

const auto& root = doim::FsDirectory::obtain(nullptr, test.root);
const auto& directory = doim::FsDirectory::obtain(root, test.dir);
ASSERT_NE(nullptr, directory);

ASSERT_EQ(test.absolute, directory->path()) << "root: \"" << test.root
<< "\", dir: \"" << test.dir << "\"";
ASSERT_EQ(test.relative, directory->path(root))
<< "root: \"" << test.root << "\", dir: \"" << test.dir << "\"";
ASSERT_EQ(test.absolute, directory->path());
ASSERT_EQ(test.relative, directory->path(root));

const auto& relative = directory->relative(root);
ASSERT_EQ(test.relative, relative == nullptr ? "" : relative->toString());
}
}

Expand Down
8 changes: 5 additions & 3 deletions src/doim/tree/string_tree_node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,18 @@ class StringTreeNode : public TreeNode<T, string>

using TreeNode<T, string>::TreeNode;

using TreeNode<T, string>::ancestor;

const string& name() const
{
return std::get<1>(TreeNode<T, string>::mArgs);
}

string toString() const
{
if (TreeNode<T, string>::ancestor() == nullptr)
return name();
return TreeNode<T, string>::ancestor()->toString() + delimiter() + name();
if (ancestor() == nullptr)
return name() + delimiter();
return ancestor()->toString() + name() + delimiter();
}
};
}
26 changes: 26 additions & 0 deletions src/doim/tree/tree_node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,32 @@ class TreeNode : public Element<T, shared_ptr<T>, Args...>
return std::get<0>(Element<T, shared_ptr<T>, Args...>::mArgs);
}

shared_ptr<T> firstCommonAncestor(const shared_ptr<T>& other) const
{
if (other == nullptr)
return nullptr;

shared_ptr<T> line1 = other;

while (line1->level() > level())
line1 = line1->ancestor();

if (line1.get() == this)
return line1;

const TreeNode* line2 = this;
while (line1->level() < line2->level())
line2 = line2->ancestor().get();

while (line1.get() != line2)
{
line1 = line1->ancestor();
line2 = line2->ancestor().get();
}

return line1;
}

private:
size_t mLevel = 1;
};
Expand Down

0 comments on commit a4e09e5

Please sign in to comment.