Version: SMASH-3.4
file.h
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014,2017-2018,2020,2022
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #ifndef SRC_INCLUDE_SMASH_FILE_H_
11 #define SRC_INCLUDE_SMASH_FILE_H_
12 
13 #include <cerrno>
14 #include <cstdio>
15 #include <cstring>
16 #include <filesystem>
17 #include <memory>
18 #include <stdexcept>
19 #include <string>
20 
21 #include "forwarddeclarations.h"
22 
23 namespace smash {
24 
25 /**
26  * FileDeleter is the deleter class for std::unique_ptr of std::FILE.
27  *
28  * std::unique_ptr takes a second template argument which determines what
29  * happens when the resource it holds needs to be freed. The default
30  * implementation calls `delete`. For std::FILE the resource needs to be freed
31  * with a call to std::fclose instead. Therefore FilePtr requires a custom
32  * deleter class to correctly free the resource.
33  */
34 struct FileDeleter {
35  /// The class has no members, so this is a noop.
36  constexpr FileDeleter() = default;
37 
38  /** Frees the std::FILE resource if it is non-zero.
39  *
40  * \param[in] f File resource.
41  * \throws runtime_error if the file could not get closed.
42  */
43  void operator()(std::FILE* f) const {
44  if (f == nullptr) {
45  return;
46  }
47  if (0 != std::fclose(f)) {
48  throw std::runtime_error(std::strerror(errno));
49  }
50  }
51 };
52 
53 /**
54  * A RAII type to replace `std::FILE *`.
55  *
56  * This is an alias type for std::unique_ptr to automatically free the std::FILE
57  * resource after the last reference goes out of scope. It is important to use a
58  * custom deleter type, and therefore SMASH code should never use
59  * std::unique_ptr directly with std::FILE.
60  */
61 using FilePtr = std::unique_ptr<std::FILE, FileDeleter>;
62 
63 /**
64  * A RAII type to replace `std::FILE *`.
65  *
66  * While open, the file name ends with ".unfinished".
67  *
68  * Automatically closes and renames the file to the original when it goes out of
69  * scope. If the object is destroyed because of stack unwinding, no renaming
70  * is done.
71  */
73  public:
74  /**
75  * Construct a `RenamingFilePtr`.
76  *
77  * \param[in] filename Path to the file.
78  * \param[in] mode The mode in which the file should be opened (see
79  * `std::fopen`).
80  * \return The constructed object.
81  */
82  RenamingFilePtr(const std::filesystem::path& filename,
83  const std::string& mode);
84  /// Get the underlying `FILE*` pointer.
85  FILE* get();
86  /// Close the file and rename it.
88 
89  private:
90  /// Internal file pointer.
91  FILE* file_;
92  /// Path of the finished file.
93  std::filesystem::path filename_;
94  /// Path of the unfinished file.
95  std::filesystem::path filename_unfinished_;
96  /**
97  * Number of uncaught exceptions at the time when the object is created.
98  * If it has not changed when the object is destroyed, we suppose that
99  * the contents of the file are reliable and in the destructor we can safely
100  * rename the file and remove the _.unfinished_ suffix.
101  */
102  int uncaught_exceptions_{std::uncaught_exceptions()};
103 };
104 
105 /**
106  * Open a file with given mode.
107  *
108  * This wraps std::fopen but uses FileDeleter to automatically close the file.
109  *
110  * \param[in] filename Path to the file.
111  * \param[in] mode The mode in which the file should be opened (see
112  * `std::fopen`).
113  * \return The constructed `FilePtr`.
114  */
115 FilePtr fopen(const std::filesystem::path& filename, const std::string& mode);
116 
117 } // namespace smash
118 
119 #endif // SRC_INCLUDE_SMASH_FILE_H_
A RAII type to replace std::FILE *.
Definition: file.h:72
~RenamingFilePtr()
Close the file and rename it.
Definition: file.cc:29
std::filesystem::path filename_unfinished_
Path of the unfinished file.
Definition: file.h:95
std::filesystem::path filename_
Path of the finished file.
Definition: file.h:93
FILE * get()
Get the underlying FILE* pointer.
Definition: file.cc:27
RenamingFilePtr(const std::filesystem::path &filename, const std::string &mode)
Construct a RenamingFilePtr.
Definition: file.cc:19
int uncaught_exceptions_
Number of uncaught exceptions at the time when the object is created.
Definition: file.h:102
FILE * file_
Internal file pointer.
Definition: file.h:91
Definition: action.h:24
std::unique_ptr< std::FILE, FileDeleter > FilePtr
A RAII type to replace std::FILE *.
Definition: file.h:61
FilePtr fopen(const std::filesystem::path &filename, const std::string &mode)
Open a file with given mode.
Definition: file.cc:14
FileDeleter is the deleter class for std::unique_ptr of std::FILE.
Definition: file.h:34
constexpr FileDeleter()=default
The class has no members, so this is a noop.
void operator()(std::FILE *f) const
Frees the std::FILE resource if it is non-zero.
Definition: file.h:43