Skip to content
Snippets Groups Projects
multi_threading_utils.h 4.31 KiB
#ifndef WOLF_MULTI_THREADING_UTILS_H_
#define WOLF_MULTI_THREADING_UTILS_H_

#include <iostream>
#include <mutex>
#include <chrono>

#include <sys/syscall.h>

namespace wolf
{

namespace core
{
inline long get_thread_id() { return syscall(__NR_gettid); }
}

namespace details
{
using std::chrono::hours;
using std::chrono::minutes;
using std::chrono::seconds;
using std::chrono::milliseconds;
using std::chrono::microseconds;
using std::chrono::nanoseconds;

using wolf_time_unit    = nanoseconds;
using wolf_clock_t      = std::chrono::_V2::high_resolution_clock;
using wolf_time_point_t = std::chrono::time_point<wolf_clock_t, wolf_time_unit>;
using wolf_duration_t   = std::chrono::duration<wolf_clock_t, std::nano>;

const wolf_time_unit zero = wolf_time_unit(0);
const wolf_time_unit min  = std::numeric_limits<wolf_time_unit>::lowest();
const wolf_time_unit max  = std::numeric_limits<wolf_time_unit>::max();
}

/**
  * \brief Return current time in 'unit'.
  * Default nanoseconds.
  * \return long, current time.
  */
template <typename unit = details::wolf_time_unit>
long int getTime()
{
  auto duration_since_epoch_to_now_unit =
      std::chrono::duration_cast<unit>(
        std::chrono::time_point_cast<unit>(
          std::chrono::system_clock::now()
          ).time_since_epoch()
        );

  return static_cast<long int>(duration_since_epoch_to_now_unit.count());
}

namespace io
{

enum class CoutColor
{
  BLACK,
  RED,
  GREEN,
  YELLOW,
  BLUE,
  MAGENTA,
  CYAN,
  WHITE,
  ENDCOLOR
};
inline std::ostream& operator<<(std::ostream& os, CoutColor c)
{
  switch(c)
  {
  // AINSI color codes. Prints bold color.
  case CoutColor::BLACK    : os << "\033[1;30m"; break;
  case CoutColor::RED      : os << "\033[1;31m"; break;
  case CoutColor::GREEN    : os << "\033[1;32m"; break;
  case CoutColor::YELLOW   : os << "\033[1;33m"; break;
  case CoutColor::BLUE     : os << "\033[1;34m"; break;
  case CoutColor::MAGENTA  : os << "\033[1;35m"; break;
  case CoutColor::CYAN     : os << "\033[1;36m"; break;
  case CoutColor::WHITE    : os << "\033[1;37m"; break;
  case CoutColor::ENDCOLOR : os << "\033[0m";    break;
  default                  : os << "\033[0m";
  }
  return os;
}

namespace details
{

static std::mutex the_infamous_cout_mutex;

/**
 * \brief Return current time in nanoseconds.
 * \return Current time formated as string.
 */
inline std::string printTime()
{
  std::string now = std::to_string(getTime()).insert(10, ".");
  return ("[" + now + "]");
}

inline void cout_impl()
{
  std::cout << CoutColor::ENDCOLOR << std::endl;
}

template <typename T>
inline void cout_impl(const T& message)
{
  std::cout << message;
  cout_impl();
}

template <typename T, typename... Args>
inline void cout_impl(const T& message, const Args&... rest)
{
  std::cout << message;
  cout_impl(rest...);
}
} // namespace details

template <typename T, typename... Args>
inline void locked_cout(const T& message, const Args&... rest)
{
  std::lock_guard<std::mutex> lock_cout{details::the_infamous_cout_mutex};
  std::cout << details::printTime() << " " << message;

  details::cout_impl(rest...);
}

template <typename... Args>
inline void locked_cout(const CoutColor& color, const Args&... rest)
{
  std::lock_guard<std::mutex> lock_cout{details::the_infamous_cout_mutex};
  std::cout << color << details::printTime() << " ";

  details::cout_impl(rest...);
}

} // namespace io

#define WOLF_PRINT_COLOR(...) \
  locked_cout(__VA_ARGS__)

#define WOLF_INFO(...) \
  locked_cout(wolf::io::CoutColor::ENDCOLOR, __VA_ARGS__)

#define WOLF_WARN(...) \
  locked_cout(wolf::io::CoutColor::MAGENTA, __VA_ARGS__)

#define WOLF_ERROR(...) \
  locked_cout(wolf::io::CoutColor::RED, __VA_ARGS__)

#define WOLF_PRINT_COLOR_COND(cond, ...) \
  if (cond) locked_cout(__VA_ARGS__)

#define WOLF_INFO_COND(cond, ...) \
  if (cond) locked_cout(cond, wolf::io::CoutColor::ENDCOLOR, __VA_ARGS__)

#define WOLF_WARN_COND(...) \
  if (cond) locked_cout(cond, wolf::io::CoutColor::MAGENTA, __VA_ARGS__)

#define WOLF_ERROR_COND(...) \
  if (cond) locked_cout(cond, wolf::io::CoutColor::RED, __VA_ARGS__)

// I need to define some custom debugging
// flag (e.g. WOLFDEBUG) that I can pass to
// gcc through cmake.
#if 0
  #define WOLF_DEBUG(...)
#else
  #define WOLF_DEBUG(...) \
  locked_cout(wolf::io::CoutColor::CYAN, __VA_ARGS__)
#endif

} // namespace wolf

#endif /* WOLF_MULTI_THREADING_UTILS_H_ */