Library of Assembled Shared Sources
enforcer_impl.h
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2011 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43
44#ifndef LASS_GUARDIAN_OF_INCLUSION_UTIL_IMPL_ENFORCER_IMPL_H
45#define LASS_GUARDIAN_OF_INCLUSION_UTIL_IMPL_ENFORCER_IMPL_H
46
47#include "../util_common.h"
48
49namespace lass
50{
51namespace util
52{
53namespace impl
54{
55
56// Predicates
57
58/** Predicate for enforcers using operator!, used by LASS_ENFORCE and LASS_ENFORCE_POINTER.
59 * @internal
60 *
61 * the value @a t is evaluated by using the operator!.
62 * if this returns true, the predicate will return true and the enforcer will raise.
63 * if this is false, the predicate will return false and the program will continue
64 *
65 * taken from:
66 * ALEXANDRESCU A. & MARGINEAN P. (2003), Enforcements. June 2003, C++ Experts Forum,
67 * http://www.cuj.com.
68 *
69 * http://www.cuj.com/documents/s=8250/cujcexp2106alexandr
70 *
71 * @pre type T must support bool operator!(const T&).
72 */
74{
75 template <typename T, typename C>
76 static bool LASS_CALL wrong(const T& t, const C& /* closure */)
77 {
78 return !t;
79 }
80};
81
82
83
84/** value must be equal to closure
85 * @internal
86 *
87 * the value @a t is compared to the value of @a closure using operator==.
88 * If they are equal, the predicate returns fals and nothing happens.
89 * Otherwise, the predicate returns true and the enforcer will raise.
90 *
91 * @pre T and C must be comparable using operator==(const T&, const C&).
92 */
94{
95 template <typename T, typename C>
96 static bool LASS_CALL wrong(const T& t, const C& closure)
97 {
98 return !(t == closure);
99 }
100};
101
102
103
104/** value must be different than closure
105 * @internal
106 *
107 * the value @a t is compared to the value of @a closure using operator==.
108 * If they are equal, the predicate returns true and the enforcer will raise.
109 * Otherwise, the predicate returns fals and nothing happens.
110 *
111 * @pre T and C must be comparable using operator==(const T&, const C&).
112 */
114{
115 template <typename T, typename C>
116 static bool LASS_CALL wrong(const T& t, const C& closure)
117 {
118 return t == closure;
119 }
120};
121
122
123
124/** value must be greater than or equal to closure
125 * @internal
126 *
127 * the value @a t is compared to the value of @a closure using operator<.
128 * If t is less, the predicate returns true and the enforcer will raise.
129 * Otherwise, the predicate returns false and nothing happens.
130 *
131 * @pre T and C must be comparable using operator<(const T&, const C&).
132 */
134{
135 template <typename T, typename C>
136 static bool LASS_CALL wrong(const T& t, const C& closure)
137 {
138 return t < closure;
139 }
140};
141
142
143
144/** value must be in range [0, closure)
145 * @internal
146 *
147 * If t is out of range, the predicate returns true and the enforcer will raise.
148 * Otherwise, the predicate returns false and nothing happens.
149 *
150 * @pre T and C must be comparable using operator<(const T&, const C&).
151 */
153{
154 template <typename T, typename C>
155 static bool LASS_CALL wrong(const T& t, const C& closure)
156 {
157 return t < C(0) || !(t < closure);
158 }
159 template <typename C>
160 static bool LASS_CALL wrong(size_t t, const C& closure)
161 {
162 return !(t < closure);
163 }
164};
165
166
167
168/** Predicate to enforce a stream to be a in good state.
169 * @internal
170 * @author Bram de Greve [Bramz].
171 *
172 * Takes a pointer to a stream, and checks if that stream is in a good state (not eof,
173 * not failed, not bad). If not, the enforcer will raise.
174 */
176{
177 template <typename T, typename C>
178 static bool LASS_CALL wrong(const T& stream, const C& /* closure */)
179 {
180 return stream.fail();
181 }
182};
183
184
185
186
187#ifdef LASS_HAS_GETLASTERROR
188
189/** Predicate for calls to the Windows API that return 0 on error _and_ have GetLastError() != 0.
190 * @internal
191 * @author Bram de Greve[Bramz]
192 *
193 * This predicate checks if the return value of the function. If it is zero, there possibly is
194 * an error. It then also checks GetLastError(). If that one differs from zero, an error indeed happened.
195 */
196struct WinAPIPredicate
197{
198 template <typename T, typename C>
199 static bool LASS_CALL wrong(const T& returnCode, const C& /* closure */)
200 {
201 return returnCode == 0 && lass_GetLastError() != 0;
202 }
203};
204
205#endif
206
207
208
209// --- Raisers -------------------------------------------------------------------------------------
210
211/** Throw a runtime error
212 * @internal
213 *
214 * taken from:
215 * ALEXANDRESCU A. & MARGINEAN P. (2003), Enforcements. June 2003, C++ Experts Forum,
216 * http://www.cuj.com.
217 *
218 * http://www.cuj.com/documents/s=8250/cujcexp2106alexandr
219 */
221{
222 template <typename T, typename C>
223 static void raise(const T&, const C&, const std::string& message, const char* locus)
224 {
225 if (message.empty())
226 {
227 LASS_THROW_EX(EnforceFailure, locus);
228 }
229 else
230 {
231 LASS_THROW_EX(EnforceFailure, locus << ":\n" << message);
232 }
233 }
234};
235
236
237
238inline void raiserAddMessage(std::ostream& stream, const std::string& message)
239{
240 if (!message.empty())
241 {
242 stream << ":\n" << message;
243 }
244}
245
246
247/** Throws an run time exception for raising LASS_ENFORCE_ZERO
248 * @internal
249 * @author Bram de Greve.
250 */
252{
253 template <typename T, typename C>
254 static void raise(const T& result, const C&, const std::string& message, const char* locus)
255 {
256 std::ostringstream buffer;
257 buffer << "Expression " << locus << " resulted in a non-zero value '" << result << "'";
258 raiserAddMessage(buffer, message);
259 LASS_THROW_EX(EnforceFailure, buffer.str());
260 }
261};
262
263
264
265/** Throws a run time exception for raisng LASS_ENFORCE_CLIB.
266 * @internal
267 * @author Bram de Greve
268 * retrieves an error code from errno.
269 */
271 {
272 template <typename T, typename C>
273 static void raise(const T&, const C&, const std::string& message, const char* locus)
274 {
275 //LASS_ASSERT(iRc == -1);
276 const int errnum = lass_errno();
277 std::ostringstream buffer;
278 buffer << "Function call " << locus << " failed with: " << lass_strerror(errnum);
279 raiserAddMessage(buffer, message);
280 LASS_THROW_EX(EnforceFailure, buffer.str());
281 }
282};
283
284
285
286/** Prints warning to std::cerr for LASS_WARN_CLIB.
287 * @internal
288 * @author Bram de Greve
289 * retrieves an error code from errno. rc should be -1.
290 */
292 {
293 template <typename T, typename C>
294 static void raise(const T&, const C&, const std::string& message, const char* locus)
295 {
296 const int errnum = lass_errno();
297 std::ostringstream buffer;
298 std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR: "
299 << "Function call " << locus << " failed with errno: ("
300 << errnum << ") " << lass_strerror(errnum);
301 raiserAddMessage(std::cerr, message);
302 std::cerr << ".\n" << std::flush;
303 }
304};
305
306
307
308/** Throws a run time exception for raisng LASS_ENFORCE_CLIB_RC.
309 * @internal
310 * @author Bram de Greve
311 * iRc contains error code and should not be zero.
312 */
314 {
315 template <typename T, typename C>
316 static void raise(const T& rc, const C&, const std::string& message, const char* locus)
317 {
318 //LASS_ASSERT(iRc != 0);
319 std::ostringstream buffer;
320 buffer << "Function call " << locus << " failed with return code: ("
321 << rc << ") " << lass_strerror(rc);
322 raiserAddMessage(buffer, message);
323 LASS_THROW_EX(EnforceFailure, buffer.str());
324 }
325};
326
327
328
329/** Throws a run time exception for raisng LASS_ENFORCE_CLIB_RC.
330 * @internal
331 * @author Bram de Greve
332 * iRc contains error code and should not be zero.
333 */
335 {
336 template <typename T, typename C>
337 static void raise(const T& rc, const C&, const std::string& message, const char* locus)
338 {
339 std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR: "
340 << "Function call " << locus << " failed with return code: ("
341 << rc << ") " << lass_strerror(rc);
342 raiserAddMessage(std::cerr, message);
343 std::cerr << std::endl << std::flush;
344 }
345};
346
347
348
349/** Throws an run time exception for raising LASS_ENFORCE_COM
350 * @internal
351 * @author Bram de Greve.
352 */
354{
355 template <typename T, typename C>
356 static void raise(const T& hResult, const C&, const std::string& message, const char* locus)
357 {
358 std::ostringstream buffer;
359 buffer << "Failure HRESULT '" << hResult << "' returned by " << locus;
360 raiserAddMessage(buffer, message);
361 LASS_THROW_EX(EnforceFailure, buffer.str());
362 }
363};
364
365
366
367#ifdef LASS_HAS_GETLASTERROR
368
369/** Throws an exception using GetLastError() and FormatMessage().
370 * @internal
371 * @author Bram de Greve
372 * @arg only available on Windows platform
373 */
374struct LastErrorRaiser
375{
376 template <typename T, typename C>
377 static void raise(const T&, const C&, const std::string& message, const char* locus)
378 {
379 std::ostringstream buffer;
380 const unsigned lastError = lass_GetLastError();
381 buffer << "Function call " << locus << " failed with last-error: ("
382 << lastError << ") " << lass_FormatMessage(lastError);
383 raiserAddMessage(buffer, message);
384 LASS_THROW_EX(EnforceFailure, buffer.str());
385 }
386};
387
388/** Writes warning to std::cerr using GetLastError() and FormatMessage().
389 * @internal
390 * @author Bram de Greve
391 * @arg only available on Windows platform
392 */
393struct LastErrorWarner
394{
395 template <typename T, typename C>
396 static void raise(const T&, const C&, const std::string& message, const char* locus)
397 {
398 const unsigned lastError = lass_GetLastError();
399 std::cerr << "Function call " << locus << " failed with last-error: ("
400 << lastError << ") " << lass_FormatMessage(lastError);
401 raiserAddMessage(std::cerr, message);
402 std::cerr << std::endl << std::flush;
403 }
404};
405
406#endif
407
408
409/** Throw a range error for LASS_ENFORCE_INDEX.
410 * @internal
411 * @author Bram de Greve.
412 * @pre type T must be streamable to a std::ostream.
413 */
415{
416 template <typename T, typename C>
417 static void raise(const T& index, const C& size, const std::string& message, const char* locus)
418 {
419 std::ostringstream buffer;
420 buffer << "Value '" << index << "' is out of range [0, " << size << ") in '"
421 << locus << "'";
422 raiserAddMessage(buffer, message);
423 LASS_THROW_EX(EnforceFailure, buffer.str());
424 }
425};
426
427
428
429// --- Other helper stuff --------------------------------------------------------------------------
430
431/** Helper class of the enforce macro's.
432 * @internal
433 *
434 * taken from:
435 * ALEXANDRESCU A. & MARGINEAN P. (2003), Enforcements. June 2003, C++ Experts Forum,
436 * http://www.cuj.com.
437 *
438 * http://www.cuj.com/documents/s=8250/cujcexp2106alexandr
439 */
440template
441<
442 typename PredicateType,
443 typename RaiserType,
444 typename T,
445 typename ClosureType
446>
447class Enforcer
448{
449public:
450 Enforcer(T t, ClosureType closure, const char* locus):
451 t_(t),
452 closure_(closure),
453 locus_(PredicateType::wrong(t, closure) ? locus : 0)
454 {
455 if (!locus)
456 {
457 std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: "
458 "Enforcer did not get a locus!\n" << std::flush;
459 }
460 }
461
462 T operator*() const
463 {
464 if (locus_)
465 {
466 RaiserType::raise(t_, closure_, msg_, locus_);
467 }
468 return t_;
469 }
470
471 template <class MsgType>
472 Enforcer& operator()(const MsgType& msg)
473 {
474 if (locus_)
475 {
476 // Here we have time; no need to be super-efficient
477 std::ostringstream ss;
478 ss << msg;
479 msg_ += ss.str();
480 }
481 return *this;
482 }
483
484private:
485
486 T t_;
487 ClosureType closure_;
488 std::string msg_;
489 const char* const locus_;
490};
491
492#ifndef LASS_ENFORCER_USE_AMBIGUITY_WORKAROUND
493# if LASS_COMPILER_TYPE == LASS_COMPILER_TYPE_GCC && LASS_COMPILER_VERSION < 40000
494# define LASS_ENFORCER_USE_AMBIGUITY_WORKAROUND
495# elif LASS_COMPILER_TYPE == LASS_COMPILER_TYPE_SUNPRO
496# define LASS_ENFORCER_USE_AMBIGUITY_WORKAROUND
497# endif
498#endif
499
500#ifdef LASS_ENFORCER_USE_AMBIGUITY_WORKAROUND
501
502template <typename PredicateType, typename RaiserType>
503struct EnforcerMaker
504{
505 template <typename T, typename C> inline
507 T& t, const C& closure, const char* locus)
508 {
510 t, closure, locus);
511 }
512
513 template <typename T, typename C> inline
514 static Enforcer<PredicateType, RaiserType, const T&, const C&> make(
515 const T& t, const C& closure, const char* locus)
516 {
517 return Enforcer<PredicateType, RaiserType, const T&, const C&>(
518 t, closure, locus);
519 }
520};
521
522#define LASS_UTIL_IMPL_MAKE_ENFORCER(predicate, raiser, t, closure, locus)\
523 ::lass::util::impl::EnforcerMaker< predicate, raiser >::make(t, closure, locus)
524
525#else
526
527/** helper function to create enforcers
528 * @internal
529 * @relates lass::util::impl::Enforcer
530 *
531 * taken from:
532 * ALEXANDRESCU A. & MARGINEAN P. (2003), Enforcements. June 2003, C++ Experts Forum,
533 * http://www.cuj.com.
534 *
535 * http://www.cuj.com/documents/s=8250/cujcexp2106alexandr
536 */
537template <typename PredicateType, typename RaiserType, typename T, typename C>
539 T& t, const C& closure, const char* locus)
540{
542 t, closure, locus);
543}
544
545template <typename PredicateType, typename RaiserType, typename T, typename C>
546inline Enforcer<PredicateType, RaiserType, const T&, const C&> makeEnforcer(
547 const T& t, const C& closure, const char* locus)
548{
549 return Enforcer<PredicateType, RaiserType, const T&, const C&>(
550 t, closure, locus);
551}
552
553#define LASS_UTIL_IMPL_MAKE_ENFORCER(predicate, raiser, t, closure, locus)\
554 ::lass::util::impl::makeEnforcer< predicate, raiser >(t, closure, locus)
555
556#endif
557
558}
559
560}
561
562}
563
564#endif
565
566// EOF
Exception thrown by enforcers.
Definition enforcer.h:67
Helper class of the enforce macro's.
Enforcer< PredicateType, RaiserType, T &, const C & > makeEnforcer(T &t, const C &closure, const char *locus)
helper function to create enforcers
const std::string lass_strerror(int errnum)
returns message associated to an CLIB error code
int lass_errno()
returns CLIB errno
general utility, debug facilities, ...
Library for Assembled Shared Sources.
Definition config.h:53
Throws a run time exception for raisng LASS_ENFORCE_CLIB.
Throws a run time exception for raisng LASS_ENFORCE_CLIB_RC.
Throws a run time exception for raisng LASS_ENFORCE_CLIB_RC.
Prints warning to std::cerr for LASS_WARN_CLIB.
Throws an run time exception for raising LASS_ENFORCE_COM.
value must be equal to closure
value must be greater than or equal to closure
value must be in range [0, closure)
Throw a range error for LASS_ENFORCE_INDEX.
Predicate to enforce a stream to be a in good state.
Predicate for enforcers using operator!
value must be different than closure
Throws an run time exception for raising LASS_ENFORCE_ZERO.