currency.h

Go to the documentation of this file.
00001 00004 /* Copyright © 2001 Michael Geddes, Sofus Mortensen 00005 * 00006 * This material is provided "as is", with absolutely no warranty 00007 * expressed or implied. Any use is at your own risk. Permission to 00008 * use or copy this software for any purpose is hereby granted without 00009 * fee, provided the above notices are retained on all copies. 00010 * Permission to modify the code and to distribute modified code is 00011 * granted, provided the above notices are retained, and a notice that 00012 * the code was modified is included with the above copyright notice. 00013 * 00014 * This header is part of comet. 00015 * http://www.lambdasoft.dk/comet 00016 */ 00017 00018 #ifndef COMET_CURRENCY_H 00019 #define COMET_CURRENCY_H 00020 00021 #include <comet/config.h> 00022 00023 #include <comet/error_fwd.h> 00024 #include <comet/assert.h> 00025 00026 #include <wtypes.h> 00027 00028 #include <iostream> 00029 #include <algorithm> 00030 00031 namespace comet 00032 { 00033 00034 class bstr_t; 00035 00036 // currency_t 00038 00042 00047 class currency_t 00048 { 00049 public: 00051 currency_t() throw() { cy_.int64 = 0; } 00052 00054 currency_t(const CY &cy): cy_(cy) { } 00055 00057 explicit currency_t(double val) 00058 { 00059 VarCyFromR8(val,&cy_) | raise_exception; 00060 } 00061 00062 #if 0 00063 // //! Construct currency from CY/CURRENCY. 00064 // /*! 00065 // Takes ownership of specified CY value. To prevent misuse the CY must be wrapped using auto_attach. 00066 // 00067 // \code 00068 // currency_t cy( auto_attach( myCY ) ); 00069 // \endcode 00070 // 00071 // \param cyVal 00072 // Value to initialise currency_t from. 00073 // */ 00074 // currency_t( const impl::auto_attach_t<CY> &cyVal) throw() : cy_(cyVal.get()) 00075 // {} 00076 #endif //0 00077 00079 currency_t( long val ) 00080 { 00081 VarCyFromI4(val,&cy_) | raise_exception; 00082 } 00083 00084 currency_t( int val ) 00085 { 00086 VarCyFromI4(val,&cy_) | raise_exception; 00087 } 00088 00089 void swap(currency_t& c) throw() 00090 { 00091 std::swap(cy_, c.cy_); 00092 } 00093 00094 static const currency_t& create_const_reference(const CY& s) throw() 00095 { return *reinterpret_cast<const currency_t*>(&s); } 00096 00097 static currency_t& create_reference(CY& s) throw() 00098 { return *reinterpret_cast<currency_t*>(&s); } 00099 00101 00102 currency_t &operator=(double newVal) 00103 { 00104 currency_t c( newVal ); 00105 swap(c); 00106 return *this; 00107 } 00108 currency_t &operator=(long newVal) 00109 { 00110 currency_t c( newVal ); 00111 swap(c); 00112 return *this; 00113 } 00114 currency_t &operator=(int newVal) 00115 { 00116 currency_t c( newVal ); 00117 swap(c); 00118 return *this; 00119 } 00120 currency_t &operator=(const tagCY &newVal) throw() 00121 { 00122 cy_ = newVal; 00123 return *this; 00124 } 00126 00128 00129 currency_t &operator+=(const currency_t &cy) 00130 { 00131 currency_t c( *this + cy ); 00132 swap(c); 00133 return *this; 00134 } 00135 currency_t &operator-=(const currency_t &cy) 00136 { 00137 currency_t c( *this - cy ); 00138 swap(c); 00139 return *this; 00140 } 00141 currency_t &operator*=(const currency_t &cy) 00142 { 00143 currency_t c( *this * cy ); 00144 swap(c); 00145 return *this; 00146 } 00147 currency_t &operator*=(long cy) 00148 { 00149 currency_t c( *this * cy ); 00150 swap(c); 00151 return *this; 00152 } 00153 currency_t &operator*=(int val) 00154 { 00155 return operator*=((long)val); 00156 } 00157 currency_t &operator*=(double val) 00158 { 00159 cy_.int64 = (LONGLONG)(cy_.int64 * val); 00160 return *this; 00161 } 00162 00163 currency_t &operator/=(int val) const 00164 { 00165 return operator/=((long)val); 00166 } 00167 currency_t &operator/=(long val) 00168 { 00169 00170 if(!valid()) 00171 { 00172 // Check for invalid number 00173 return *this; 00174 } 00175 00176 // Check for divide by 0 00177 if (val == 0) 00178 { 00179 // Set to maximum negative value 00180 cy_.Hi = 0x80000000; 00181 cy_.Lo = 0x00000000; 00182 00183 return *this; 00184 } 00185 cy_.int64/=val; 00186 00187 return *this; 00188 } 00189 00190 currency_t operator+(const currency_t &cy)const 00191 { 00192 currency_t rv; 00193 VarCyAdd(cy_,cy.cy_,&rv.cy_) | raise_exception ; 00194 return rv; 00195 } 00196 currency_t operator-(const currency_t &cy)const 00197 { 00198 currency_t rv; 00199 VarCySub(cy_,cy.cy_,&rv.cy_) | raise_exception ; 00200 return rv; 00201 } 00202 currency_t operator*(const currency_t &cy)const 00203 { 00204 currency_t rv; 00205 VarCyMul(cy_,cy.cy_,&rv.cy_) | raise_exception ; 00206 return rv; 00207 } 00208 currency_t operator*(long cy)const 00209 { 00210 currency_t rv; 00211 VarCyMulI4(cy_,cy,&rv.cy_) | raise_exception; 00212 return rv; 00213 } 00214 currency_t operator*(int cy)const 00215 { 00216 return operator *((long)cy); 00217 } 00218 00219 currency_t operator*(double cy) const 00220 { 00221 currency_t val(*this); 00222 val *=cy; 00223 return val; 00224 } 00225 00226 00228 double operator/(const currency_t &cy)const 00229 { 00230 return ((double)cy_.int64 /(double)cy.cy_.int64); 00231 } 00232 00234 currency_t operator/(int val) const 00235 { 00236 return operator/((long)val); 00237 } 00239 currency_t operator/(long val) const 00240 { 00241 currency_t tmp(cy_); 00242 tmp/=val; 00243 return tmp; 00244 } 00245 00247 double operator/(double val) const 00248 { 00249 if(!valid()) 00250 { 00251 // Check for invalid number 00252 throw std::invalid_argument("Invalid divide"); 00253 } 00254 00255 // Check for divide by 0 00256 if (val == 0) 00257 { 00258 throw std::overflow_error("Divide by 0"); 00259 } 00260 return cy_.int64/(val*10000); 00261 } 00262 00264 currency_t operator-()const 00265 { 00266 currency_t cy; 00267 VarCyNeg(cy_,&(cy.cy_)) | raise_exception; 00268 return cy; 00269 } 00270 00272 00276 currency_t &round_to(int decimals) 00277 { 00278 VarCyRound(cy_,decimals,&cy_) | raise_exception; 00279 return *this; 00280 } 00281 00283 00284 00285 bool operator!=(const currency_t &cy) const { return cmp(cy)!=0; } 00286 bool operator!=(double val) const{ return cmp(val)!=0; } 00287 bool operator==(const currency_t &cy) const { return cmp(cy)==0; } 00288 bool operator==(double val) const{ return cmp(val)==0; } 00289 bool operator<=(const currency_t &cy) const{ return cmp(cy)<=0; } 00290 bool operator<=(double val) const{ return cmp(val)<=0; } 00291 bool operator>=(const currency_t &cy) const{ return cmp(cy)>=0; } 00292 bool operator>=(double val) const{ return cmp(val)>=0; } 00293 bool operator<(const currency_t &cy) const{ return cmp(cy)<0; } 00294 bool operator<(double val) const{ return cmp(val)<0; } 00295 bool operator>(const currency_t &cy) const{ return cmp(cy)>0; } 00296 bool operator>(double val) const{ return cmp(val)>0; } 00297 00299 00303 int cmp(const currency_t &cy) const 00304 { 00305 return _cmpResult(VarCyCmp(cy_,cy.cy_)); 00306 00307 } 00308 00312 int cmp(double cy) const 00313 { 00314 return _cmpResult(VarCyCmpR8(cy_,cy)); 00315 } 00316 00317 00319 00320 tagCY get() const { return cy_;} 00321 tagCY in() const { return cy_;} 00322 tagCY *in_ptr() const { return const_cast<CY*>(&cy_);} 00323 tagCY *out() { return &cy_;} 00324 tagCY *inout() { return &cy_;} 00326 00327 00328 #if 0 00329 friend std::ostream &operator <<(std::ostream &str, const currency_t &val) 00330 { 00331 std::string strval=val.format( 1, str.precision(), str.width() ); 00332 return str<< strval.c_str(); 00333 } 00334 #endif 00335 00336 00337 00338 friend 00339 std::basic_ostream<char> &operator<<(std::basic_ostream<char> &str, const currency_t &val) 00340 { 00341 std::basic_string<char> strval; 00342 val.do_format(strval, 1, str.precision(), str.width() ); 00343 return str << strval.c_str(); 00344 } 00345 00346 friend 00347 std::basic_ostream<wchar_t> &operator<<(std::basic_ostream<wchar_t> &str, const currency_t &val) 00348 { 00349 std::basic_string<wchar_t> strval; 00350 val.do_format(strval, 1, str.precision(), str.width() ); 00351 return str << strval.c_str(); 00352 } 00353 00355 std::basic_string<TCHAR> format(int mindigits=0,int minprecision=0, int width=0) const 00356 { 00357 std::basic_string<TCHAR> strval; 00358 do_format(strval, mindigits, minprecision, width); 00359 return strval; 00360 } 00361 00363 currency_t &parse( const bstr_t &str, LCID locale =::GetThreadLocale() ); 00364 /* { 00365 VarCyFromStr( str.in(), locale, 0, &cy_ ) | raise_exception; 00366 return *this; 00367 }*/ 00368 00369 protected: 00376 template <typename CH> 00377 void do_format(std::basic_string<CH> &val, int mindigits,int minprecision, int /*width*/) const 00378 { 00379 COMET_ASSERT(mindigits>=0 && minprecision >=0 ); 00380 if(minprecision> 4) minprecision =4; 00381 00382 // Add in the 4 fixed decimal points 00383 int pr=((0 <= minprecision && minprecision <=4)?(4-minprecision):0); 00384 mindigits+=4; 00385 00386 val.erase(); 00387 val.reserve(22); 00388 LONGLONG value=cy_.int64; 00389 bool neg=value<0; 00390 if(neg) 00391 { 00392 value=-value; 00393 } 00394 // Put in the digits backwards 00395 int digit=0; 00396 bool output=false; 00397 while(value !=0 || digit < mindigits) 00398 { 00399 CH dig=CH(value%10); 00400 if(output || true==(output= (dig >0 || digit>=pr))) // Once 'output' is set - output everything. 00401 { 00402 val+=(CH('0'+dig)); 00403 } 00404 if(++digit == 4) 00405 { 00406 val+=CH('.'); 00407 output=true; 00408 } 00409 value/=10; 00410 } 00411 if(neg) 00412 { 00413 val+=CH('-'); 00414 } 00415 00416 // Now reverse the digits 00417 std::reverse(val.begin(), val.end()); 00418 } 00419 public: 00420 00422 bool valid() const throw() 00423 { return !(cy_.Hi==(long)0x80000000 && cy_.Lo==0);} 00424 00426 CY detach() throw() 00427 { 00428 CY val = cy_; 00429 cy_.int64 = 0; 00430 return val; 00431 } 00432 00434 static CY detach(currency_t& cy) throw() 00435 { 00436 return cy.detach(); 00437 } 00438 00439 private: 00440 CY cy_; 00441 00442 static int _cmpResult(HRESULT hr) 00443 { 00444 if(SUCCEEDED(hr)) 00445 { 00446 switch(hr) 00447 { 00448 case VARCMP_LT: 00449 return -1; 00450 case VARCMP_EQ : 00451 return 0; 00452 case VARCMP_GT: 00453 return 1; 00454 case VARCMP_NULL: 00455 COMET_ASSERT(!"What do we do with this?"); 00456 } 00457 } 00458 else 00459 { 00460 hr | raise_exception; 00461 } 00462 return 0; // shut the compiler up 00463 } 00464 }; 00466 } 00467 00468 #endif // COMET_CURRENCY_H