| // Copyright 2023 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef DIAGNOSTICS_BASE_PATH_LITERAL_H_ | |
| #define DIAGNOSTICS_BASE_PATH_LITERAL_H_ | |
| #include <algorithm> | |
| #include <array> | |
| #include <cstddef> | |
| #include <string> | |
| #include <vector> | |
| #include <base/files/file_path.h> | |
| #include <brillo/brillo_export.h> | |
| namespace diagnostics { | |
| // A helper class to define constexpr paths with concatenation supports. Use | |
| // `MakePathLiteral` helper function to create literals. | |
| // E.g. | |
| // constexpr auto kMyPath = MakePathLiteral("a", "b", "c"); | |
| // constexpr auto kMyFile = MakePathLiteral(kMyPath, "myfile"); | |
| // | |
| template <std::size_t Size> | |
| class StaticPathLiteral; | |
| class BRILLO_EXPORT PathLiteral { | |
| public: | |
| PathLiteral(const char** tokens, std::size_t size); | |
| template <std::size_t Size> | |
| PathLiteral(StaticPathLiteral<Size> path); // NOLINT(runtime/explicit) | |
| PathLiteral(const PathLiteral&) = delete; | |
| PathLiteral& operator=(const PathLiteral&) = delete; | |
| ~PathLiteral(); | |
| // Returns relative paths by join each tokens. | |
| base::FilePath ToPath() const; | |
| // Same as above but return std::string. | |
| std::string ToStr() const; | |
| // Returns full paths from root directory. | |
| base::FilePath ToFull() const; | |
| private: | |
| std::vector<const char*> tokens_; | |
| }; | |
| template <std::size_t Size> | |
| class StaticPathLiteral { | |
| static_assert(Size >= 1); | |
| public: | |
| constexpr explicit StaticPathLiteral( | |
| const std::array<const char*, Size>& tokens) | |
| : tokens_(tokens) {} | |
| StaticPathLiteral(const StaticPathLiteral&) = default; | |
| StaticPathLiteral& operator=(const StaticPathLiteral&) = default; | |
| ~StaticPathLiteral() = default; | |
| constexpr std::array<const char*, Size> tokens() const { return tokens_; } | |
| base::FilePath ToPath() const { return PathLiteral(*this).ToPath(); } | |
| std::string ToStr() const { return PathLiteral(*this).ToStr(); } | |
| base::FilePath ToFull() const { return PathLiteral(*this).ToFull(); } | |
| private: | |
| std::array<const char*, Size> tokens_; | |
| }; | |
| template <std::size_t Size> | |
| PathLiteral::PathLiteral(StaticPathLiteral<Size> path) | |
| : PathLiteral(path.tokens().data(), path.tokens().size()) {} | |
| template <std::size_t Size> | |
| constexpr auto MakePathLiteral(const std::array<const char*, Size>& base) { | |
| return StaticPathLiteral<Size>(base); | |
| } | |
| template <std::size_t Size, typename... Types> | |
| constexpr auto MakePathLiteral(const std::array<const char*, Size>& base, | |
| const char* token, | |
| Types... rest) { | |
| std::array<const char*, Size + 1> res; | |
| std::copy(base.begin(), base.end(), res.begin()); | |
| res.back() = token; | |
| return MakePathLiteral(res, rest...); | |
| } | |
| template <std::size_t S1, std::size_t S2, typename... Types> | |
| constexpr auto MakePathLiteral(const std::array<const char*, S1>& base, | |
| const StaticPathLiteral<S2>& path, | |
| Types... rest) { | |
| std::array<const char*, S1 + S2> res; | |
| std::copy(base.begin(), base.end(), res.begin()); | |
| std::array<const char*, S2> tokens = path.tokens(); | |
| std::copy(tokens.begin(), tokens.end(), res.begin() + S1); | |
| return MakePathLiteral(res, rest...); | |
| } | |
| template <std::size_t Size, typename... Types> | |
| constexpr auto MakePathLiteral(const StaticPathLiteral<Size>& base, | |
| Types... rest) { | |
| return MakePathLiteral(base.tokens(), rest...); | |
| } | |
| template <typename... Types> | |
| constexpr auto MakePathLiteral(const char* token, Types... rest) { | |
| std::array<const char*, 1> base; | |
| base[0] = token; | |
| return MakePathLiteral(base, rest...); | |
| } | |
| } // namespace diagnostics | |
| #endif // DIAGNOSTICS_BASE_PATH_LITERAL_H_ |