NumCpp  2.11.0
A Templatized Header Only C++ Implementation of the Python NumPy Library
BinaryLogger.hpp
Go to the documentation of this file.
1 #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 
44 namespace 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=(BinaryLogger &&)=delete
BinaryLogger(const BinaryLogger &)=delete
BinaryLogger(BinaryLogger &&)=delete
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
BinaryLogger & operator=(const 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
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=(const 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
BinaryDataLogger & operator=(BinaryDataLogger &&)=delete
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()
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