Commit patch to not break on spaces.
[bowtie.git] / SeqAn-1.1 / seqan / basic / basic_debug.h
1  /*==========================================================================
2                 SeqAn - The Library for Sequence Analysis
3                           http://www.seqan.de 
4  ============================================================================
5   Copyright (C) 2007
6
7   This library is free software; you can redistribute it and/or
8   modify it under the terms of the GNU Lesser General Public
9   License as published by the Free Software Foundation; either
10   version 3 of the License, or (at your option) any later version.
11
12   This library is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   Lesser General Public License for more details.
16
17  ============================================================================
18   $Id: basic_debug.h,v 1.1 2008/08/25 16:20:01 langmead Exp $
19  ==========================================================================*/
20
21 #ifndef SEQAN_HEADER_BASIC_DEBUG_H
22 #define SEQAN_HEADER_BASIC_DEBUG_H
23
24 #ifndef SEQAN_DEBUG_OR_TEST_
25 #ifdef SEQAN_DEBUG
26 #define SEQAN_DEBUG_OR_TEST_
27 #else //#ifdef SEQAN_DEBUG
28 #ifdef SEQAN_TEST
29 #define SEQAN_DEBUG_OR_TEST_
30 #endif //#ifdef SEQAN_TEST
31 #endif //#ifdef SEQAN_DEBUG
32 #endif //#ifndef SEQAN_DEBUG_OR_TEST_
33
34
35 #ifdef SEQAN_DEBUG_OR_TEST_
36 #include <cstdio>
37 #endif //#ifdef SEQAN_DEBUG_OR_TEST_
38
39 #ifdef SEQAN_DEBUG
40
41 //throw a fatal debug report if _cond is false
42 #define SEQAN_ASSERT(_cond) { if (!(_cond)) ::SEQAN_NAMESPACE_MAIN::debug::Error< ::SEQAN_NAMESPACE_MAIN::debug::Check >(__FILE__, __LINE__, #_cond " is FALSE"); }
43 #define SEQAN_ASSERT1(_cond) SEQAN_ASSERT(_cond)
44 #define SEQAN_ASSERT2(_cond, _comment) { if (!(_cond)) ::SEQAN_NAMESPACE_MAIN::debug::Error< ::SEQAN_NAMESPACE_MAIN::debug::Check >(__FILE__, __LINE__, _comment); }
45
46 //throw a debug report if _cond is false
47 #define SEQAN_CHECK(_cond) { if (!(_cond)) ::SEQAN_NAMESPACE_MAIN::debug::Message< ::SEQAN_NAMESPACE_MAIN::debug::Check >(__FILE__, __LINE__, #_cond " is FALSE"); }
48 #define SEQAN_CHECK1(_cond) SEQAN_CHECK(_cond)
49 #define SEQAN_CHECK2(_cond, _comment) { if (!(_cond)) ::SEQAN_NAMESPACE_MAIN::debug::Message< ::SEQAN_NAMESPACE_MAIN::debug::Check >(__FILE__, __LINE__, _comment); }
50
51 #define SEQAN_DO(_cond) { if (!(_cond)) ::SEQAN_NAMESPACE_MAIN::debug::Message< ::SEQAN_NAMESPACE_MAIN::debug::Check >(__FILE__, __LINE__, #_cond " is FALSE"); }
52 #define SEQAN_DO1(_cond) SEQAN_DO(_cond)
53 #define SEQAN_DO2(_cond, _comment) { if (!(_cond)) ::SEQAN_NAMESPACE_MAIN::debug::Error< ::SEQAN_NAMESPACE_MAIN::debug::Check >(__FILE__, __LINE__, _comment); }
54
55 //report a message
56 #define SEQAN_ABORT(_comment) { ::SEQAN_NAMESPACE_MAIN::debug::Error< ::SEQAN_NAMESPACE_MAIN::debug::Report >(__FILE__, __LINE__, _comment); }
57 #define SEQAN_REPORT(_comment) { ::SEQAN_NAMESPACE_MAIN::debug::Message< ::SEQAN_NAMESPACE_MAIN::debug::Report >(__FILE__, __LINE__, _comment); }
58
59 #else //#ifdef SEQAN_DEBUG
60
61 //disable debug reports in release built
62 #define SEQAN_ASSERT(_cond) {}
63 #define SEQAN_ASSERT1(_cond) {}
64 #define SEQAN_ASSERT2(_cond, _comment) {}
65
66 #define SEQAN_CHECK(_cond) {}
67 #define SEQAN_CHECK1(_cond) {}
68 #define SEQAN_CHECK2(_cond, _comment) {}
69
70 #define SEQAN_DO(_cond) { _cond; }
71 #define SEQAN_DO1(_cond) SEQAN_DO(_cond)
72 #define SEQAN_DO2(_cond, _comment) { _cond; }
73
74 #define SEQAN_ABORT(_comment) {}
75 #define SEQAN_REPORT(_comment) {}
76
77 #endif //#ifdef SEQAN_DEBUG
78
79 #ifdef SEQAN_TEST
80
81 //test a condition and report test result
82 #define SEQAN_TASSERT(_cond) \
83         { if (!(_cond)) ::SEQAN_NAMESPACE_MAIN::debug::Error< ::SEQAN_NAMESPACE_MAIN::debug::Check >(__FILE__, __LINE__, "(" #_cond ") is FALSE"); }
84 #define SEQAN_TASSERT1(_cond) SEQAN_TASSERT(_cond)
85 #define SEQAN_TASSERT2(_cond, _comment) \
86         { if (!(_cond)) ::SEQAN_NAMESPACE_MAIN::debug::Error< ::SEQAN_NAMESPACE_MAIN::debug::Check >(__FILE__, __LINE__, _comment); }
87
88 #define SEQAN_TCHECK(_cond) \
89         { if (_cond) ::SEQAN_NAMESPACE_MAIN::debug::Result< ::SEQAN_NAMESPACE_MAIN::debug::Check >(__FILE__, __LINE__, "(" #_cond ") is TRUE"); \
90         else ::SEQAN_NAMESPACE_MAIN::debug::Result< ::SEQAN_NAMESPACE_MAIN::debug::Check >(__FILE__, __LINE__, "(" #_cond ") is FALSE"); }
91 #define SEQAN_TCHECK1(_cond) SEQAN_TCHECK(_cond)
92 #define SEQAN_TCHECK2(_cond, _comment) \
93         { if (_cond) ::SEQAN_NAMESPACE_MAIN::debug::Result< ::SEQAN_NAMESPACE_MAIN::debug::Check >(__FILE__, __LINE__, _comment); }
94
95 //report a test result
96 #define SEQAN_TABORT(_comment) { ::SEQAN_NAMESPACE_MAIN::debug::Error< ::SEQAN_NAMESPACE_MAIN::debug::Report >(__FILE__, __LINE__, _comment); }
97 #define SEQAN_TREPORT(_comment) { ::SEQAN_NAMESPACE_MAIN::debug::Result< ::SEQAN_NAMESPACE_MAIN::debug::Report >(__FILE__, __LINE__, _comment); }
98
99 #else //#ifdef SEQAN_TEST
100
101 #define SEQAN_TASSERT(_cond) {}
102 #define SEQAN_TASSERT1(_cond) {}
103 #define SEQAN_TASSERT2(_cond, _comment) {}
104
105 #define SEQAN_TCHECK(_cond) {}
106 #define SEQAN_TABORT(_comment) {}
107 #define SEQAN_TREPORT(_comment) {}
108
109 #endif //#ifdef SEQAN_TEST
110 //____________________________________________________________________________
111
112 #ifdef SEQAN_DEBUG_OR_TEST_
113
114 //Test Helper Functions
115
116 // compare two files, do not translate linebreaks
117 inline bool 
118 _compareBinaryFiles(char * file1, char * file2)
119 {
120         bool ret = false;
121
122         FILE * fl1 = fopen(file1, "rb");
123         if (!fl1) return ret;
124
125         FILE * fl2 = fopen(file2, "rb");
126         if (!fl2)
127         {
128                 fclose(fl1);
129                 return ret;
130         }
131
132         while (!feof(fl1) && !feof(fl2))
133         {
134                 if (fgetc(fl1) != fgetc(fl2)) goto End;
135         }
136
137         ret = feof(fl1) && feof(fl2);
138
139 End:
140         fclose(fl2);
141         fclose(fl1);
142
143         return ret;
144
145 }
146 //____________________________________________________________________________
147
148 //one line break is either \r, \n, or \r\n.
149 inline void 
150 _compareTextFiles_readChar(FILE * fl, char & c, bool & is_lb, bool & is_eof)
151 {
152         is_lb = false;
153         is_eof = false;
154
155         c = fgetc(fl);
156         if (c == '\r')
157         {
158                 is_lb = true;
159                 char c_help = fgetc(fl);
160                 if (feof(fl)) is_eof = true;
161                 else
162                 {
163                         if (c_help == '\n')
164                         {
165                                 c = fgetc(fl);
166                                 if (feof(fl)) is_eof = true;
167                         }
168                         else c = c_help;
169                 }
170         }
171         if (c == '\n')
172         {
173                 is_lb = true;
174                 c = fgetc(fl);
175                 if (feof(fl)) is_eof = true;
176         }
177 }
178
179 // compare two files, translate linebreaks
180 inline bool 
181 _compareTextFiles(char * file1, char * file2)
182 {
183         FILE * fl1 = fopen(file1, "rb");
184         if (!fl1) return false;
185
186         FILE * fl2 = fopen(file2, "rb");
187         if (!fl2)
188         {
189                 fclose(fl1);
190                 return false;
191         }
192
193         bool ret = false;
194
195         bool is_lb1, is_lb2, is_eof1, is_eof2;
196         char c1, c2;
197
198         while (!feof(fl1) && !feof(fl2))
199         {
200                 _compareTextFiles_readChar(fl1, c1, is_lb1, is_eof1);
201                 _compareTextFiles_readChar(fl2, c2, is_lb2, is_eof2);
202
203                 if (is_lb1 ^ is_lb2)
204                 {
205                         goto End;
206                 }
207                 if (is_eof1 ^ is_eof2)
208                 {
209                         goto End;
210                 }
211                 if (c1 != c2)
212                 {
213                         goto End;
214                 }
215         }
216
217         ret = feof(fl1) && feof(fl2);
218
219 End:
220         fclose(fl2);
221         fclose(fl1);
222
223         return ret;
224
225 }
226
227
228 //____________________________________________________________________________
229
230 namespace SEQAN_NAMESPACE_MAIN
231 {
232
233 namespace debug
234 {
235
236 //action of SEQAN_ASSERT, SEQAN_TCHECK and SEQAN_CHECK
237 //use as template argument for Error<> and Message<> and Result<>
238 class Check {};
239
240 //action of SEQAN_ABORT, SEQAN_TREPORT and SEQAN_REPORT
241 //use as template argument for Error<> and Message<> and Result<>
242 class Report {};
243
244
245 //report fatal error
246 //template argument TAction is the action (Check or Report)
247 //use explicit instatiation for overwriting the default behavior
248 template <typename TAction>
249 void Error(const char * file, int line, const char * comment="-")
250 {
251         std::fprintf(stderr, "%s(%i) : SEQAN: %s\nSEQAN: execution aborted\n", file, line, comment);
252         exit(1);
253 }
254
255 //report debug message
256 //template argument TAction is the action (Check or Report)
257 //use explicit instatiation for overwriting the default behavior
258 template <typename TAction>
259 void Message(const char * file, int line, const char * comment="-")
260 {
261         std::fprintf(stderr, "%s(%i) : SEQAN: %s\n", file, line, comment);
262 }
263
264 //report test result
265 //template argument TAction is the action (Check or Report)
266 //use explicit instatiation for overwriting the default behavior
267 template <typename TAction>
268 void Result(const char * file, int line, const char * comment="-")
269 {
270         std::fprintf(stdout, "%s(%i) : %s\n", file, line, comment);
271 }
272
273 } //namespace debug
274
275 } //namespace SEQAN_NAMESPACE_MAIN
276
277 #endif //#ifdef SEQAN_DEBUG_OR_TEST_
278
279
280 //____________________________________________________________________________
281 //Checkpoint Testing
282
283 //note: this framework relies on the filenames in the project to be unique 
284
285 #ifdef SEQAN_TEST
286
287 #include <set>
288 #include <vector>
289 #include <cstring>
290
291 namespace SEQAN_NAMESPACE_MAIN
292 {
293 namespace debug
294 {
295 struct Checkpoint
296 {
297         char const* file;
298         unsigned int line;
299 };
300
301 struct CheckpointLess : public ::std::binary_function <Checkpoint, Checkpoint, bool>
302 {
303         inline bool operator() (Checkpoint const &a, Checkpoint const &b) const
304         {
305                 int c = strcmp(a.file, b.file);
306                 return c < 0 || (c == 0 && a.line < b.line);
307         }
308 };
309
310 template <typename T = void>
311 struct CheckpointStore
312 {
313         static ::std::set<Checkpoint, CheckpointLess> data;
314 };
315 template <typename T>
316 ::std::set<Checkpoint, CheckpointLess> CheckpointStore<T>::data;
317
318
319 inline bool 
320 checkpoint(unsigned int line, char const* file)
321 {
322         char const* file_name = strrchr(file, '/');
323         char const* file_name_2 = strrchr(file, '\\');
324         if (file_name_2 > file_name) file_name = file_name_2;
325         if (!file_name) file_name = file;
326         else ++file_name;
327
328         Checkpoint cp = {file_name, line};
329         CheckpointStore<>::data.insert(cp);
330         return true;
331 }
332 #define SEQAN_CHECKPOINT \
333         ::SEQAN_NAMESPACE_MAIN::debug::checkpoint(__LINE__, __FILE__);
334
335
336 inline void 
337 testCheckpoint(char const* file, unsigned int line)
338 {
339         Checkpoint cp = {file, line};
340         if (CheckpointStore<>::data.find(cp) == CheckpointStore<>::data.end())
341                 Message< Report >(file, line, "Checkpoint lost");
342 }
343
344 inline void 
345 verifyCheckpoints(char const* file)
346 {
347         char const* file_name = strrchr(file, '/');
348         char const* file_name_2 = strrchr(file, '\\');
349         if (file_name_2 > file_name) file_name = file_name_2;
350         if (!file_name) file_name = file;
351         else ++file_name;
352
353         FILE * fl = ::std::fopen(file, "r");
354         if (!fl)
355         {
356                 Error< Report >(file, 0, "verifyCheckpoints could not find this file.");        
357         }
358         unsigned int line_number = 1;
359         char buf[1<<16];
360
361         while (::std::fgets(buf, sizeof(buf), fl))
362         {
363                 if (::std::strstr(buf, "SEQAN_CHECKPOINT"))
364                 {
365                         testCheckpoint(file_name, line_number);
366                 }
367                 ++line_number;
368         }
369
370         ::std::fclose(fl);
371 }
372
373 } //namespace debug
374
375 } //namespace SEQAN_NAMESPACE_MAIN
376
377 #else //#ifdef SEQAN_TEST
378
379 #define SEQAN_CHECKPOINT
380
381 #endif //#ifdef SEQAN_TEST
382
383 //____________________________________________________________________________
384
385 #endif //#ifndef SEQAN_HEADER_...