Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members

misc.h

00001 #ifndef CRYPTOPP_MISC_H 00002 #define CRYPTOPP_MISC_H 00003 00004 #include "cryptopp_config.h" 00005 #include "cryptlib.h" 00006 #include <assert.h> 00007 #include <string.h> // CodeWarrior doesn't have memory.h 00008 #include <algorithm> 00009 #include <string> 00010 00011 #ifdef INTEL_INTRINSICS 00012 #include <stdlib.h> 00013 #endif 00014 00015 NAMESPACE_BEGIN(CryptoPP) 00016 00017 // ************** compile-time assertion *************** 00018 00019 template <bool b> 00020 struct CompileAssert 00021 { 00022 static char dummy[2*b-1]; 00023 }; 00024 00025 #define CRYPTOPP_COMPILE_ASSERT(assertion) CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, __LINE__) 00026 #define CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, instance) static CompileAssert<(assertion)> CRYPTOPP_ASSERT_JOIN(cryptopp_assert_, instance) 00027 #define CRYPTOPP_ASSERT_JOIN(X, Y) CRYPTOPP_DO_ASSERT_JOIN(X, Y) 00028 #define CRYPTOPP_DO_ASSERT_JOIN(X, Y) X##Y 00029 00030 // ************** misc classes *************** 00031 00032 class Empty 00033 { 00034 }; 00035 00036 template <class BASE1, class BASE2> 00037 class TwoBases : public BASE1, public BASE2 00038 { 00039 }; 00040 00041 template <class BASE1, class BASE2, class BASE3> 00042 class ThreeBases : public BASE1, public BASE2, public BASE3 00043 { 00044 }; 00045 00046 template <class T> 00047 class ObjectHolder 00048 { 00049 protected: 00050 T m_object; 00051 }; 00052 00053 class NotCopyable 00054 { 00055 public: 00056 NotCopyable() {} 00057 private: 00058 NotCopyable(const NotCopyable &); 00059 void operator=(const NotCopyable &); 00060 }; 00061 00062 // ************** misc functions *************** 00063 00064 // can't use std::min or std::max in MSVC60 or Cygwin 1.1.0 00065 template <class _Tp> inline const _Tp& STDMIN(const _Tp& __a, const _Tp& __b) 00066 { 00067 return __b < __a ? __b : __a; 00068 } 00069 00070 template <class _Tp> inline const _Tp& STDMAX(const _Tp& __a, const _Tp& __b) 00071 { 00072 return __a < __b ? __b : __a; 00073 } 00074 00075 #define RETURN_IF_NONZERO(x) unsigned int returnedValue = x; if (returnedValue) return returnedValue 00076 00077 // this version of the macro is fastest on Pentium 3 and Pentium 4 with MSVC 6 SP5 w/ Processor Pack 00078 #define GETBYTE(x, y) (unsigned int)byte((x)>>(8*(y))) 00079 // these may be faster on other CPUs/compilers 00080 // #define GETBYTE(x, y) (unsigned int)(((x)>>(8*(y)))&255) 00081 // #define GETBYTE(x, y) (((byte *)&(x))[y]) 00082 00083 unsigned int Parity(unsigned long); 00084 unsigned int BytePrecision(unsigned long); 00085 unsigned int BitPrecision(unsigned long); 00086 unsigned long Crop(unsigned long, unsigned int size); 00087 00088 inline unsigned int BitsToBytes(unsigned int bitCount) 00089 { 00090 return ((bitCount+7)/(8)); 00091 } 00092 00093 inline unsigned int BytesToWords(unsigned int byteCount) 00094 { 00095 return ((byteCount+WORD_SIZE-1)/WORD_SIZE); 00096 } 00097 00098 inline unsigned int BitsToWords(unsigned int bitCount) 00099 { 00100 return ((bitCount+WORD_BITS-1)/(WORD_BITS)); 00101 } 00102 00103 void xorbuf(byte *buf, const byte *mask, unsigned int count); 00104 void xorbuf(byte *output, const byte *input, const byte *mask, unsigned int count); 00105 00106 template <class T> 00107 inline bool IsPowerOf2(T n) 00108 { 00109 return n > 0 && (n & (n-1)) == 0; 00110 } 00111 00112 template <class T1, class T2> 00113 inline T2 ModPowerOf2(T1 a, T2 b) 00114 { 00115 assert(IsPowerOf2(b)); 00116 return T2(a) & (b-1); 00117 } 00118 00119 template <class T> 00120 inline T RoundDownToMultipleOf(T n, T m) 00121 { 00122 return n - (IsPowerOf2(m) ? ModPowerOf2(n, m) : (n%m)); 00123 } 00124 00125 template <class T> 00126 inline T RoundUpToMultipleOf(T n, T m) 00127 { 00128 return RoundDownToMultipleOf(n+m-1, m); 00129 } 00130 00131 template <class T> 00132 inline unsigned int GetAlignment(T *dummy=NULL) // VC60 workaround 00133 { 00134 #if (_MSC_VER >= 1300) 00135 return __alignof(T); 00136 #elif defined(__GNUC__) 00137 return __alignof__(T); 00138 #else 00139 return sizeof(T); 00140 #endif 00141 } 00142 00143 inline bool IsAlignedOn(const void *p, unsigned int alignment) 00144 { 00145 return IsPowerOf2(alignment) ? ModPowerOf2((unsigned int)p, alignment) == 0 : (unsigned int)p % alignment == 0; 00146 } 00147 00148 template <class T> 00149 inline bool IsAligned(const void *p, T *dummy=NULL) // VC60 workaround 00150 { 00151 return IsAlignedOn(p, GetAlignment<T>()); 00152 } 00153 00154 #ifdef IS_LITTLE_ENDIAN 00155 typedef LittleEndian NativeByteOrder; 00156 #else 00157 typedef BigEndian NativeByteOrder; 00158 #endif 00159 00160 inline ByteOrder GetNativeByteOrder() 00161 { 00162 return NativeByteOrder::ToEnum(); 00163 } 00164 00165 inline bool NativeByteOrderIs(ByteOrder order) 00166 { 00167 return order == GetNativeByteOrder(); 00168 } 00169 00170 template <class T> // can't use <sstream> because GCC 2.95.2 doesn't have it 00171 std::string IntToString(T a, unsigned int base = 10) 00172 { 00173 if (a == 0) 00174 return "0"; 00175 bool negate = false; 00176 if (a < 0) 00177 { 00178 negate = true; 00179 a = 0-a; // VC .NET does not like -a 00180 } 00181 std::string result; 00182 while (a > 0) 00183 { 00184 T digit = a % base; 00185 result = char((digit < 10 ? '0' : ('a' - 10)) + digit) + result; 00186 a /= base; 00187 } 00188 if (negate) 00189 result = "-" + result; 00190 return result; 00191 } 00192 00193 template <class T1, class T2> 00194 inline T1 SaturatingSubtract(T1 a, T2 b) 00195 { 00196 CRYPTOPP_COMPILE_ASSERT_INSTANCE(T1(-1)>0, 0); // T1 is unsigned type 00197 CRYPTOPP_COMPILE_ASSERT_INSTANCE(T2(-1)>0, 1); // T2 is unsigned type 00198 return T1((a > b) ? (a - b) : 0); 00199 } 00200 00201 template <class T> 00202 inline CipherDir GetCipherDir(const T &obj) 00203 { 00204 return obj.IsForwardTransformation() ? ENCRYPTION : DECRYPTION; 00205 } 00206 00207 // ************** rotate functions *************** 00208 00209 template <class T> inline T rotlFixed(T x, unsigned int y) 00210 { 00211 assert(y < sizeof(T)*8); 00212 return (x<<y) | (x>>(sizeof(T)*8-y)); 00213 } 00214 00215 template <class T> inline T rotrFixed(T x, unsigned int y) 00216 { 00217 assert(y < sizeof(T)*8); 00218 return (x>>y) | (x<<(sizeof(T)*8-y)); 00219 } 00220 00221 template <class T> inline T rotlVariable(T x, unsigned int y) 00222 { 00223 assert(y < sizeof(T)*8); 00224 return (x<<y) | (x>>(sizeof(T)*8-y)); 00225 } 00226 00227 template <class T> inline T rotrVariable(T x, unsigned int y) 00228 { 00229 assert(y < sizeof(T)*8); 00230 return (x>>y) | (x<<(sizeof(T)*8-y)); 00231 } 00232 00233 template <class T> inline T rotlMod(T x, unsigned int y) 00234 { 00235 y %= sizeof(T)*8; 00236 return (x<<y) | (x>>(sizeof(T)*8-y)); 00237 } 00238 00239 template <class T> inline T rotrMod(T x, unsigned int y) 00240 { 00241 y %= sizeof(T)*8; 00242 return (x>>y) | (x<<(sizeof(T)*8-y)); 00243 } 00244 00245 #ifdef INTEL_INTRINSICS 00246 00247 #pragma intrinsic(_lrotl, _lrotr) 00248 00249 template<> inline word32 rotlFixed<word32>(word32 x, unsigned int y) 00250 { 00251 assert(y < 32); 00252 return y ? _lrotl(x, y) : x; 00253 } 00254 00255 template<> inline word32 rotrFixed<word32>(word32 x, unsigned int y) 00256 { 00257 assert(y < 32); 00258 return y ? _lrotr(x, y) : x; 00259 } 00260 00261 template<> inline word32 rotlVariable<word32>(word32 x, unsigned int y) 00262 { 00263 assert(y < 32); 00264 return _lrotl(x, y); 00265 } 00266 00267 template<> inline word32 rotrVariable<word32>(word32 x, unsigned int y) 00268 { 00269 assert(y < 32); 00270 return _lrotr(x, y); 00271 } 00272 00273 template<> inline word32 rotlMod<word32>(word32 x, unsigned int y) 00274 { 00275 return _lrotl(x, y); 00276 } 00277 00278 template<> inline word32 rotrMod<word32>(word32 x, unsigned int y) 00279 { 00280 return _lrotr(x, y); 00281 } 00282 00283 #endif // #ifdef INTEL_INTRINSICS 00284 00285 #ifdef PPC_INTRINSICS 00286 00287 template<> inline word32 rotlFixed<word32>(word32 x, unsigned int y) 00288 { 00289 assert(y < 32); 00290 return y ? __rlwinm(x,y,0,31) : x; 00291 } 00292 00293 template<> inline word32 rotrFixed<word32>(word32 x, unsigned int y) 00294 { 00295 assert(y < 32); 00296 return y ? __rlwinm(x,32-y,0,31) : x; 00297 } 00298 00299 template<> inline word32 rotlVariable<word32>(word32 x, unsigned int y) 00300 { 00301 assert(y < 32); 00302 return (__rlwnm(x,y,0,31)); 00303 } 00304 00305 template<> inline word32 rotrVariable<word32>(word32 x, unsigned int y) 00306 { 00307 assert(y < 32); 00308 return (__rlwnm(x,32-y,0,31)); 00309 } 00310 00311 template<> inline word32 rotlMod<word32>(word32 x, unsigned int y) 00312 { 00313 return (__rlwnm(x,y,0,31)); 00314 } 00315 00316 template<> inline word32 rotrMod<word32>(word32 x, unsigned int y) 00317 { 00318 return (__rlwnm(x,32-y,0,31)); 00319 } 00320 00321 #endif // #ifdef PPC_INTRINSICS 00322 00323 // ************** endian reversal *************** 00324 00325 template <class T> 00326 inline unsigned int GetByte(ByteOrder order, T value, unsigned int index) 00327 { 00328 if (order == LITTLE_ENDIAN_ORDER) 00329 return GETBYTE(value, index); 00330 else 00331 return GETBYTE(value, sizeof(T)-index-1); 00332 } 00333 00334 inline byte ByteReverse(byte value) 00335 { 00336 return value; 00337 } 00338 00339 inline word16 ByteReverse(word16 value) 00340 { 00341 return rotlFixed(value, 8U); 00342 } 00343 00344 inline word32 ByteReverse(word32 value) 00345 { 00346 #ifdef PPC_INTRINSICS 00347 // PPC: load reverse indexed instruction 00348 return (word32)__lwbrx(&value,0); 00349 #elif defined(FAST_ROTATE) 00350 // 5 instructions with rotate instruction, 9 without 00351 return (rotrFixed(value, 8U) & 0xff00ff00) | (rotlFixed(value, 8U) & 0x00ff00ff); 00352 #else 00353 // 6 instructions with rotate instruction, 8 without 00354 value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); 00355 return rotlFixed(value, 16U); 00356 #endif 00357 } 00358 00359 #ifdef WORD64_AVAILABLE 00360 inline word64 ByteReverse(word64 value) 00361 { 00362 #ifdef SLOW_WORD64 00363 return (word64(ByteReverse(word32(value))) << 32) | ByteReverse(word32(value>>32)); 00364 #else 00365 value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) | ((value & W64LIT(0x00FF00FF00FF00FF)) << 8); 00366 value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) | ((value & W64LIT(0x0000FFFF0000FFFF)) << 16); 00367 return rotlFixed(value, 32U); 00368 #endif 00369 } 00370 #endif 00371 00372 inline byte BitReverse(byte value) 00373 { 00374 value = ((value & 0xAA) >> 1) | ((value & 0x55) << 1); 00375 value = ((value & 0xCC) >> 2) | ((value & 0x33) << 2); 00376 return rotlFixed(value, 4); 00377 } 00378 00379 inline word16 BitReverse(word16 value) 00380 { 00381 value = ((value & 0xAAAA) >> 1) | ((value & 0x5555) << 1); 00382 value = ((value & 0xCCCC) >> 2) | ((value & 0x3333) << 2); 00383 value = ((value & 0xF0F0) >> 4) | ((value & 0x0F0F) << 4); 00384 return ByteReverse(value); 00385 } 00386 00387 inline word32 BitReverse(word32 value) 00388 { 00389 value = ((value & 0xAAAAAAAA) >> 1) | ((value & 0x55555555) << 1); 00390 value = ((value & 0xCCCCCCCC) >> 2) | ((value & 0x33333333) << 2); 00391 value = ((value & 0xF0F0F0F0) >> 4) | ((value & 0x0F0F0F0F) << 4); 00392 return ByteReverse(value); 00393 } 00394 00395 #ifdef WORD64_AVAILABLE 00396 inline word64 BitReverse(word64 value) 00397 { 00398 #ifdef SLOW_WORD64 00399 return (word64(BitReverse(word32(value))) << 32) | BitReverse(word32(value>>32)); 00400 #else 00401 value = ((value & W64LIT(0xAAAAAAAAAAAAAAAA)) >> 1) | ((value & W64LIT(0x5555555555555555)) << 1); 00402 value = ((value & W64LIT(0xCCCCCCCCCCCCCCCC)) >> 2) | ((value & W64LIT(0x3333333333333333)) << 2); 00403 value = ((value & W64LIT(0xF0F0F0F0F0F0F0F0)) >> 4) | ((value & W64LIT(0x0F0F0F0F0F0F0F0F)) << 4); 00404 return ByteReverse(value); 00405 #endif 00406 } 00407 #endif 00408 00409 template <class T> 00410 inline T BitReverse(T value) 00411 { 00412 if (sizeof(T) == 1) 00413 return (T)BitReverse((byte)value); 00414 else if (sizeof(T) == 2) 00415 return (T)BitReverse((word16)value); 00416 else if (sizeof(T) == 4) 00417 return (T)BitReverse((word32)value); 00418 else 00419 { 00420 #ifdef WORD64_AVAILABLE 00421 assert(sizeof(T) == 8); 00422 return (T)BitReverse((word64)value); 00423 #else 00424 assert(false); 00425 return 0; 00426 #endif 00427 } 00428 } 00429 00430 template <class T> 00431 inline T ConditionalByteReverse(ByteOrder order, T value) 00432 { 00433 return NativeByteOrderIs(order) ? value : ByteReverse(value); 00434 } 00435 00436 template <class T> 00437 void ByteReverse(T *out, const T *in, unsigned int byteCount) 00438 { 00439 assert(byteCount % sizeof(T) == 0); 00440 unsigned int count = byteCount/sizeof(T); 00441 for (unsigned int i=0; i<count; i++) 00442 out[i] = ByteReverse(in[i]); 00443 } 00444 00445 template <class T> 00446 inline void ConditionalByteReverse(ByteOrder order, T *out, const T *in, unsigned int byteCount) 00447 { 00448 if (!NativeByteOrderIs(order)) 00449 ByteReverse(out, in, byteCount); 00450 else if (in != out) 00451 memcpy(out, in, byteCount); 00452 } 00453 00454 template <class T> 00455 inline void GetUserKey(ByteOrder order, T *out, unsigned int outlen, const byte *in, unsigned int inlen) 00456 { 00457 const unsigned int U = sizeof(T); 00458 assert(inlen <= outlen*U); 00459 memcpy(out, in, inlen); 00460 memset((byte *)out+inlen, 0, outlen*U-inlen); 00461 ConditionalByteReverse(order, out, out, RoundUpToMultipleOf(inlen, U)); 00462 } 00463 00464 inline byte UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, byte*) 00465 { 00466 return block[0]; 00467 } 00468 00469 inline word16 UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, word16*) 00470 { 00471 return (order == BIG_ENDIAN_ORDER) 00472 ? block[1] | (block[0] << 8) 00473 : block[0] | (block[1] << 8); 00474 } 00475 00476 inline word32 UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, word32*) 00477 { 00478 return (order == BIG_ENDIAN_ORDER) 00479 ? word32(block[3]) | (word32(block[2]) << 8) | (word32(block[1]) << 16) | (word32(block[0]) << 24) 00480 : word32(block[0]) | (word32(block[1]) << 8) | (word32(block[2]) << 16) | (word32(block[3]) << 24); 00481 } 00482 00483 template <class T> 00484 inline T UnalignedGetWord(ByteOrder order, const byte *block, T*dummy=NULL) 00485 { 00486 return UnalignedGetWordNonTemplate(order, block, dummy); 00487 } 00488 00489 inline void UnalignedPutWord(ByteOrder order, byte *block, byte value, const byte *xorBlock = NULL) 00490 { 00491 block[0] = xorBlock ? (value ^ xorBlock[0]) : value; 00492 } 00493 00494 inline void UnalignedPutWord(ByteOrder order, byte *block, word16 value, const byte *xorBlock = NULL) 00495 { 00496 if (order == BIG_ENDIAN_ORDER) 00497 { 00498 block[0] = GETBYTE(value, 1); 00499 block[1] = GETBYTE(value, 0); 00500 } 00501 else 00502 { 00503 block[0] = GETBYTE(value, 0); 00504 block[1] = GETBYTE(value, 1); 00505 } 00506 00507 if (xorBlock) 00508 { 00509 block[0] ^= xorBlock[0]; 00510 block[1] ^= xorBlock[1]; 00511 } 00512 } 00513 00514 inline void UnalignedPutWord(ByteOrder order, byte *block, word32 value, const byte *xorBlock = NULL) 00515 { 00516 if (order == BIG_ENDIAN_ORDER) 00517 { 00518 block[0] = GETBYTE(value, 3); 00519 block[1] = GETBYTE(value, 2); 00520 block[2] = GETBYTE(value, 1); 00521 block[3] = GETBYTE(value, 0); 00522 } 00523 else 00524 { 00525 block[0] = GETBYTE(value, 0); 00526 block[1] = GETBYTE(value, 1); 00527 block[2] = GETBYTE(value, 2); 00528 block[3] = GETBYTE(value, 3); 00529 } 00530 00531 if (xorBlock) 00532 { 00533 block[0] ^= xorBlock[0]; 00534 block[1] ^= xorBlock[1]; 00535 block[2] ^= xorBlock[2]; 00536 block[3] ^= xorBlock[3]; 00537 } 00538 } 00539 00540 template <class T> 00541 inline T GetWord(bool assumeAligned, ByteOrder order, const byte *block) 00542 { 00543 if (assumeAligned) 00544 { 00545 assert(IsAligned<T>(block)); 00546 return ConditionalByteReverse(order, *reinterpret_cast<const T *>(block)); 00547 } 00548 else 00549 return UnalignedGetWord<T>(order, block); 00550 } 00551 00552 template <class T> 00553 inline void GetWord(bool assumeAligned, ByteOrder order, T &result, const byte *block) 00554 { 00555 result = GetWord<T>(assumeAligned, order, block); 00556 } 00557 00558 template <class T> 00559 inline void PutWord(bool assumeAligned, ByteOrder order, byte *block, T value, const byte *xorBlock = NULL) 00560 { 00561 if (assumeAligned) 00562 { 00563 assert(IsAligned<T>(block)); 00564 if (xorBlock) 00565 *reinterpret_cast<T *>(block) = ConditionalByteReverse(order, value) ^ *reinterpret_cast<const T *>(xorBlock); 00566 else 00567 *reinterpret_cast<T *>(block) = ConditionalByteReverse(order, value); 00568 } 00569 else 00570 UnalignedPutWord(order, block, value, xorBlock); 00571 } 00572 00573 template <class T, class B, bool A=true> 00574 class GetBlock 00575 { 00576 public: 00577 GetBlock(const void *block) 00578 : m_block((const byte *)block) {} 00579 00580 template <class U> 00581 inline GetBlock<T, B, A> & operator()(U &x) 00582 { 00583 CRYPTOPP_COMPILE_ASSERT(sizeof(U) >= sizeof(T)); 00584 x = GetWord<T>(A, B::ToEnum(), m_block); 00585 m_block += sizeof(T); 00586 return *this; 00587 } 00588 00589 private: 00590 const byte *m_block; 00591 }; 00592 00593 template <class T, class B, bool A=true> 00594 class PutBlock 00595 { 00596 public: 00597 PutBlock(const void *xorBlock, void *block) 00598 : m_xorBlock((const byte *)xorBlock), m_block((byte *)block) {} 00599 00600 template <class U> 00601 inline PutBlock<T, B, A> & operator()(U x) 00602 { 00603 PutWord(A, B::ToEnum(), m_block, (T)x, m_xorBlock); 00604 m_block += sizeof(T); 00605 if (m_xorBlock) 00606 m_xorBlock += sizeof(T); 00607 return *this; 00608 } 00609 00610 private: 00611 const byte *m_xorBlock; 00612 byte *m_block; 00613 }; 00614 00615 template <class T, class B, bool A=true> 00616 struct BlockGetAndPut 00617 { 00618 // function needed because of C++ grammatical ambiguity between expression-statements and declarations 00619 static inline GetBlock<T, B, A> Get(const void *block) {return GetBlock<T, B, A>(block);} 00620 typedef PutBlock<T, B, A> Put; 00621 }; 00622 00623 template <class T> 00624 std::string WordToString(T value, ByteOrder order = BIG_ENDIAN_ORDER) 00625 { 00626 if (!NativeByteOrderIs(order)) 00627 value = ByteReverse(value); 00628 00629 return std::string((char *)&value, sizeof(value)); 00630 } 00631 00632 template <class T> 00633 T StringToWord(const std::string &str, ByteOrder order = BIG_ENDIAN_ORDER) 00634 { 00635 T value = 0; 00636 memcpy(&value, str.data(), STDMIN(sizeof(value), str.size())); 00637 return NativeByteOrderIs(order) ? value : ByteReverse(value); 00638 } 00639 00640 // ************** help remove warning on g++ *************** 00641 00642 template <bool overflow> struct SafeShifter; 00643 00644 template<> struct SafeShifter<true> 00645 { 00646 template <class T> 00647 static inline T RightShift(T value, unsigned int bits) 00648 { 00649 return 0; 00650 } 00651 00652 template <class T> 00653 static inline T LeftShift(T value, unsigned int bits) 00654 { 00655 return 0; 00656 } 00657 }; 00658 00659 template<> struct SafeShifter<false> 00660 { 00661 template <class T> 00662 static inline T RightShift(T value, unsigned int bits) 00663 { 00664 return value >> bits; 00665 } 00666 00667 template <class T> 00668 static inline T LeftShift(T value, unsigned int bits) 00669 { 00670 return value << bits; 00671 } 00672 }; 00673 00674 template <unsigned int bits, class T> 00675 inline T SafeRightShift(T value) 00676 { 00677 return SafeShifter<(bits>=(8*sizeof(T)))>::RightShift(value, bits); 00678 } 00679 00680 template <unsigned int bits, class T> 00681 inline T SafeLeftShift(T value) 00682 { 00683 return SafeShifter<(bits>=(8*sizeof(T)))>::LeftShift(value, bits); 00684 } 00685 00686 NAMESPACE_END 00687 00688 #endif // MISC_H

Generated on Wed Jul 28 08:07:08 2004 for Crypto++ by doxygen 1.3.7