error.h 3.46 KB
Newer Older
1
2
3
4
5
6
7
8
#ifndef _MCQTL_ERROR_H_
#define _MCQTL_ERROR_H_

#include <string>
#include <iostream>
#include <set>
#include <utility>
#include <sstream>
9
#include <thread>
Damien Leroux's avatar
Damien Leroux committed
10
#include <mutex>
11
12
13
14
15
16
17
18

#define _WHITE "\x1b[37;1m"
#define _RED "\x1b[31;1m"
#define _YELLOW "\x1b[33;1m"
#define _CYAN "\x1b[36;1m"
#define _NORMAL "\x1b[0;m"

struct msg_handler_t {
19
20
21
    typedef std::recursive_mutex lock_type;
    typedef std::unique_lock<lock_type> scoped_lock_type;

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    struct state_t {
        bool color;
        std::set<std::string> workarounds;
        int count;

        const char* error() { ++count; return color ? _RED : ""; }
        const char* warning() { return color ? _YELLOW : ""; }
        const char* info() { return color ? _CYAN : ""; }
        const char* normal() { return color ? _NORMAL : ""; }

        state_t() : color(true), workarounds(), count(0) {}
        void check(bool fatal);
        void reset();
    };

    static state_t& instance() { static state_t _; return _; }

    static void set_color(bool _) { instance().color = _; }
    static bool color() { return instance().color; }

    static const char* e() { return instance().error(); }
    static const char* w() { return instance().warning(); }
    static const char* i() { return instance().info(); }
    static const char* n() { return instance().normal(); }

    static void check(bool fatal) { instance().check(fatal); }
    static void reset() { instance().reset(); }
49
50

    static lock_type mutex;
51
52
53
54
};


#define ERROR(_msg_expr_, _workaround_expr_) do {\
55
56
    {msg_handler_t::scoped_lock_type _(msg_handler_t::mutex);\
    std::cerr << msg_handler_t::e() << "[ERR] " << _msg_expr_ << msg_handler_t::n() << std::endl;}\
57
58
59
    std::stringstream s; s << _workaround_expr_;\
    if (s.str().size()) { msg_handler_t::instance().workarounds.insert(s.str()); } } while (0)

60
61
62
63
64
65
66
67
68
69
70
#define WARNING(_msg_expr_) do {\
    msg_handler_t::scoped_lock_type _(msg_handler_t::mutex);\
    std::cerr << msg_handler_t::w() << "[WRN] " << _msg_expr_ << msg_handler_t::n() << std::endl; } while(0)

#define INFO(_msg_expr_) do {\
    msg_handler_t::scoped_lock_type _(msg_handler_t::mutex);\
    std::cout << msg_handler_t::i() << "[MSG] " << _msg_expr_ << msg_handler_t::n() << std::endl; } while(0)

#define DEBUG(_msg_expr_) do {\
    msg_handler_t::scoped_lock_type _(msg_handler_t::mutex);\
    std::cout << _msg_expr_ << std::endl; } while(0)
71
72
73
74


inline void msg_handler_t::state_t::check(bool fatal)
{
75
    msg_handler_t::scoped_lock_type _(msg_handler_t::mutex);
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    if (count > 0) {
        std::cerr << info() << "[MSG] " << count;
        if (count > 1) {
            std::cout << " errors were";
        } else {
            std::cout << " error was";
        }
        std::cout << " reported. Suggestions to fix this:" << std::endl;
        for (auto& w: workarounds) {
            std::cout << "      - " << w << std::endl;
        }
        if (fatal) {
            exit(-count);
        } else {
            reset();
        }
        std::cout << normal();
    }
}

inline void msg_handler_t::state_t::reset()
{
    if (workarounds.size()) {
        WARNING(workarounds.size() << " workarounds silently discarded");
    }
    count = 0;
    workarounds.clear();
}

#define WHITE (msg_handler_t::instance().color ? _WHITE : "")
#define YELLOW (msg_handler_t::instance().color ? _YELLOW : "")
#define RED (msg_handler_t::instance().color ? _RED : "")
#define CYAN (msg_handler_t::instance().color ? _CYAN : "")
#define NORMAL (msg_handler_t::instance().color ? _NORMAL : "")

#endif