1 | /******************************************************************************* |
2 | Copyright (c) The Taichi Authors (2016- ). All Rights Reserved. |
3 | The use of this software is governed by the LICENSE file. |
4 | *******************************************************************************/ |
5 | |
6 | #pragma once |
7 | |
8 | #include "taichi/common/core.h" |
9 | #include <string> |
10 | #include <vector> |
11 | #include <cstdio> |
12 | #include <cstdlib> |
13 | #include <sys/stat.h> |
14 | |
15 | #if defined(TI_PLATFORM_WINDOWS) |
16 | #include <filesystem> |
17 | #else // POSIX |
18 | #include <unistd.h> |
19 | #include <dirent.h> |
20 | #include <sys/types.h> |
21 | #include <sys/stat.h> |
22 | #endif |
23 | |
24 | namespace taichi { |
25 | |
26 | inline bool path_exists(const std::string &dir) { |
27 | struct stat buffer; |
28 | return stat(dir.c_str(), &buffer) == 0; |
29 | } |
30 | |
31 | // TODO: move to std::filesystem after it's nonexperimental on all platforms |
32 | inline void create_directories(const std::string &dir) { |
33 | #if defined(TI_PLATFORM_WINDOWS) |
34 | std::filesystem::create_directories(dir); |
35 | #else |
36 | int return_code = std::system(fmt::format("mkdir -p {}" , dir).c_str()); |
37 | if (return_code != 0) { |
38 | throw std::runtime_error( |
39 | fmt::format("Unable to create directory at: {dir}" ).c_str()); |
40 | } |
41 | #endif |
42 | } |
43 | |
44 | template <typename First, typename... Path> |
45 | inline std::string join_path(First &&path, Path &&...others) { |
46 | if constexpr (sizeof...(others) == 0) { |
47 | return std::string(path); |
48 | } else { |
49 | return std::string(path) + "/" + |
50 | taichi::join_path(std::forward<Path>(others)...); |
51 | } |
52 | return "" ; |
53 | } |
54 | |
55 | inline bool remove(const std::string &path) { |
56 | return std::remove(path.c_str()) == 0; |
57 | } |
58 | |
59 | template <typename Visitor> // void(const std::string &name, bool is_dir) |
60 | inline bool traverse_directory(const std::string &dir, Visitor v) { |
61 | #if defined(TI_PLATFORM_WINDOWS) |
62 | namespace fs = std::filesystem; |
63 | std::error_code ec{}; |
64 | auto iter = fs::directory_iterator(dir, ec); |
65 | if (ec) { |
66 | return false; |
67 | } |
68 | for (auto &f : iter) { |
69 | v(f.path().filename().string(), f.is_directory()); |
70 | } |
71 | return true; |
72 | #else // POSIX |
73 | struct dirent *f = nullptr; |
74 | DIR *directory = ::opendir(dir.c_str()); |
75 | if (!directory) { |
76 | return false; |
77 | } |
78 | while ((f = ::readdir(directory))) { |
79 | auto fullpath = join_path(dir, f->d_name); |
80 | struct stat stat_buf; |
81 | auto ret = ::stat(fullpath.c_str(), &stat_buf); |
82 | TI_ASSERT(ret == 0); |
83 | v(f->d_name, S_ISDIR(stat_buf.st_mode)); |
84 | } |
85 | auto ret = ::closedir(directory); |
86 | TI_ASSERT(ret == 0); |
87 | return true; |
88 | #endif |
89 | } |
90 | |
91 | inline std::string filename_extension(const std::string &filename) { |
92 | std::string postfix; |
93 | auto pos = filename.find_last_of('.'); |
94 | if (pos != std::string::npos) { |
95 | postfix = filename.substr(pos + 1); |
96 | } |
97 | return postfix; |
98 | } |
99 | |
100 | template <typename T> |
101 | void write_to_disk(const T &dat, std::string fn) { |
102 | FILE *f = fopen(fn.c_str(), "wb" ); |
103 | fwrite(&dat, sizeof(dat), 1, f); |
104 | fclose(f); |
105 | } |
106 | |
107 | template <typename T> |
108 | bool read_from_disk(T &dat, std::string fn) { |
109 | FILE *f = fopen(fn.c_str(), "rb" ); |
110 | if (f == nullptr) { |
111 | return false; |
112 | } |
113 | size_t ret = fread(&dat, sizeof(dat), 1, f); |
114 | if (ret != sizeof(dat)) { |
115 | return false; |
116 | } |
117 | fclose(f); |
118 | return true; |
119 | } |
120 | |
121 | template <typename T> |
122 | void write_vector_to_disk(std::vector<T> *p_vec, std::string fn) { |
123 | std::vector<T> &vec = *p_vec; |
124 | FILE *f = fopen(fn.c_str(), "wb" ); |
125 | size_t length = vec.size(); |
126 | fwrite(&length, sizeof(length), 1, f); |
127 | fwrite(&vec[0], sizeof(vec[0]), length, f); |
128 | fclose(f); |
129 | } |
130 | |
131 | template <typename T> |
132 | bool read_vector_from_disk(std::vector<T> *p_vec, std::string fn) { |
133 | std::vector<T> &vec = *p_vec; |
134 | FILE *f = fopen(fn.c_str(), "rb" ); |
135 | if (f == nullptr) { |
136 | return false; |
137 | } |
138 | size_t length; |
139 | size_t ret = fread(&length, sizeof(length), 1, f); |
140 | if (ret != 1) { |
141 | return false; |
142 | } |
143 | vec.resize(length); |
144 | ret = fread(&vec[0], sizeof(vec[0]), length, f); |
145 | if (ret != length) { |
146 | return false; |
147 | } |
148 | fclose(f); |
149 | return true; |
150 | } |
151 | |
152 | } // namespace taichi |
153 | |