/*******************************************************************************
 *
 * File:     debug.hpp
 *
 * Contents: Facility for debugging
 *
 * Copyright 2017
 *
 * Author: David Juhasz (david.juhasz@tuwien.ac.at)
 *
 ******************************************************************************/

#ifndef _ROSA__SUPPORT_DEBUG_HPP_
#define _ROSA__SUPPORT_DEBUG_HPP_

#include "rosa/support/types.hpp"
#include <ostream>
#include <array>

namespace rosa {

// Returns an output stream to use for debugging.
std::ostream &dbgs(void);

// Prints an array to the ostream.
template <typename T, size_t size>
std::ostream &operator<<(std::ostream &os, const std::array<T, size> &arr) {
  os << '[';
  for (unsigned i = 0; i < size; ++i) {
    if (i) {
      os << ',';
    }
    os << (PRINTABLE(T)) arr[i];
  }
  os << ']';
  return os;
}

} // End namespace rosa

#ifndef ROSA_ENABLE_ASSERTIONS
#define ASSERT(unused) static_cast<void>(0)
#elif defined(ROSA_WINDOWS)
#define ASSERT(stmt)                                                           \
  if (static_cast<bool>(stmt) == false) {                                      \
    rosa::dbgs() << __FILE__ << ":" << __LINE__ << ": requirement failed '"    \
                 << #stmt << "'" << std::endl;                                 \
    ::abort();                                                                 \
  }                                                                            \
  static_cast<void>(0)
#else // defined(ROSA_LINUX)
#include <execinfo.h>
#define ASSERT(stmt)                                                           \
  if (static_cast<bool>(stmt) == false) {                                      \
    rosa::dbgs() << __FILE__ << ":" << __LINE__ << ": requirement failed '"    \
                 << #stmt << "'" << std::endl;                                 \
    void *array[20];                                                           \
    auto bt_size = ::backtrace(array, 20);                                     \
    ::backtrace_symbols_fd(array, bt_size, 2);                                 \
    ::abort();                                                                 \
  }                                                                            \
  static_cast<void>(0)
#endif // defined(ROSA_ENABLE_ASSERTIONS)

#ifndef NDEBUG
#define DEBUG(X)                                                               \
  do {                                                                         \
    X;                                                                         \
  } while (0)
#define DEBUGVAR(V)                                                            \
  do {                                                                         \
    rosa::dbgs() << #V << " (" << __FILE__ << ":" << __LINE__ << "): " << (V)  \
                 << std::endl;                                                 \
  } while (0)
#else // defined(NDEBUG)
#define DEBUG(X) static_cast<void>(0)
#define DEBUGVAR(X) static_cast<void>(0)
#endif // defined(NDEBUG)

#endif // _ROSA__SUPPORT_DEBUG_HPP_

