NumCpp  2.12.1
A Templatized Header Only C++ Implementation of the Python NumPy Library
BinaryLogger.hpp
Go to the documentation of this file.
1
28#pragma once
29
30#ifndef NUMCPP_NO_USE_BOOST
31
32#include <algorithm>
33#include <filesystem>
34#include <fstream>
35#include <stdexcept>
36#include <string>
37#include <string_view>
38#include <type_traits>
39#include <typeinfo>
40
41#include "boost/algorithm/string.hpp"
42#include "boost/core/demangle.hpp"
43
44namespace nc::logger
45{
46 namespace detail
47 {
48 namespace type_traits
49 {
53 template<typename DataType>
54 using serialize_t = decltype(std::declval<DataType>().serialize());
55
59 template<typename DataType, typename = std::void_t<>>
60 class has_serialize : std::false_type
61 {
62 public:
63 static constexpr bool value = false;
64 };
65
69 template<typename DataType>
70 class has_serialize<DataType,
71 std::void_t<std::enable_if_t<std::is_same_v<serialize_t<DataType>, std::string>, int>>>
72 {
73 public:
74 static constexpr bool value = true;
75 };
76
80 template<typename DataType>
82 } // namespace type_traits
83
87 template<typename DataType>
89 {
90 public:
91 using value_type = DataType;
92 using const_pointer = const DataType* const;
93 using const_reference = const DataType&;
94
95 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, hicpp-avoid-c-arrays, modernize-avoid-c-arrays)
96 static constexpr char LOG_EXT[] = ".log";
97 static constexpr auto DATA_ELEMENT_SIZE = sizeof(value_type);
98 static constexpr auto DATE_TYPE_HAS_SERIALIZE_METHOD = type_traits::has_serialize_v<value_type>;
99
104
109 explicit BinaryDataLogger(std::filesystem::path outputDir)
110 {
111 setOutputDir(outputDir);
112 }
113
118 explicit BinaryDataLogger(std::string_view outputDir) :
119 BinaryDataLogger(std::filesystem::path(outputDir))
120 {
121 }
122
127 {
128 ofile_.close();
129 }
130
131 // explicitly delete
136
140 const std::filesystem::path& filepath() const noexcept
141 {
142 return filepath_;
143 }
144
150 void setOutputDir(std::filesystem::path outputDir)
151 {
152 if (std::filesystem::is_directory(outputDir))
153 {
154 auto dataTypeName = boost::core::demangle(typeid(DataType).name());
155 boost::algorithm::replace_all(dataTypeName, "::", "_");
156 boost::algorithm::replace_all(dataTypeName, "<", "_");
157 boost::algorithm::replace_all(dataTypeName, ">", "_");
158 const auto filename = std::filesystem::path(dataTypeName).replace_extension(LOG_EXT);
159 filepath_ = std::filesystem::canonical(outputDir) / filename;
160
161 ofile_ = std::ofstream(filepath_.c_str(), std::ios::out | std::ios::binary);
162 if (!ofile_.good())
163 {
164 throw std::runtime_error("Unable to open the log file:\n\t" + filepath_.string());
165 }
166 }
167 else
168 {
169 throw std::runtime_error("The provided output log directory is not valid:\n\t" +
170 outputDir.string());
171 }
172 }
173
179 void setOutputDir(std::string_view outputDir)
180 {
181 setOutputDir(std::filesystem::path(outputDir));
182 }
183
187 void enable() noexcept
188 {
189 enabled_ = true;
190 }
191
195 void disable() noexcept
196 {
197 enabled_ = false;
198 }
199
203 bool isEnabled() noexcept
204 {
205 return enabled_;
206 }
207
211 void flush()
212 {
213 ofile_.flush();
214 }
215
220 void log(const_reference dataElement)
221 {
222 if (!enabled_)
223 {
224 return;
225 }
226
227 if (filepath_.empty())
228 {
229 throw std::runtime_error("The output log directory does not exist");
230 }
231
232 if constexpr (DATE_TYPE_HAS_SERIALIZE_METHOD)
233 {
234 const auto serializedData = dataElement.serialize();
235 ofile_.write(serializedData.data(), serializedData.size());
236 }
237 else
238 {
239 ofile_.write(reinterpret_cast<const char*>(&dataElement), DATA_ELEMENT_SIZE);
240 }
241 }
242
248 void log(const_pointer dataElements, std::size_t numElements)
249 {
250 if (!enabled_)
251 {
252 return;
253 }
254
255 if (filepath_.empty())
256 {
257 throw std::runtime_error("The output log directory does not exist");
258 }
259
260 std::for_each(dataElements,
261 dataElements + numElements,
262 [this](const_reference dataElement) { log(dataElement); });
263 }
264
265 private:
266 std::filesystem::path filepath_{};
267 std::ofstream ofile_;
268 bool enabled_{ true };
269 };
270 } // namespace detail
271
276 {
277 public:
278 // explicitly delete
279 BinaryLogger(const BinaryLogger&) = delete;
283
289 static BinaryLogger& getInstance() noexcept
290 {
291 static BinaryLogger binaryLogger;
292 return binaryLogger;
293 }
294
301 void setOutputDir(const std::filesystem::path& outputDir)
302 {
303 if (!std::filesystem::is_directory(outputDir))
304 {
305 throw std::runtime_error("outputDir does not exist");
306 }
307
308 outputDir_ = outputDir;
309 }
310
317 void setOutputDir(std::string_view outputDir)
318 {
319 setOutputDir(std::filesystem::path(outputDir));
320 }
321
327 template<typename DataType>
329 {
330 static detail::BinaryDataLogger<DataType> typeLogger(outputDir_);
331 return typeLogger;
332 }
333
334 private:
335 std::filesystem::path outputDir_{ "." };
336
340 BinaryLogger() = default;
341 };
342} // namespace nc::logger
343
344#endif // #ifndef NUMCPP_NO_USE_BOOST
Binary Logger Singleton.
Definition: BinaryLogger.hpp:276
void setOutputDir(std::string_view outputDir)
Sets the output directory. This should be called BEFORE any type loggers have been created,...
Definition: BinaryLogger.hpp:317
BinaryLogger & operator=(const BinaryLogger &)=delete
BinaryLogger(const BinaryLogger &)=delete
BinaryLogger(BinaryLogger &&)=delete
BinaryLogger & operator=(BinaryLogger &&)=delete
void setOutputDir(const std::filesystem::path &outputDir)
Sets the output directory. This should be called BEFORE any type loggers have been created,...
Definition: BinaryLogger.hpp:301
detail::BinaryDataLogger< DataType > & getTypeLogger()
Gets the logger instance for the specific data type.
Definition: BinaryLogger.hpp:328
static BinaryLogger & getInstance() noexcept
Singleton instance getter.
Definition: BinaryLogger.hpp:289
Binary Logger.
Definition: BinaryLogger.hpp:89
BinaryDataLogger()
Default constructor.
Definition: BinaryLogger.hpp:103
static constexpr char LOG_EXT[]
Definition: BinaryLogger.hpp:96
BinaryDataLogger(std::string_view outputDir)
Constructor.
Definition: BinaryLogger.hpp:118
void log(const_reference dataElement)
Logs the data element.
Definition: BinaryLogger.hpp:220
bool isEnabled() noexcept
Checks whether logger is enabled.
Definition: BinaryLogger.hpp:203
BinaryDataLogger & operator=(BinaryDataLogger &&)=delete
const std::filesystem::path & filepath() const noexcept
The log file path.
Definition: BinaryLogger.hpp:140
const DataType *const const_pointer
Definition: BinaryLogger.hpp:92
void setOutputDir(std::filesystem::path outputDir)
Sets the output log directory.
Definition: BinaryLogger.hpp:150
DataType value_type
Definition: BinaryLogger.hpp:91
void disable() noexcept
Disable the logger.
Definition: BinaryLogger.hpp:195
static constexpr auto DATE_TYPE_HAS_SERIALIZE_METHOD
Definition: BinaryLogger.hpp:98
BinaryDataLogger & operator=(const BinaryDataLogger &)=delete
~BinaryDataLogger()
Destructor.
Definition: BinaryLogger.hpp:126
BinaryDataLogger(const BinaryDataLogger &)=delete
BinaryDataLogger(std::filesystem::path outputDir)
Constructor.
Definition: BinaryLogger.hpp:109
BinaryDataLogger(BinaryDataLogger &&)=delete
const DataType & const_reference
Definition: BinaryLogger.hpp:93
static constexpr auto DATA_ELEMENT_SIZE
Definition: BinaryLogger.hpp:97
void log(const_pointer dataElements, std::size_t numElements)
Logs the data elements.
Definition: BinaryLogger.hpp:248
void flush()
Force a flush of the output stream.
Definition: BinaryLogger.hpp:211
void enable() noexcept
Enable the logger.
Definition: BinaryLogger.hpp:187
void setOutputDir(std::string_view outputDir)
Sets the output log directory.
Definition: BinaryLogger.hpp:179
type trait to check if a type has a serialize method with the correct signature
Definition: BinaryLogger.hpp:61
static constexpr bool value
Definition: BinaryLogger.hpp:63
decltype(std::declval< DataType >().serialize()) serialize_t
type trait to check if a type has a serialize method with the correct signature
Definition: BinaryLogger.hpp:54
constexpr bool has_serialize_v
type trait to check if a type has a serialize method with the correct signature
Definition: BinaryLogger.hpp:81
Definition: BinaryLogger.hpp:45
void for_each(InputIt first, InputIt last, UnaryFunction f)
Definition: StlAlgorithms.hpp:225