1 // Copyright (C) 2003  Davis E. King (davis@dlib.net)
2 // License: Boost Software License   See LICENSE.txt for the full license.
3 #ifndef DLIB_ERROr_
4 #define DLIB_ERROr_
5 
6 #include <string>
7 #include <new>          // for std::bad_alloc
8 #include <iostream>
9 #include <cassert>
10 #include <cstdlib>
11 #include <exception>
12 
13 // -------------------------------
14 // ------ exception classes ------
15 // -------------------------------
16 
17 namespace dlib
18 {
19 
20 // ----------------------------------------------------------------------------------------
21 
22     enum error_type
23     {
24         EPORT_IN_USE,
25         ETIMEOUT,
26         ECONNECTION,
27         ELISTENER,
28         ERESOLVE,
29         EMONITOR,
30         ECREATE_THREAD,
31         ECREATE_MUTEX,
32         ECREATE_SIGNALER,
33         EUNSPECIFIED,
34         EGENERAL_TYPE1,
35         EGENERAL_TYPE2,
36         EGENERAL_TYPE3,
37         EINVALID_OPTION,
38         ETOO_FEW_ARGS,
39         ETOO_MANY_ARGS,
40         ESOCKET,
41         ETHREAD,
42         EGUI,
43         EFATAL,
44         EBROKEN_ASSERT,
45         EIMAGE_LOAD,
46         EDIR_CREATE,
47         EINCOMPATIBLE_OPTIONS,
48         EMISSING_REQUIRED_OPTION,
49         EINVALID_OPTION_ARG,
50         EMULTIPLE_OCCURANCES,
51         ECONFIG_READER,
52         EIMAGE_SAVE,
53         ECAST_TO_STRING,
54         ESTRING_CAST,
55         EUTF8_TO_UTF32,
56         EOPTION_PARSE
57     };
58 
59 // ----------------------------------------------------------------------------------------
60 
61     // the base exception class
62     class error : public std::exception
63     {
64         /*!
65             WHAT THIS OBJECT REPRESENTS
66                 This is the base exception class for the dlib library.  i.e. all
67                 exceptions in this library inherit from this class.
68         !*/
69 
70     public:
error(error_type t,const std::string & a)71         error(
72             error_type t,
73             const std::string& a
74         ): info(a), type(t) {}
75         /*!
76             ensures
77                 - #type == t
78                 - #info == a
79         !*/
80 
error(error_type t)81         error(
82             error_type t
83         ): type(t) {}
84         /*!
85             ensures
86                 - #type == t
87                 - #info == ""
88         !*/
89 
error(const std::string & a)90         error(
91             const std::string& a
92         ): info(a), type(EUNSPECIFIED) {}
93         /*!
94             ensures
95                 - #type == EUNSPECIFIED
96                 - #info == a
97         !*/
98 
error()99         error(
100         ): type(EUNSPECIFIED) {}
101         /*!
102             ensures
103                 - #type == EUNSPECIFIED
104                 - #info == ""
105         !*/
106 
~error()107         virtual ~error(
108         ) throw() {}
109         /*!
110             ensures
111                 - does nothing
112         !*/
113 
what()114         const char* what(
115         ) const throw()
116         /*!
117             ensures
118                 - if (info.size() != 0) then
119                     - returns info.c_str()
120                 - else
121                     - returns type_to_string(type)
122         !*/
123         {
124             if (info.size() > 0)
125                 return info.c_str();
126             else
127                 return type_to_string();
128         }
129 
type_to_string()130         const char* type_to_string (
131         ) const throw()
132         /*!
133             ensures
134                 - returns a string that names the contents of the type member.
135         !*/
136         {
137             if ( type == EPORT_IN_USE) return "EPORT_IN_USE";
138             else if ( type == ETIMEOUT) return "ETIMEOUT";
139             else if ( type == ECONNECTION) return "ECONNECTION";
140             else if ( type == ELISTENER) return "ELISTENER";
141             else if ( type == ERESOLVE) return "ERESOLVE";
142             else if ( type == EMONITOR) return "EMONITOR";
143             else if ( type == ECREATE_THREAD) return "ECREATE_THREAD";
144             else if ( type == ECREATE_MUTEX) return "ECREATE_MUTEX";
145             else if ( type == ECREATE_SIGNALER) return "ECREATE_SIGNALER";
146             else if ( type == EUNSPECIFIED) return "EUNSPECIFIED";
147             else if ( type == EGENERAL_TYPE1) return "EGENERAL_TYPE1";
148             else if ( type == EGENERAL_TYPE2) return "EGENERAL_TYPE2";
149             else if ( type == EGENERAL_TYPE3) return "EGENERAL_TYPE3";
150             else if ( type == EINVALID_OPTION) return "EINVALID_OPTION";
151             else if ( type == ETOO_FEW_ARGS) return "ETOO_FEW_ARGS";
152             else if ( type == ETOO_MANY_ARGS) return "ETOO_MANY_ARGS";
153             else if ( type == ESOCKET) return "ESOCKET";
154             else if ( type == ETHREAD) return "ETHREAD";
155             else if ( type == EGUI) return "EGUI";
156             else if ( type == EFATAL) return "EFATAL";
157             else if ( type == EBROKEN_ASSERT) return "EBROKEN_ASSERT";
158             else if ( type == EIMAGE_LOAD) return "EIMAGE_LOAD";
159             else if ( type == EDIR_CREATE) return "EDIR_CREATE";
160             else if ( type == EINCOMPATIBLE_OPTIONS) return "EINCOMPATIBLE_OPTIONS";
161             else if ( type == EMISSING_REQUIRED_OPTION) return "EMISSING_REQUIRED_OPTION";
162             else if ( type == EINVALID_OPTION_ARG) return "EINVALID_OPTION_ARG";
163             else if ( type == EMULTIPLE_OCCURANCES) return "EMULTIPLE_OCCURANCES";
164             else if ( type == ECONFIG_READER) return "ECONFIG_READER";
165             else if ( type == EIMAGE_SAVE) return "EIMAGE_SAVE";
166             else if ( type == ECAST_TO_STRING) return "ECAST_TO_STRING";
167             else if ( type == ESTRING_CAST) return "ESTRING_CAST";
168             else if ( type == EUTF8_TO_UTF32) return "EUTF8_TO_UTF32";
169             else if ( type == EOPTION_PARSE) return "EOPTION_PARSE";
170             else return "undefined error type";
171         }
172 
173         const std::string info;  // info about the error
174         const error_type type; // the type of the error
175 
176     private:
177         const error& operator=(const error&);
178     };
179 
180 // ----------------------------------------------------------------------------------------
181 
182     class fatal_error : public error
183     {
184         /*!
185             WHAT THIS OBJECT REPRESENTS
186                 As the name says, this object represents some kind of fatal error.
187                 That is, it represents an unrecoverable error and any program that
188                 throws this exception is, by definition, buggy and needs to be fixed.
189 
190                 Note that a fatal_error exception can only be thrown once.  The second
191                 time an application attempts to construct a fatal_error it will be
192                 immediately aborted and an error message will be printed to std::cerr.
193                 The reason for this is because the first fatal_error was apparently ignored
194                 so the second fatal_error is going to make itself impossible to ignore
195                 by calling abort.  The lesson here is that you should not try to ignore
196                 fatal errors.
197 
198                 This is also the exception thrown by the DLIB_ASSERT and DLIB_CASSERT macros.
199         !*/
200 
201     public:
fatal_error(error_type t,const std::string & a)202         fatal_error(
203             error_type t,
204             const std::string& a
205         ): error(t,a) {check_for_previous_fatal_errors();}
206         /*!
207             ensures
208                 - #type == t
209                 - #info == a
210         !*/
211 
fatal_error(error_type t)212         fatal_error(
213             error_type t
214         ): error(t) {check_for_previous_fatal_errors();}
215         /*!
216             ensures
217                 - #type == t
218                 - #info == ""
219         !*/
220 
fatal_error(const std::string & a)221         fatal_error(
222             const std::string& a
223         ): error(EFATAL,a) {check_for_previous_fatal_errors();}
224         /*!
225             ensures
226                 - #type == EFATAL
227                 - #info == a
228         !*/
229 
fatal_error()230         fatal_error(
231         ): error(EFATAL) {check_for_previous_fatal_errors();}
232         /*!
233             ensures
234                 - #type == EFATAL
235                 - #info == ""
236         !*/
237 
238     private:
239 
message()240         static inline char* message ()
241         {
242             static char buf[2000];
243             buf[1999] = '\0'; // just to be extra safe
244             return buf;
245         }
246 
dlib_fatal_error_terminate()247         static inline void dlib_fatal_error_terminate (
248         )
249         {
250             std::cerr << "\n**************************** FATAL ERROR DETECTED ****************************";
251             std::cerr << message() << std::endl;
252             std::cerr << "******************************************************************************\n" << std::endl;
253         }
254 
check_for_previous_fatal_errors()255         void check_for_previous_fatal_errors()
256         {
257             // If dlib is being use to create plugins for some other application, like
258             // MATLAB, then don't do these checks since it terminates the over arching
259             // system.  Just let the errors go to the plugin handler and it will deal with
260             // them.
261 #if defined(MATLAB_MEX_FILE) || defined(DLIB_NO_ABORT_ON_2ND_FATAL_ERROR)
262             return;
263 #else
264             static bool is_first_fatal_error = true;
265             if (is_first_fatal_error == false)
266             {
267                 std::cerr << "\n\n ************************** FATAL ERROR DETECTED ************************** " << std::endl;
268                 std::cerr << " ************************** FATAL ERROR DETECTED ************************** " << std::endl;
269                 std::cerr << " ************************** FATAL ERROR DETECTED ************************** \n" << std::endl;
270                 std::cerr << "Two fatal errors have been detected, the first was inappropriately ignored. \n"
271                           << "To prevent further fatal errors from being ignored this application will be \n"
272                           << "terminated immediately and you should go fix this buggy program.\n\n"
273                           << "The error message from this fatal error was:\n" << this->what() << "\n\n" << std::endl;
274                 using namespace std;
275                 assert(false);
276                 abort();
277             }
278             else
279             {
280                 // copy the message into the fixed message buffer so that it can be recalled by dlib_fatal_error_terminate
281                 // if needed.
282                 char* msg = message();
283                 unsigned long i;
284                 for (i = 0; i < 2000-1 && i < this->info.size(); ++i)
285                     msg[i] = info[i];
286                 msg[i] = '\0';
287 
288                 // set this termination handler so that if the user doesn't catch this dlib::fatal_error that is being
289                 // thrown then it will eventually be printed to standard error
290                 std::set_terminate(&dlib_fatal_error_terminate);
291             }
292             is_first_fatal_error = false;
293 #endif
294         }
295     };
296 
297 // ----------------------------------------------------------------------------------------
298 
299     class gui_error : public error
300     {
301     public:
gui_error(error_type t,const std::string & a)302         gui_error(
303             error_type t,
304             const std::string& a
305         ): error(t,a) {}
306         /*!
307             ensures
308                 - #type == t
309                 - #info == a
310         !*/
311 
gui_error(error_type t)312         gui_error(
313             error_type t
314         ): error(t) {}
315         /*!
316             ensures
317                 - #type == t
318                 - #info == ""
319         !*/
320 
gui_error(const std::string & a)321         gui_error(
322             const std::string& a
323         ): error(EGUI,a) {}
324         /*!
325             ensures
326                 - #type == EGUI
327                 - #info == a
328         !*/
329 
gui_error()330         gui_error(
331         ): error(EGUI) {}
332         /*!
333             ensures
334                 - #type == EGUI
335                 - #info == ""
336         !*/
337     };
338 
339 // ----------------------------------------------------------------------------------------
340 
341     class socket_error : public error
342     {
343     public:
socket_error(error_type t,const std::string & a)344         socket_error(
345             error_type t,
346             const std::string& a
347         ): error(t,a) {}
348         /*!
349             ensures
350                 - #type == t
351                 - #info == a
352         !*/
353 
socket_error(error_type t)354         socket_error(
355             error_type t
356         ): error(t) {}
357         /*!
358             ensures
359                 - #type == t
360                 - #info == ""
361         !*/
362 
socket_error(const std::string & a)363         socket_error(
364             const std::string& a
365         ): error(ESOCKET,a) {}
366         /*!
367             ensures
368                 - #type == ESOCKET
369                 - #info == a
370         !*/
371 
socket_error()372         socket_error(
373         ): error(ESOCKET) {}
374         /*!
375             ensures
376                 - #type == ESOCKET
377                 - #info == ""
378         !*/
379     };
380 
381 // ----------------------------------------------------------------------------------------
382 
383     class thread_error : public error
384     {
385     public:
thread_error(error_type t,const std::string & a)386         thread_error(
387             error_type t,
388             const std::string& a
389         ): error(t,a) {}
390         /*!
391             ensures
392                 - #type == t
393                 - #info == a
394         !*/
395 
thread_error(error_type t)396         thread_error(
397             error_type t
398         ): error(t) {}
399         /*!
400             ensures
401                 - #type == t
402                 - #info == ""
403         !*/
404 
thread_error(const std::string & a)405         thread_error(
406             const std::string& a
407         ): error(ETHREAD,a) {}
408         /*!
409             ensures
410                 - #type == ETHREAD
411                 - #info == a
412         !*/
413 
thread_error()414         thread_error(
415         ): error(ETHREAD) {}
416         /*!
417             ensures
418                 - #type == ETHREAD
419                 - #info == ""
420         !*/
421     };
422 
423 // ----------------------------------------------------------------------------------------
424 
425     class impossible_labeling_error : public dlib::error
426     {
427         /*!
428             WHAT THIS OBJECT REPRESENTS
429                 This is the exception thrown by code that trains object detectors (e.g.
430                 structural_svm_object_detection_problem) when they detect that the set of
431                 truth boxes given to the training algorithm contains some impossible to
432                 obtain outputs.
433 
434                 This kind of problem can happen when the set of image positions scanned by
435                 the underlying object detection method doesn't include the truth rectangle
436                 as a possible output.  Another possibility is when two truth boxes are very
437                 close together and hard coded non-max suppression logic would prevent two
438                 boxes in such close proximity from being output.
439         !*/
440     public:
impossible_labeling_error(const std::string & msg)441         impossible_labeling_error(const std::string& msg) : dlib::error(msg) {};
442     };
443 
444 // ----------------------------------------------------------------------------------------
445 
446 }
447 
448 #endif // DLIB_ERROr_
449 
450