library of assembled shared sources

http://lass.cocamware.com

enforcer_impl.h

Go to the documentation of this file.
00001 /** @file
00002  *  @author Bram de Greve (bramz@users.sourceforge.net)
00003  *  @author Tom De Muer (tomdemuer@users.sourceforge.net)
00004  *
00005  *  *** BEGIN LICENSE INFORMATION ***
00006  *  
00007  *  The contents of this file are subject to the Common Public Attribution License 
00008  *  Version 1.0 (the "License"); you may not use this file except in compliance with 
00009  *  the License. You may obtain a copy of the License at 
00010  *  http://lass.sourceforge.net/cpal-license. The License is based on the 
00011  *  Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover 
00012  *  use of software over a computer network and provide for limited attribution for 
00013  *  the Original Developer. In addition, Exhibit A has been modified to be consistent 
00014  *  with Exhibit B.
00015  *  
00016  *  Software distributed under the License is distributed on an "AS IS" basis, WITHOUT 
00017  *  WARRANTY OF ANY KIND, either express or implied. See the License for the specific 
00018  *  language governing rights and limitations under the License.
00019  *  
00020  *  The Original Code is LASS - Library of Assembled Shared Sources.
00021  *  
00022  *  The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
00023  *  The Original Developer is the Initial Developer.
00024  *  
00025  *  All portions of the code written by the Initial Developer are:
00026  *  Copyright (C) 2004-2007 the Initial Developer.
00027  *  All Rights Reserved.
00028  *  
00029  *  Contributor(s):
00030  *
00031  *  Alternatively, the contents of this file may be used under the terms of the 
00032  *  GNU General Public License Version 2 or later (the GPL), in which case the 
00033  *  provisions of GPL are applicable instead of those above.  If you wish to allow use
00034  *  of your version of this file only under the terms of the GPL and not to allow 
00035  *  others to use your version of this file under the CPAL, indicate your decision by 
00036  *  deleting the provisions above and replace them with the notice and other 
00037  *  provisions required by the GPL License. If you do not delete the provisions above,
00038  *  a recipient may use your version of this file under either the CPAL or the GPL.
00039  *  
00040  *  *** END LICENSE INFORMATION ***
00041  */
00042 
00043 
00044 #ifndef LASS_GUARDIAN_OF_INCLUSION_UTIL_IMPL_ENFORCER_IMPL_H
00045 #define LASS_GUARDIAN_OF_INCLUSION_UTIL_IMPL_ENFORCER_IMPL_H
00046 
00047 #include "../util_common.h"
00048 
00049 namespace lass
00050 {
00051 namespace util
00052 {
00053 namespace impl
00054 {
00055 
00056 // Predicates
00057 
00058 /** Predicate for enforcers using operator!, used by LASS_ENFORCE and LASS_ENFORCE_POINTER.
00059  *  @internal
00060  *
00061  *  the value @a t is evaluated by using the operator!.
00062  *  if this returns true, the predicate will return true and the enforcer will raise.
00063  *  if this is false, the predicate will return false and the program will continue
00064  *
00065  *  taken from:
00066  *  ALEXANDRESCU A. & MARGINEAN P. (2003), Enforcements. June 2003, C++ Experts Forum,
00067  *  http://www.cuj.com.
00068  *
00069  *  http://www.cuj.com/documents/s=8250/cujcexp2106alexandr
00070  *
00071  *  @pre type T must support bool operator!(const T&).
00072  */
00073 struct TruePredicate
00074 {
00075     template <typename T, typename C>
00076     static bool LASS_CALL wrong(const T& t, const C& /* closure */)
00077     {
00078         return !t;
00079     }
00080 };
00081 
00082 
00083 
00084 /** value must be equal to closure
00085  *  @internal
00086  *
00087  *  the value @a t is compared to the value of @a closure using operator==.
00088  *  If they are equal, the predicate returns fals and nothing happens.
00089  *  Otherwise, the predicate returns true and the enforcer will raise.
00090  *
00091  *  @pre T and C must be comparable using operator==(const T&, const C&).
00092  */
00093 struct EqualPredicate
00094 {
00095     template <typename T, typename C>
00096     static bool LASS_CALL wrong(const T& t, const C& closure)
00097     {
00098         return !(t == closure);
00099     }
00100 };
00101 
00102 
00103 
00104 /** value must be different than closure
00105  *  @internal
00106  *
00107  *  the value @a t is compared to the value of @a closure using operator==.
00108  *  If they are equal, the predicate returns true and the enforcer will raise.
00109  *  Otherwise, the predicate returns fals and nothing happens.
00110  *
00111  *  @pre T and C must be comparable using operator==(const T&, const C&).
00112  */
00113 struct UnequalPredicate
00114 {
00115     template <typename T, typename C>
00116     static bool LASS_CALL wrong(const T& t, const C& closure)
00117     {
00118         return t == closure;
00119     }
00120 };
00121 
00122 
00123 
00124 /** value must be greater than or equal to closure
00125  *  @internal
00126  *
00127  *  the value @a t is compared to the value of @a closure using operator<.
00128  *  If t is less, the predicate returns true and the enforcer will raise.
00129  *  Otherwise, the predicate returns false and nothing happens.
00130  *
00131  *  @pre T and C must be comparable using operator<(const T&, const C&).
00132  */
00133 struct GreaterEqualPredicate
00134 {
00135     template <typename T, typename C>
00136     static bool LASS_CALL wrong(const T& t, const C& closure)
00137     {
00138         return t < closure;
00139     }
00140 };
00141 
00142 
00143 
00144 /** value must be in range [0, closure)
00145  *  @internal
00146  *
00147  *  If t is out of range, the predicate returns true and the enforcer will raise.
00148  *  Otherwise, the predicate returns false and nothing happens.
00149  *
00150  *  @pre T and C must be comparable using operator<(const T&, const C&).
00151  */
00152 struct IndexPredicate
00153 {
00154     template <typename T, typename C>
00155     static bool LASS_CALL wrong(const T& t, const C& closure)
00156     {
00157         return t < C(0) || !(t < closure);
00158     }
00159 };
00160 
00161 
00162 
00163 /** Predicate to enforce a stream to be a in good state.
00164  *  @internal
00165  *  @author Bram de Greve [Bramz].
00166  *
00167  *  Takes a pointer to a stream, and checks if that stream is in a good state (not eof,
00168  *  not failed, not bad).  If not, the enforcer will raise.
00169  */
00170 struct StreamPredicate
00171 {
00172     template <typename T, typename C>
00173     static bool LASS_CALL wrong(const T& stream, const C& /* closure */)
00174     {
00175         return stream.fail();
00176     }
00177 };
00178 
00179 
00180 
00181 
00182 #ifdef LASS_HAS_GETLASTERROR
00183 
00184 /** Predicate for calls to the Windows API that return 0 on error _and_ have GetLastError() != 0.
00185  *  @internal
00186  *  @author Bram de Greve[Bramz]
00187  *
00188  *  This predicate checks if the return value of the function.  If it is zero, there possibly is
00189  *  an error.  It then also checks GetLastError().  If that one differs from zero, an error indeed happened.
00190  */
00191 struct WinAPIPredicate
00192 {
00193     template <typename T, typename C>
00194     static bool LASS_CALL wrong(const T& returnCode, const C& /* closure */)
00195     {
00196         return returnCode == 0 && lass_GetLastError() != 0;
00197     }
00198 };
00199 
00200 #endif
00201 
00202 
00203 
00204 // --- Raisers -------------------------------------------------------------------------------------
00205 
00206 /** Throw a runtime error
00207  *  @internal
00208  *
00209  *  taken from:
00210  *  ALEXANDRESCU A. & MARGINEAN P. (2003), Enforcements. June 2003, C++ Experts Forum,
00211  *  http://www.cuj.com.
00212  *
00213  *  http://www.cuj.com/documents/s=8250/cujcexp2106alexandr
00214  */
00215 struct DefaultRaiser
00216 {
00217     template <typename T, typename C>
00218     static void raise(const T&, const C&, const std::string& message, const char* locus)
00219     {
00220         if (message.empty())
00221         {
00222             LASS_THROW_EX(EnforceFailure, locus);
00223         }
00224         else
00225         {
00226             LASS_THROW_EX(EnforceFailure, locus << ":\n" << message);
00227         }
00228     }
00229 };
00230 
00231 
00232 
00233 inline void raiserAddMessage(std::ostream& stream, const std::string& message)
00234 {
00235     if (!message.empty())
00236     {
00237         stream << ":\n" << message;
00238     }
00239 }
00240 
00241 
00242 /** Throws an run time exception for raising LASS_ENFORCE_ZERO
00243  *  @internal
00244  *  @author Bram de Greve.
00245  */
00246 struct ZeroRaiser
00247 {
00248     template <typename T, typename C>
00249     static void raise(const T& result, const C&, const std::string& message, const char* locus)
00250     {
00251         std::ostringstream buffer;
00252         buffer << "Expression " << locus << " resulted in a non-zero value '" << result << "'";
00253         raiserAddMessage(buffer, message);
00254         LASS_THROW_EX(EnforceFailure, buffer.str());
00255     }
00256 };
00257 
00258 
00259 
00260 /** Throws a run time exception for raisng LASS_ENFORCE_CLIB.
00261  *  @internal
00262  *  @author Bram de Greve
00263  *  retrieves an error code from errno.
00264  */
00265  struct ClibRaiser
00266  {
00267     template <typename T, typename C>
00268     static void raise(const T&, const C&, const std::string& message, const char* locus)
00269     {
00270         //LASS_ASSERT(iRc == -1);
00271         const int errnum = lass_errno();
00272         std::ostringstream buffer;
00273         buffer << "Function call " << locus << " failed with errno: ("
00274             << errnum << ") " << lass_strerror(errnum);         
00275         raiserAddMessage(buffer, message);
00276         LASS_THROW_EX(EnforceFailure, buffer.str());
00277     }
00278 };
00279 
00280 
00281 
00282 /** Prints warning to std::cerr for LASS_WARN_CLIB.
00283  *  @internal
00284  *  @author Bram de Greve
00285  *  retrieves an error code from errno.  rc should be -1.
00286  */
00287  struct ClibWarner
00288  {
00289     template <typename T, typename C>
00290     static void raise(const T&, const C&, const std::string& message, const char* locus)
00291     {
00292         const int errnum = lass_errno();
00293         std::ostringstream buffer;
00294         std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR: "
00295             << "Function call " << locus << " failed with errno: ("
00296             << errnum << ") " << lass_strerror(errnum);         
00297         raiserAddMessage(std::cerr, message);
00298         std::cerr << ".\n" << std::flush;
00299     }
00300 };
00301 
00302 
00303 
00304 /** Throws a run time exception for raisng LASS_ENFORCE_CLIB_RC.
00305  *  @internal
00306  *  @author Bram de Greve
00307  *  iRc contains error code and should not be zero.
00308  */
00309  struct ClibRcRaiser
00310  {
00311     template <typename T, typename C>
00312     static void raise(const T& rc, const C&, const std::string& message, const char* locus)
00313     {
00314         //LASS_ASSERT(iRc != 0);
00315         std::ostringstream buffer;
00316         buffer << "Function call " << locus << " failed with return code: ("
00317             << rc << ") " << lass_strerror(rc);         
00318         raiserAddMessage(buffer, message);
00319         LASS_THROW_EX(EnforceFailure, buffer.str());
00320     }
00321 };
00322 
00323 
00324 
00325 /** Throws a run time exception for raisng LASS_ENFORCE_CLIB_RC.
00326  *  @internal
00327  *  @author Bram de Greve
00328  *  iRc contains error code and should not be zero.
00329  */
00330  struct ClibRcWarner
00331  {
00332     template <typename T, typename C>
00333     static void raise(const T& rc, const C&, const std::string& message, const char* locus)
00334     {
00335         std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR: "
00336             << "Function call " << locus << " failed with return code: ("
00337             << rc << ") " << lass_strerror(rc);         
00338         raiserAddMessage(std::cerr, message);
00339         std::cerr << std::endl << std::flush;
00340     }
00341 };
00342 
00343 
00344 
00345 /** Throws an run time exception for raising LASS_ENFORCE_COM
00346  *  @internal
00347  *  @author Bram de Greve.
00348  */
00349 struct ComRaiser
00350 {
00351     template <typename T, typename C>
00352     static void raise(const T& hResult, const C&, const std::string& message, const char* locus)
00353     {
00354         std::ostringstream buffer;
00355         buffer << "Failure HRESULT '" << hResult << "' returned by " << locus;
00356         raiserAddMessage(buffer, message);
00357         LASS_THROW_EX(EnforceFailure, buffer.str());
00358     }
00359 };
00360 
00361 
00362 
00363 #ifdef LASS_HAS_GETLASTERROR
00364 
00365 /** Throws an exception using GetLastError() and FormatMessage().
00366  *  @internal
00367  *  @author Bram de Greve
00368  *  @arg only available on Windows platform
00369  */
00370 struct LastErrorRaiser
00371 {
00372     template <typename T, typename C>
00373     static void raise(const T&, const C&, const std::string& message, const char* locus)
00374     {
00375         std::ostringstream buffer;
00376         const unsigned lastError = lass_GetLastError();
00377         buffer << "Function call " << locus << " failed with last-error: ("
00378             << lastError << ") " << lass_FormatMessage(lastError);
00379         raiserAddMessage(buffer, message);
00380         LASS_THROW_EX(EnforceFailure, buffer.str());
00381     }
00382 };
00383 
00384 /** Writes warning to std::cerr using GetLastError() and FormatMessage().
00385  *  @internal
00386  *  @author Bram de Greve
00387  *  @arg only available on Windows platform
00388  */
00389 struct LastErrorWarner
00390 {
00391     template <typename T, typename C>
00392     static void raise(const T&, const C&, const std::string& message, const char* locus)
00393     {
00394         const unsigned lastError = lass_GetLastError();
00395         std::cerr << "Function call " << locus << " failed with last-error: ("
00396             << lastError << ") " << lass_FormatMessage(lastError);
00397         raiserAddMessage(std::cerr, message);
00398         std::cerr << std::endl << std::flush;
00399     }
00400 };
00401 
00402 #endif
00403 
00404 
00405 /** Throw a range error for LASS_ENFORCE_INDEX.
00406  *  @internal
00407  *  @author Bram de Greve.
00408  *  @pre type T must be streamable to a std::ostream.
00409  */
00410 struct IndexRaiser
00411 {
00412     template <typename T, typename C>
00413     static void raise(const T& index, const C& size, const std::string& message, const char* locus)
00414     {
00415         std::ostringstream buffer;
00416         buffer << "Value '" << index << "' is out of range [0, " << size << ") in '"
00417             << locus << "'";
00418         raiserAddMessage(buffer, message);
00419         LASS_THROW_EX(EnforceFailure, buffer.str());
00420     }
00421 };
00422 
00423 
00424 
00425 // --- Other helper stuff --------------------------------------------------------------------------
00426 
00427 /** Helper class of the enforce macro's.
00428  *  @internal
00429  *
00430  *  taken from:
00431  *  ALEXANDRESCU A. & MARGINEAN P. (2003), Enforcements. June 2003, C++ Experts Forum,
00432  *  http://www.cuj.com.
00433  *
00434  *  http://www.cuj.com/documents/s=8250/cujcexp2106alexandr
00435  */
00436 template
00437 <
00438     typename PredicateType,
00439     typename RaiserType,
00440     typename T,
00441     typename ClosureType
00442 >
00443 class Enforcer
00444 {
00445 public:
00446     Enforcer(T t, ClosureType closure, const char* locus):
00447         t_(t),
00448         closure_(closure),
00449         locus_(PredicateType::wrong(t, closure) ? locus : 0)
00450     {
00451         if (!locus)
00452         {
00453             std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: "
00454                 "Enforcer did not get a locus!\n" << std::flush;
00455         }
00456     }
00457 
00458     T operator*() const
00459     {
00460         if (locus_)
00461         {
00462             RaiserType::raise(t_, closure_, msg_, locus_);
00463         }
00464         return t_;
00465     }
00466 
00467     template <class MsgType>
00468     Enforcer& operator()(const MsgType& msg)
00469     {
00470         if (locus_)
00471         {
00472             // Here we have time; no need to be super-efficient
00473             std::ostringstream ss;
00474             ss << msg;
00475             msg_ += ss.str();
00476         }
00477         return *this;
00478     }
00479 
00480 private:
00481 
00482     T t_;
00483     ClosureType closure_;
00484     std::string msg_;
00485     const char* const locus_;
00486 };
00487 
00488 #if LASS_COMPILER_TYPE == LASS_COMPILER_TYPE_GCC && LASS_COMPILER_VERSION < 40000
00489 
00490 template <typename PredicateType, typename RaiserType>
00491 struct EnforcerMaker
00492 {
00493     template <typename T, typename C> inline
00494     static Enforcer<PredicateType, RaiserType, T&, const C&> make(
00495             T& t, const C& closure, const char* locus)
00496     {
00497         return Enforcer<PredicateType, RaiserType, T&, const C&>(
00498             t, closure, locus);
00499     }
00500 
00501     template <typename T, typename C> inline
00502     static Enforcer<PredicateType, RaiserType, const T&, const C&> make(
00503             const T& t, const C& closure, const char* locus)
00504     {
00505         return Enforcer<PredicateType, RaiserType, const T&, const C&>(
00506             t, closure, locus);
00507     }
00508 };
00509 
00510 #define LASS_UTIL_IMPL_MAKE_ENFORCER(predicate, raiser, t, closure, locus)\
00511     ::lass::util::impl::EnforcerMaker<predicate, raiser>::make(t, closure, locus)
00512 
00513 #else
00514 
00515 /** helper function to create enforcers
00516  *  @internal
00517  *  @relates lass::util::impl::Enforcer
00518  *
00519  *  taken from:
00520  *  ALEXANDRESCU A. & MARGINEAN P. (2003), Enforcements. June 2003, C++ Experts Forum,
00521  *  http://www.cuj.com.
00522  *
00523  *  http://www.cuj.com/documents/s=8250/cujcexp2106alexandr
00524  */
00525 template <typename PredicateType, typename RaiserType, typename T, typename C>
00526 inline Enforcer<PredicateType, RaiserType, T&, const C&> makeEnforcer(
00527         T& t, const C& closure, const char* locus)
00528 {
00529     return Enforcer<PredicateType, RaiserType, T&, const C&>(
00530         t, closure, locus);
00531 }
00532 
00533 template <typename PredicateType, typename RaiserType, typename T, typename C>
00534 inline Enforcer<PredicateType, RaiserType, const T&, const C&> makeEnforcer(
00535         const T& t, const C& closure, const char* locus)
00536 {
00537     return Enforcer<PredicateType, RaiserType, const T&, const C&>(
00538         t, closure, locus);
00539 }
00540 
00541 #define LASS_UTIL_IMPL_MAKE_ENFORCER(predicate, raiser, t, closure, locus)\
00542     ::lass::util::impl::makeEnforcer< predicate, raiser >(t, closure, locus)
00543 
00544 #endif
00545 
00546 }
00547 
00548 }
00549 
00550 }
00551 
00552 #endif
00553 
00554 // EOF

Generated on Mon Nov 10 14:20:04 2008 for Library of Assembled Shared Sources by doxygen 1.5.7.1
SourceForge.net Logo