ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
file_handle.hpp
1// This file is part of the ACTS project.
2//
3// Copyright (C) 2016 CERN for the benefit of the ACTS project
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9#pragma once
10
11// Project include(s)
12#include "detray/io/utils/create_path.hpp"
13#include "detray/utils/logging.hpp"
14
15// System include(s)
16#include <cassert>
17#include <cstdint>
18#include <filesystem>
19#include <fstream>
20#include <ios>
21#include <iostream>
22#include <limits>
23#include <sstream>
24#include <stdexcept>
25#include <string>
26
27namespace detray::io {
28
42class file_handle final {
43 public:
45 file_handle() = delete;
46
50 explicit file_handle(const std::string& file_name,
51 std::ios_base::openmode mode = std::ios_base::in |
52 std::ios_base::out)
53 : file_handle(std::filesystem::path{file_name}.parent_path() /
54 std::filesystem::path{file_name}.stem(),
55 std::filesystem::path{file_name}.extension(), mode) {}
56
61 file_handle(const std::string& name, const std::string& extension,
62 std::ios_base::openmode mode = std::ios_base::in |
63 std::ios_base::out) {
64 // File name
65 std::string file_name{name};
66
67 // Pure output mode without replacement of file: Check if name is taken
68 // and modify it if necessary
69 if (mode == std::ios_base::out ||
70 (mode == (std::ios_base::out | std::ios_base::binary))) {
71 // Default name for output
72 file_name =
73 name.empty() ? "./detray_" + std::to_string(n_files) : file_name;
74
75 // Does the file stem need to be adjusted (in case the file exists)?
76 std::string new_name = io::alt_file_name(file_name + extension);
77 auto new_path = std::filesystem::path{new_name};
78 file_name = new_path.parent_path() / new_path.stem();
79
80 // Pure input mode: Check if file name makes sense and file exists
81 } else if ((mode == std::ios_base::in) ||
82 (mode == (std::ios_base::in | std::ios_base::binary))) {
83 if (file_name.empty()) {
84 std::stringstream err_str{};
85 err_str << "File name empty";
86
87 DETRAY_FATAL_HOST(err_str.str());
88 throw std::invalid_argument(err_str.str());
89 }
90
91 std::filesystem::path file_path{file_name + extension};
92 if (!std::filesystem::exists(file_path)) {
93 std::stringstream err_str{};
94 err_str << "Could not open file: File does not exist: " << file_name
95 << extension;
96
97 DETRAY_FATAL_HOST(err_str.str());
98 throw std::invalid_argument(err_str.str());
99 }
100 } else if (file_name.empty()) {
101 DETRAY_VERBOSE_HOST("Empty file name");
102 }
103
104 // Count the new file
105 const std::string file_path{file_name + extension};
106 ++n_files;
107 ++n_open_files;
108 if (n_files >= std::numeric_limits<std::uint_least16_t>::max()) {
109 std::stringstream err_str{};
110 err_str << "Could not open file: Too many files written: " << file_path;
111
112 DETRAY_FATAL_HOST(err_str.str());
113 throw std::runtime_error(err_str.str());
114 } else if (n_open_files >= 1000u) {
115 std::stringstream err_str{};
116 err_str << "Could not open file: Too many files currently open: "
117 << file_path;
118
119 DETRAY_FATAL_HOST(err_str.str());
120 throw std::runtime_error(err_str.str());
121 }
122
123 // Open file
124 m_stream.open(file_path, mode);
125
126 if (!m_stream.is_open()) {
127 std::stringstream err_str{};
128 err_str << "Could not open file: " << file_path;
129
130 DETRAY_FATAL_HOST(err_str.str());
131 throw std::runtime_error(err_str.str());
132 }
133 }
134
137 if (m_stream.bad()) {
138 DETRAY_ERROR_HOST("Could not read from/write to file");
139 }
140 try {
141 m_stream.close();
142 } catch (std::fstream::failure& err) {
143 DETRAY_ERROR_HOST("Could not properly close file:\n" << err.what());
144 }
145 --n_open_files;
146 }
147
149 std::fstream& operator*() { return m_stream; }
150
151 private:
153 std::fstream m_stream;
154
156 inline static std::size_t n_files{0u};
157 inline static std::size_t n_open_files{0u};
158};
159
160} // namespace detray::io
std::fstream & operator*()
Definition file_handle.hpp:149
file_handle()=delete
All writers must define a file name.
~file_handle()
Destructor closes the file.
Definition file_handle.hpp:136
file_handle(const std::string &name, const std::string &extension, std::ios_base::openmode mode=std::ios_base::in|std::ios_base::out)
File gets created with a name and extension.
Definition file_handle.hpp:61
file_handle(const std::string &file_name, std::ios_base::openmode mode=std::ios_base::in|std::ios_base::out)
Open the file at the supplied path.
Definition file_handle.hpp:50
The following enums are global for all detectors.
Definition concepts.hpp:18
std::string alt_file_name(const std::string &name)
Find an unused numbered alternative to an existing file name.
Definition create_path.hpp:31