fork download
  1. #include <string>
  2. #include <memory>
  3. #include <vector>
  4. #include <iostream>
  5. #include <functional>
  6. class File;
  7. class Directory;
  8. class Visitor {
  9. public:
  10. virtual ~Visitor() {}
  11. virtual void visit(std::shared_ptr<File>) = 0;
  12. virtual void visit(std::shared_ptr<Directory>) = 0;
  13. virtual void leave(std::shared_ptr<Directory>) = 0;
  14. };
  15. class Entry {
  16. public:
  17. virtual ~Entry() {};
  18. virtual std::string getName() const = 0;
  19. virtual size_t getSize() = 0;
  20. virtual void accept(Visitor &) = 0;
  21. };
  22. class File : public Entry, public std::enable_shared_from_this<File> {
  23. struct this_is_private {};
  24. std::string name;
  25. size_t size;
  26. public:
  27. File(this_is_private, std::string name, size_t size) : name(name), size(size) {}
  28. std::string getName() const override {return name;}
  29. size_t getSize() override {return size;}
  30. void accept(Visitor &v) override {v.visit(shared_from_this());}
  31. static std::shared_ptr<File> create(std::string name, size_t size) {
  32. return std::make_shared<File>(this_is_private(), name, size);
  33. }
  34. };
  35. class Directory : public Entry, public std::enable_shared_from_this<Directory> {
  36. struct this_is_private {};
  37. std::string name;
  38. std::vector<std::shared_ptr<Entry>> es;
  39. public:
  40. Directory(this_is_private, std::string name) : name(name) {}
  41. std::string getName() const override {return name;}
  42. size_t getSize() override {
  43. size_t sum = 0;
  44. for (auto &e : es) sum += e->getSize();
  45. return sum;
  46. }
  47. void accept(Visitor &v) override {
  48. v.visit(shared_from_this());
  49. for (auto &e : es) e->accept(v);
  50. v.leave(shared_from_this());
  51. }
  52. void add(std::shared_ptr<Entry> entry) {es.push_back(entry);}
  53. static std::shared_ptr<Directory> create(std::string name) {
  54. return std::make_shared<Directory>(this_is_private(), name);
  55. }
  56. };
  57. // こっから↑は安定したクラス階層を想定
  58. //////////////////////////////////////////////////////////////////
  59. // こっから↓はVisitor派生クラスを作ることで「新しいオペレーションを簡単に追加できる」とのこと。
  60. class SizeVisitor : public Visitor {
  61. size_t size;
  62. public:
  63. SizeVisitor() : size(0) {};
  64. void visit(std::shared_ptr<File> file) {size += file->getSize();}
  65. void visit(std::shared_ptr<Directory>) {}
  66. void leave(std::shared_ptr<Directory>) {}
  67. size_t getTotalSize() {return size;}
  68. };
  69. class ListVisitor : public Visitor {
  70. std::string cd;
  71. public:
  72. ListVisitor() : cd("") {}
  73. void visit(std::shared_ptr<File> file) {
  74. std::cout << cd << "/" << file->getName() << " (" << file->getSize() << ")" << std::endl;
  75. }
  76. void visit(std::shared_ptr<Directory> dir) {
  77. std::cout << cd << "/" << dir->getName() << " (" << dir->getSize() << ")" << std::endl;
  78. cd += "/" + dir->getName();
  79. }
  80. void leave(std::shared_ptr<Directory> dir) {
  81. cd.resize(cd.length() - 1 - dir->getName().length());
  82. }
  83. };
  84. class FunctionalVisitor : public Visitor {
  85. std::function<void(std::shared_ptr<File>)> vf;
  86. std::function<void(std::shared_ptr<Directory>)> vd, ld;
  87. public:
  88. FunctionalVisitor(
  89. std::function<void(std::shared_ptr<File>)> vf, std::function<void(std::shared_ptr<Directory>)> vd, std::function<void(std::shared_ptr<Directory>)> ld
  90. ) : vf(vf), vd(vd), ld(ld) {}
  91. void visit(std::shared_ptr<File> file) {vf(file);}
  92. void visit(std::shared_ptr<Directory> dir) {vd(dir);}
  93. void leave(std::shared_ptr<Directory> dir) {ld(dir);}
  94. };
  95. int main() {
  96. auto a = Directory::create("a");
  97. auto b = File::create("b.txt", 100);
  98. auto c = File::create("c.txt", 200);
  99. auto d = Directory::create("d");
  100. auto e = File::create("e.txt", 300);
  101. a->add(b);
  102. a->add(c);
  103. a->add(d);
  104. d->add(e);
  105. SizeVisitor sv;
  106. a->accept(sv);
  107. std::cout << "total size: " << sv.getTotalSize() << std::endl;
  108.  
  109. ListVisitor lv;
  110. std::cout << "\nlist: " << std::endl;
  111. a->accept(lv);
  112.  
  113. std::vector<std::string> dirs;
  114. FunctionalVisitor fv(
  115. [&dirs](std::shared_ptr<File> file) {
  116. if (file->getName().find(".txt") != std::string::npos) {
  117. for (auto &d : dirs) std::cout << "/" << d;
  118. std::cout << "/" << file->getName() << std::endl;
  119. }
  120. }
  121. , [&dirs](std::shared_ptr<Directory> dir) {dirs.push_back(dir->getName());}
  122. , [&dirs](std::shared_ptr<Directory> dir) {dirs.pop_back();}
  123. );
  124. std::cout << "\n.txt: " << std::endl;
  125. a->accept(fv);
  126. return 0;
  127. }
  128. /*
  129. ・https://i...content-available-to-author-only...e.com/p3li2Y を元に若干の整理を行った
  130.  
  131. ・make_shared<File>(this)の多重開放?を修正
  132.  std::enable_shared_from_thisを使ってJavaの参照型変数っぽい使用感を得た。
  133.  
  134. ・struct this_is_private {};
  135.  これは単にコンストラクタを実質的にprivateにするためだけに使ってる
  136.  https://e...content-available-to-author-only...e.com/w/cpp/memory/enable_shared_from_this
  137.  https://stackoverflow.com/questions/8147027/how-do-i-call-stdmake-shared-on-a-class-with-only-protected-or-private-const
  138.  このへん参照されたし
  139. */
  140.  
Success #stdin #stdout 0.01s 5284KB
stdin
Standard input is empty
stdout
total size: 600

list: 
/a (600)
/a/b.txt (100)
/a/c.txt (200)
/a/d (300)
/a/d/e.txt (300)

.txt: 
/a/b.txt
/a/c.txt
/a/d/e.txt