PixelBullet  0.0.1
A C++ game engine
Loading...
Searching...
No Matches
path.h
1#pragma once
2
3#include <algorithm>
4#include <cctype>
5#include <filesystem>
6#include <string>
7#include <vector>
8
9namespace pixelbullet::filesystem
10{
11[[nodiscard]] inline std::filesystem::path normalized_path(const std::filesystem::path& path)
12{
13 std::filesystem::path normalized = path.lexically_normal();
14 while (!normalized.empty() && !normalized.has_filename())
15 {
16 const std::filesystem::path parent = normalized.parent_path();
17 if (parent.empty() || parent == normalized)
18 {
19 break;
20 }
21 normalized = parent;
22 }
23 return normalized;
24}
25
26[[nodiscard]] inline std::string normalized_path_key(const std::filesystem::path& path)
27{
28 std::string key = normalized_path(path).generic_string();
29#ifdef _WIN32
30 for (char& value : key)
31 {
32 value = static_cast<char>(std::tolower(static_cast<unsigned char>(value)));
33 }
34#endif
35 return key;
36}
37
38[[nodiscard]] inline bool paths_equal(const std::filesystem::path& lhs, const std::filesystem::path& rhs)
39{
40 return normalized_path_key(lhs) == normalized_path_key(rhs);
41}
42
43[[nodiscard]] inline bool path_is_within(const std::filesystem::path& path, const std::filesystem::path& directory)
44{
45 if (path.empty() || directory.empty())
46 {
47 return false;
48 }
49
50 const std::filesystem::path normalized_target = normalized_path(path);
51 const std::filesystem::path normalized_directory = normalized_path(directory);
52 auto target_it = normalized_target.begin();
53 for (auto directory_it = normalized_directory.begin(); directory_it != normalized_directory.end(); ++directory_it, ++target_it)
54 {
55 if (target_it == normalized_target.end() || normalized_path_key(*target_it) != normalized_path_key(*directory_it))
56 {
57 return false;
58 }
59 }
60
61 return true;
62}
63
64inline void normalize_sort_unique_paths(std::vector<std::filesystem::path>& paths)
65{
66 for (std::filesystem::path& path : paths)
67 {
68 path = normalized_path(path);
69 }
70
71 std::sort(paths.begin(), paths.end(),
72 [](const std::filesystem::path& lhs, const std::filesystem::path& rhs)
73 {
74 const std::string lhs_key = normalized_path_key(lhs);
75 const std::string rhs_key = normalized_path_key(rhs);
76 if (lhs_key != rhs_key)
77 {
78 return lhs_key < rhs_key;
79 }
80 return lhs.generic_string() < rhs.generic_string();
81 });
82 paths.erase(std::unique(paths.begin(), paths.end(),
83 [](const std::filesystem::path& lhs, const std::filesystem::path& rhs) { return paths_equal(lhs, rhs); }),
84 paths.end());
85}
86} // namespace pixelbullet::filesystem