|
| 1 | +#include <utility> // std::move, std::pair, std::make_pair |
| 2 | +#include <vector> // std::vector |
| 3 | +#include <string> // std::string |
| 4 | +#include <string_view> // std::string_view |
1 | 5 | #include "CxxNodeApiHostModule.hpp" |
2 | 6 | #include "Logger.hpp" |
3 | 7 |
|
4 | 8 | using namespace facebook; |
5 | 9 |
|
| 10 | +namespace { |
| 11 | + |
| 12 | +// NOTE: behaves like `explode()` in PHP |
| 13 | +std::vector<std::string_view> explodePath(const std::string_view &path) { |
| 14 | + std::vector<std::string_view> parts; |
| 15 | + for (size_t pos = 0; std::string_view::npos != pos; /* no-op */) { |
| 16 | + if (const size_t nextPos = path.find('/', pos); std::string_view::npos != nextPos) { |
| 17 | + parts.emplace_back(path.substr(pos, nextPos - pos)); |
| 18 | + pos = nextPos + 1; |
| 19 | + } else { |
| 20 | + if (std::string_view &&part = path.substr(pos); !part.empty()) { |
| 21 | + // Paths ending with `/` are as if there was a tailing dot `/.` |
| 22 | + // therefore the last `/` can be safely removed |
| 23 | + parts.emplace_back(part); |
| 24 | + } |
| 25 | + break; |
| 26 | + } |
| 27 | + } |
| 28 | + return parts; |
| 29 | +} |
| 30 | + |
| 31 | +// NOTE: Absolute paths would have the first part empty, relative would have a name |
| 32 | +std::string implodePath(const std::vector<std::string_view> &parts) { |
| 33 | + std::string joinedPath; |
| 34 | + for (size_t i = 0; i < parts.size(); ++i) { |
| 35 | + if (i > 0) { |
| 36 | + joinedPath += '/'; |
| 37 | + } |
| 38 | + joinedPath += parts[i]; |
| 39 | + } |
| 40 | + return joinedPath; |
| 41 | +} |
| 42 | + |
| 43 | +// NOTE: Returned path does not include the `/` at the end of the string |
| 44 | +// NOTE: For some cases this cannot be a view: `getParentPath("..")` => "../.." |
| 45 | +void makeParentPathInplace(std::vector<std::string_view> &parts) { |
| 46 | + if (!parts.empty() && ".." != parts.back()) { |
| 47 | + const bool wasDot = "." == parts.back(); |
| 48 | + parts.pop_back(); |
| 49 | + if (wasDot && parts.empty()) { |
| 50 | + parts.emplace_back(".."); |
| 51 | + } |
| 52 | + } else { |
| 53 | + parts.emplace_back(".."); |
| 54 | + } |
| 55 | +} |
| 56 | + |
| 57 | +std::vector<std::string_view> simplifyPath(const std::vector<std::string_view> &parts) { |
| 58 | + std::vector<std::string_view> result; |
| 59 | + if (!parts.empty()) { |
| 60 | + for (const auto &part : parts) { |
| 61 | + if ("." == part && !result.empty()) { |
| 62 | + continue; // We only allow for a single `./` at the beginning |
| 63 | + } else if (".." == part) { |
| 64 | + makeParentPathInplace(result); |
| 65 | + } else { |
| 66 | + result.emplace_back(part); |
| 67 | + } |
| 68 | + } |
| 69 | + } else { |
| 70 | + result.emplace_back("."); // Empty path is as if it was "." |
| 71 | + } |
| 72 | + return result; |
| 73 | +} |
| 74 | + |
| 75 | +std::string joinPath(const std::string_view &baseDir, const std::string_view &rest) { |
| 76 | + auto pathComponents = simplifyPath(explodePath(baseDir)); |
| 77 | + auto restComponents = simplifyPath(explodePath(rest)); |
| 78 | + for (auto &&part : restComponents) { |
| 79 | + if (".." == part) { |
| 80 | + makeParentPathInplace(pathComponents); |
| 81 | + } else if (!part.empty() && "." != part) { |
| 82 | + pathComponents.emplace_back(part); |
| 83 | + } |
| 84 | + } |
| 85 | + return implodePath(pathComponents); |
| 86 | +} |
| 87 | + |
| 88 | +std::pair<std::string_view, std::string_view> |
| 89 | +rpartition(const std::string_view &input, char delimiter) { |
| 90 | + if (const size_t pos = input.find_last_of(delimiter); std::string_view::npos != pos) { |
| 91 | + const auto head = std::string_view(input).substr(0, pos); |
| 92 | + const auto tail = std::string_view(input).substr(pos + 1); |
| 93 | + return std::make_pair(head, tail); |
| 94 | + } else { |
| 95 | + return std::make_pair(std::string_view(), input); |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +} // namespace |
| 100 | + |
6 | 101 | namespace callstack::nodeapihost { |
7 | 102 |
|
8 | 103 | CxxNodeApiHostModule::CxxNodeApiHostModule( |
|
0 commit comments