Output.hpp 4.67 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma once

#include <iostream>
#include <string>

/**
 * \def AMDIS_NO_THROW
 * \brief The preprocessor constant sets whether to use c-asserts (if defined) or
 * to throw an exception in case of an error (if not defined).
 **/
#ifdef AMDIS_NO_THROW
  #include <cassert>
#else
  #include <stdexcept>
#endif

17
#ifdef HAVE_MPI
18
19
20
  #include <mpi.h>
#endif

21
22
23
24
/// Use the formatting librart fmtlib::fmt
#include <fmt/core.h>
#include <fmt/ostream.h>

25
26
#include <amdis/common/TypeTraits.hpp>

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/**
 * \def AMDIS_ENABLE_MSG_DBG
 * \brief The preprocessor constant enables the functions \ref AMDiS::MSG_DBG
 * and \ref AMDiS::TEST_EXIT_DBG.
 *
 * If the value is set to 1 the functions \ref AMDiS::MSG_DBG and \ref AMDiS::TEST_EXIT_DBG
 * are implemented, otherwise empty. Default is value 0 if \ref NDEBUG is not
 * defined, otherwise value 1.
 **/
#ifndef AMDIS_ENABLE_MSG_DBG
  #ifndef NDEBUG
    #define AMDIS_ENABLE_MSG_DBG 1
  #else
    #define AMDIS_ENABLE_MSG_DBG 0
  #endif
#endif

#define AMDIS_UNUSED(var) __attribute__((unused)) var

#define AMDIS_FUNCNAME(nn) AMDIS_UNUSED(const char *funcName); funcName = nn;

#ifdef NDEBUG
  #define AMDIS_FUNCNAME_DBG(nn)
  #define AMDIS_DBG_VAR(var)
#else
  #define AMDIS_FUNCNAME_DBG(nn) AMDIS_UNUSED(const char *funcName); funcName = nn;
  #define AMDIS_DBG_VAR(var) var
#endif


namespace AMDiS
{
  namespace Impl
  {
    template <class OStream, class... Args>
    OStream& msg(OStream& out, Args&&... args)
    {
#ifdef AMDIS_HAS_MPI
      int rank = -1;
      int num_ranks = -1;
      MPI_Comm_rank(MPI_COMM_WORLD, &rank);
      MPI_Comm_size(MPI_COMM_WORLD, &num_ranks);
      if (num_ranks > 1 && rank == 0) {
70
        out << "[0] ";
71
        fmt::print(out, FWD(args)...);
72
      } else if (num_ranks == 1) {
73
        fmt::print(out, FWD(args)...);
74
75
      }
#else
76
      fmt::print(out, FWD(args)...);
77
78
79
80
81
82
83
84
85
86
87
#endif
      return out;
    }

  } // end namespace Impl


  /// \brief print a message
  /**
   * Example:
   * ```
88
   * msg("Hello {}: {}", "World", 123); // prints "Hello World: 123\n"
89
90
91
92
93
   * ```
   **/
  template <class... Args>
  void msg(Args&&... args)
  {
94
    Impl::msg(std::cout, FWD(args)...) << std::endl;
95
96
97
98
99
100
101
  }


  /// \brief print a message (without appended newline)
  /**
   * Example:
   * ```
102
   * msg_("Hello {}: {}", "World", 123); // prints "Hello World: 123"
103
104
105
106
107
   * ```
   **/
  template <class... Args>
  void msg_(Args&&... args)
  {
108
    Impl::msg(std::cout, FWD(args)...);
109
110
111
112
113
114
115
116
117
118
119
120
121
  }


  /// \brief print a message and exit
  /**
   * If the preprocessor constant \ref AMDIS_NO_THROW is defined,
   * the c-assert macro is called, otherwise an exception of
   * type \ref std::runtime_Error is thrown.
   **/
  template <class... Args>
  void error_exit(Args&&... args)
  {
#ifdef AMDIS_NO_THROW
122
    Impl::msg(std::cerr << "ERROR: ", FWD(args)...) << std::endl;
123
124
125
126
127
128
    #ifndef NDEBUG
      assert(false);
    #else
      std::exit(EXIT_FAILURE);
    #endif
#else
129
    throw std::runtime_error( std::string("ERROR: ") + fmt::format(FWD(args)...));
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#endif
  }


  /// \brief test for condition and in case of failure print message and exit
  /**
   * This function is equivalent to
   * ```
   * if (condition == false) error_exit(text);
   * ```
   * where `text` correspond to the arguments passed after the
   * \p condition argument.
   **/
  template <class... Args>
  void test_exit(bool condition, Args&&... args)
  {
146
    if (!condition) { error_exit(FWD(args)...); }
147
148
149
150
151
152
  }


  template <class... Args>
  void warning(Args&&... args)
  {
153
    Impl::msg(std::cout << "WARNING: ", FWD(args)...) << std::endl;
154
155
156
157
158
159
160
161
162
163
164
165
  }


  /// \brief test for condition and in case of failure print message
  /**
   * Same as \ref TEST_EXIT but does not throw an exception, or call assert.
   * It just tests for the condition and prints a message with prepended
   * string "WARNING".
   **/
  template <class... Args>
  void test_warning(bool condition, Args&&... args)
  {
166
    if (!condition) { warning(FWD(args)...); }
167
168
169
170
171
172
173
174
175
176
  }


#if AMDIS_ENABLE_MSG_DBG
  /// \brief print message, in debug mode only
  /**
   * Same as \ref MSG, but is available only if preprocessor constant
   * \ref AMDIS_ENABLE_MSG_DBG is set to 1, otherwise the function is empty.
   **/
  template <class... Args>
177
  void msg_dbg(Args&&... args) { msg(FWD(args)...); }
178
179
180
181
182
183
184
185
186
187


  /// \brief call assert_msg, in debug mode only
  /**
   * Same as \ref TEST_EXIT, but is available only if preprocessor constant
   * \ref AMDIS_ENABLE_MSG_DBG is set to 1, otherwise the function is empty.
   **/
  template <class... Args>
  void test_exit_dbg(bool condition, Args&&... args)
  {
188
    test_exit(condition, FWD(args)...);
189
190
191
192
193
194
195
196
197
198
  }
#else
  template <class... Args>
  void msg_dbg(Args&&...) {}

  template <class... Args>
  void test_exit_dbg(bool, Args&&...) {}
#endif

} // end namespace AMDiS