diff --git a/.clang-tidy b/.clang-tidy index 2badda7..a864159 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -25,7 +25,8 @@ Checks: > -modernize-use-auto, -modernize-use-nodiscard, -modernize-use-trailing-return-type, - -readability-named-parameter + -readability-named-parameter, + -readability-redundant-declaration CheckOptions: readability-identifier-length.IgnoredParameterNames: 'ec|to' diff --git a/include/tmp/directory b/include/tmp/directory index 2aa5fb9..29f4406 100644 --- a/include/tmp/directory +++ b/include/tmp/directory @@ -9,9 +9,13 @@ #include #include #include +#include namespace tmp { +extern "C++" std::filesystem::path create_directory(std::string_view prefix); +extern "C++" void remove_all(const std::filesystem::path& path) noexcept; + /// tmp::directory is a smart handle that manages a temporary directory, /// ensuring its recursive deletion when the handle goes out of scope /// @@ -45,7 +49,29 @@ public: /// @param prefix A prefix to add to the temporary directory name /// @throws std::filesystem::filesystem_error if cannot create a directory /// @throws std::invalid_argument if the prefix contains a directory separator - explicit directory(std::string_view prefix = ""); + explicit directory(std::string_view prefix = "") + : pathobject(create_directory(prefix)) {} + + directory(const directory&) = delete; + directory& operator=(const directory&) = delete; + + /// Moves the ownership of the directory managed by `other` to a new handle + /// @note After the move, `other` is not associated with a directory + /// @param other Another directory that will be moved from + directory(directory&& other) noexcept + : pathobject(std::exchange(other.pathobject, std::filesystem::path())) {} + + /// Deletes the managed temporary directory, then moves the ownership + /// of the directory managed by `other` to `this` + /// @note After the assignment, `other` is not associated with a directory + /// @param other Another directory that will be moved from + /// @returns `*this` + directory& operator=(directory&& other) noexcept { + remove_all(*this); + pathobject = std::exchange(other.pathobject, std::filesystem::path()); + + return *this; + } /// Returns the path of this directory /// @returns The full path of this directory @@ -67,12 +93,9 @@ public: } /// Deletes this directory recursively - ~directory() noexcept; - - directory(directory&&) noexcept; - directory& operator=(directory&&) noexcept; - directory(const directory&) = delete; - directory& operator=(const directory&) = delete; + ~directory() noexcept { + remove_all(*this); + } private: /// This directory path diff --git a/src/abi.hpp b/src/abi.hpp index 7127151..ea6a7aa 100644 --- a/src/abi.hpp +++ b/src/abi.hpp @@ -4,6 +4,9 @@ #ifndef TMP_ABI_H #define TMP_ABI_H +#include +#include + #ifdef _WIN32 #define abi __declspec(dllexport) #else @@ -12,7 +15,9 @@ namespace tmp { -class abi directory; +std::filesystem::path abi create_directory(std::string_view prefix); +void abi remove_all(const std::filesystem::path& path) noexcept; + class abi file; } // namespace tmp diff --git a/src/directory.cpp b/src/directory.cpp index c7a20c4..636a633 100644 --- a/src/directory.cpp +++ b/src/directory.cpp @@ -22,11 +22,10 @@ namespace tmp { namespace { - namespace fs = std::filesystem; /// Checks if the given prefix is valid to attach to a temporary directory name -/// @param[in] prefix The prefix to check validity for +/// @param prefix The prefix to check validity for /// @returns `true` if the prefix is valid, `false` otherwise bool is_prefix_valid(const fs::path& prefix) { // We also need to check that the prefix does not contain a root path @@ -38,7 +37,7 @@ bool is_prefix_valid(const fs::path& prefix) { #ifdef _WIN32 /// Creates a temporary path with the given prefix /// @note prefix must be valid -/// @param[in] prefix A prefix to attach to the path pattern +/// @param prefix A prefix to attach to the path pattern /// @returns A unique temporary path fs::path make_path(std::string_view prefix) { GUID guid; @@ -61,9 +60,10 @@ fs::path make_path(std::string_view prefix) { return path; } #endif +} // namespace /// Creates a temporary directory in the current user's temporary directory -/// @param[in] prefix A prefix to attach to the temporary directory name +/// @param prefix A prefix to attach to the temporary directory name /// @returns A path to the created temporary directory /// @throws fs::filesystem_error if cannot create a temporary directory /// @throws std::invalid_argument if the prefix contains a directory separator @@ -95,38 +95,20 @@ fs::path create_directory(std::string_view prefix) { return path; } -/// Deletes a directory recursively, ignoring any errors -/// @param[in] directory The directory to delete -void remove_directory(const directory& directory) noexcept { +/// Deletes a path recursively, ignoring any errors +/// @param path The path to delete +void remove_all(const fs::path& path) noexcept { try { - if (!directory.path().empty()) { + if (!path.empty()) { // Calling the `std::error_code` overload of `fs::remove_all` should be // more optimal here since it would not require creating // a `fs::filesystem_error` message before we suppress the exception std::error_code ec; - fs::remove_all(directory, ec); + fs::remove_all(path, ec); } } catch (...) { // Do nothing: if we failed to delete the temporary directory, // the system should do it later } } -} // namespace - -directory::directory(std::string_view prefix) - : pathobject(create_directory(prefix)) {} - -directory::~directory() noexcept { - remove_directory(*this); -} - -directory::directory(directory&& other) noexcept - : pathobject(std::exchange(other.pathobject, fs::path())) {} - -directory& directory::operator=(directory&& other) noexcept { - remove_directory(*this); - - pathobject = std::exchange(other.pathobject, fs::path()); - return *this; -} } // namespace tmp