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

#include <string>
#include <iostream>
#include <set>
#include <utility>
#include <sstream>
9
#include <thread>
Damien Leroux's avatar
Damien Leroux committed
10
#include <mutex>
11
#include <vector>
12
13
14
extern "C" {
#include <unistd.h>
}
15
16
17
18
19
20
21

#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"

22
23
#define MSG_HANDLER_IS_SYNCED

24
struct msg_handler_t {
25
#ifdef MSG_HANDLER_IS_SYNCED
26
27
    typedef std::recursive_mutex lock_type;
    typedef std::unique_lock<lock_type> scoped_lock_type;
28
29
30
31
32
33
34
35
36
#else
    typedef struct {
        void lock() {}
        void unlock() {}
    } lock_type;
    typedef struct _slt {
        _slt(lock_type&) {}
    } scoped_lock_type;
#endif
37

38
39
40
41
    struct state_t {
        bool color;
        std::set<std::string> workarounds;
        int count;
42
        std::vector<std::function<void()>> hooks;
43
44
45
46
47
48

        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 : ""; }

49
        state_t() : color(!!isatty(fileno(stdout))), workarounds(), count(0) {}
50
		~state_t() {}
51
52
        void check(bool fatal);
        void reset();
53
        void run_hooks() { for (auto& f: hooks) { f(); } }
54
55
56
57
58
59
60
61
62
63
64
65
66
67
    };

    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(); }
68

69
70
71
    static void hook(std::function<void()>&& f) { instance().hooks.push_back(f); }
    static void run_hooks() { instance().run_hooks(); }

72
    static lock_type mutex;
73
74
75
};


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
#define MSG_ERROR(_msg_expr_, _workaround_expr_) \
    do {\
        {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;}\
        std::stringstream s; s << _workaround_expr_;\
        if (s.str().size()) { msg_handler_t::instance().workarounds.insert(s.str()); }\
        msg_handler_t::run_hooks();\
} while (0)

#define MSG_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;\
        msg_handler_t::run_hooks();\
    } while(0)

#define MSG_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;\
        msg_handler_t::run_hooks();\
    } while(0)

#define MSG_DEBUG(_msg_expr_) \
    do {\
        msg_handler_t::scoped_lock_type _(msg_handler_t::mutex);\
        std::cout << _msg_expr_ << std::endl;\
        msg_handler_t::run_hooks();\
    } while(0)
105
106
107
108


inline void msg_handler_t::state_t::check(bool fatal)
{
109
    msg_handler_t::scoped_lock_type _(msg_handler_t::mutex);
110
111
112
113
114
115
116
117
118
119
120
121
    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) {
122
			std::cout << normal() << "At least one fatal error encountered. Aborting process." << std::endl;
123
124
125
126
127
128
129
130
131
132
133
            exit(-count);
        } else {
            reset();
        }
        std::cout << normal();
    }
}

inline void msg_handler_t::state_t::reset()
{
    if (workarounds.size()) {
134
        MSG_WARNING(workarounds.size() << " workarounds silently discarded");
135
136
137
138
139
140
141
142
143
144
145
    }
    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 : "")

146
147
148
149
150
151
#ifdef NDEBUG
#define DUMP_FILE_LINE()
#else
#define DUMP_FILE_LINE() MSG_DEBUG(__FILE__ << ':' << __LINE__)
#endif

152
153
#endif