$search
00001 00008 /***************************************************************************** 00009 ** Ifdefs 00010 *****************************************************************************/ 00011 00012 #ifndef ECL_FORMATTERS_NUMBER_HPP_ 00013 #define ECL_FORMATTERS_NUMBER_HPP_ 00014 00015 /***************************************************************************** 00016 ** Includes 00017 *****************************************************************************/ 00018 00019 #include "common.hpp" 00020 #include <ecl/exceptions/standard_exception.hpp> 00021 #include <ecl/converters/char_strings.hpp> 00022 00023 /***************************************************************************** 00024 ** Namespaces 00025 *****************************************************************************/ 00026 00027 namespace ecl { 00028 00029 /***************************************************************************** 00030 ** Format Tags 00031 *****************************************************************************/ 00037 enum IntegralBase 00038 { 00039 Bin, 00040 Hex, 00041 Dec, 00042 }; 00043 00044 namespace interfaces { 00045 00046 /***************************************************************************** 00047 ** FormatNumber Interface [Integral types] 00048 *****************************************************************************/ 00049 00056 template < typename Number > 00057 class FormatNumber { 00058 public: 00059 /****************************************** 00060 ** C&D's 00061 *******************************************/ 00068 FormatNumber(int w = -1, ecl::Alignment a = NoAlign, ecl::IntegralBase b = Dec) : prm_width(w),prm_alignment(a),prm_base(b),width_(&prm_width),alignment_(&prm_alignment),base_(&prm_base),ready_to_format(false) {} 00069 00070 virtual ~FormatNumber() {} 00071 00072 /****************************************** 00073 ** Set 00074 *******************************************/ 00080 FormatNumber<Number>& base(ecl::IntegralBase b); 00085 FormatNumber<Number>& width(int w); 00091 FormatNumber<Number>& align(ecl::Alignment a); 00092 00093 /****************************************** 00094 * Set Format Combinations 00095 ******************************************/ 00103 FormatNumber<Number>& operator ()(int w, ecl::Alignment a, ecl::IntegralBase b); 00104 00105 /****************************************** 00106 ** Format a value 00107 *******************************************/ 00114 FormatNumber<Number>& operator() (Number n); 00115 00116 /****************************************** 00117 ** Common format usages 00118 *******************************************/ 00127 FormatNumber<Number>& operator() (Number n, int w, ecl::IntegralBase b); 00137 FormatNumber<Number>& operator() (Number n, int w, ecl::Alignment a, ecl::IntegralBase b); 00138 00139 /****************************************** 00140 ** Insert the formatter into a stream 00141 *******************************************/ 00152 template <typename OutputStream, typename N> friend OutputStream& operator << (OutputStream& ostream, FormatNumber<N>& formatter) ecl_assert_throw_decl(StandardException); 00153 00154 protected: 00155 /****************************************** 00156 ** Paramaters 00157 *******************************************/ 00158 int prm_width, tmp_width; 00159 ecl::Alignment prm_alignment, tmp_alignment; 00160 ecl::IntegralBase prm_base, tmp_base; 00161 int *width_; 00162 ecl::Alignment *alignment_; IntegralBase *base_; 00163 bool ready_to_format; 00164 Number value_; 00165 00166 /****************************************** 00167 ** Padding 00168 *******************************************/ 00169 template <typename OutputStream> void pad(int n, OutputStream &ostream) const; 00170 template <typename OutputStream> void prePad(int n, OutputStream &ostream) const; 00171 template <typename OutputStream> void postPad(int n, OutputStream &ostream) const; 00172 00173 /****************************************** 00174 ** Formatter Functions 00175 *******************************************/ 00176 template <typename OutputStream> void formatBin(OutputStream &ostream) const; 00177 template <typename OutputStream> void formatHex(OutputStream &ostream) const; 00178 template <typename OutputStream> void formatDec(OutputStream &ostream) const; 00179 00180 }; // FormatNumber 00181 00182 /***************************************************************************** 00183 * FormatNumber Implementation [configuration] 00184 *****************************************************************************/ 00185 template <typename Number> 00186 FormatNumber<Number>& FormatNumber<Number>::base(ecl::IntegralBase b) 00187 { 00188 *base_ = b; 00189 return *this; 00190 } 00191 00192 template <typename Number> 00193 FormatNumber<Number>& FormatNumber<Number>::width(int w) 00194 { 00195 *width_ = w; 00196 if ( ( *width_ > 0 ) && ( *alignment_ == NoAlign ) ) { 00197 *alignment_ = RightAlign; 00198 } 00199 return *this; 00200 } 00201 00202 template <typename Number> 00203 FormatNumber<Number>& FormatNumber<Number>::align(ecl::Alignment a) 00204 { 00205 *alignment_ = a; 00206 if ( *alignment_ == NoAlign ) 00207 { 00208 *width_ = 0; 00209 } 00210 return *this; 00211 } 00212 template <typename Number> 00213 FormatNumber<Number>& FormatNumber<Number>::operator () (int w, ecl::Alignment a, ecl::IntegralBase b) 00214 { 00215 base(b); 00216 width(w); 00217 align(a); 00218 return *this; 00219 } 00220 00221 /***************************************************************************** 00222 * FormatNumber Implementation [internal formatting] 00223 *****************************************************************************/ 00224 template <typename Number> 00225 template <typename OutputStream> 00226 void FormatNumber<Number>::formatBin(OutputStream &ostream) const 00227 { 00228 int size = 8*sizeof(Number); 00229 prePad(*width_ - (size + 2),ostream); 00230 ostream << "0b"; 00231 for (int i = size - 1; i>=0; i--) 00232 { 00233 ostream << "01"[((value_ >> i) & 1)]; 00234 } 00235 postPad(*width_ - (size + 2),ostream); 00236 } 00237 00238 template <typename Number> 00239 template <typename OutputStream> 00240 void FormatNumber<Number>::formatHex(OutputStream &ostream) const 00241 { 00242 static const char hex_string[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; 00243 00244 int size = 2*sizeof(Number); 00245 prePad(*width_ - (size + 2),ostream); 00246 ostream << "0x"; 00247 for (int i = size - 1; i>=0; i--) 00248 { 00249 // ostream << "0123456789abcdef"[((value_ >> i*4) & 0xF)]; 00250 ostream << hex_string[((value_ >> i*4) & 0xF)]; // Dont have to recreate this every time 00251 } 00252 postPad(*width_ - (size + 2),ostream); 00253 } 00254 00255 template <typename Number> 00256 template <typename OutputStream> 00257 void FormatNumber<Number>::formatDec(OutputStream &ostream) const 00258 { 00259 static ecl::Converter<char*> convert; 00260 char *s = convert(value_); 00261 int size = strlen(s); 00262 prePad(*width_ - size,ostream); 00263 ostream << s; 00264 postPad(*width_ - size,ostream); 00265 } 00266 00267 template <typename Number> 00268 template <typename OutputStream> 00269 void FormatNumber<Number>::prePad(int n, OutputStream &ostream) const 00270 { 00271 if ( n <= 0 ) { return; } 00272 switch ( *alignment_ ) 00273 { 00274 case ( NoAlign ) : { break; } 00275 case ( LeftAlign ) : { break; } 00276 case ( RightAlign ) : { pad(n,ostream); break; } 00277 case ( CentreAlign ) : { pad(n/2+ n%2,ostream); break; } // Add the remainder 00278 default : break; 00279 } 00280 } 00281 00282 template <typename Number> 00283 template <typename OutputStream> 00284 void FormatNumber<Number>::postPad(int n, OutputStream &ostream) const 00285 { 00286 if ( n <= 0 ) { return; } 00287 switch ( *alignment_ ) 00288 { 00289 case ( NoAlign ) : { break; } 00290 case ( LeftAlign ) : { pad(n,ostream); break; } 00291 case ( RightAlign ) : { break; } 00292 case ( CentreAlign ) : { pad(n/2,ostream); break; } // Do not add the remainder 00293 default : break; 00294 } 00295 } 00296 00297 template <typename Number> 00298 template <typename OutputStream> 00299 void FormatNumber<Number>::pad(int n, OutputStream &ostream) const 00300 { 00301 for (int i = n; i > 0; --i ) 00302 { 00303 ostream << ' '; 00304 } 00305 } 00306 /***************************************************************************** 00307 * FormatNumber Implementation [value] 00308 *****************************************************************************/ 00312 template <typename Number> 00313 FormatNumber<Number>& FormatNumber<Number>::operator()(Number n) 00314 { 00315 value_ = n; 00316 ready_to_format = true; 00317 return *this; 00318 } 00319 00320 /***************************************************************************** 00321 * FormatNumber Implementation [temporary formatting] 00322 *****************************************************************************/ 00323 00327 template <typename Number> 00328 FormatNumber<Number>& FormatNumber<Number>::operator() (Number n, int w, ecl::IntegralBase b) 00329 { 00330 width_ = &tmp_width; 00331 alignment_ = &tmp_alignment; 00332 base_ = &tmp_base; 00333 base(b); 00334 width(w); 00335 value_ = n; 00336 ready_to_format = true; 00337 return *this; 00338 } 00342 template <typename Number> 00343 FormatNumber<Number>& FormatNumber<Number>::operator() (Number n, int w, ecl::Alignment a, ecl::IntegralBase b) 00344 { 00345 width_ = &tmp_width; 00346 alignment_ = &tmp_alignment; 00347 base_ = &tmp_base; 00348 base(b); 00349 width(w); 00350 align(a); 00351 value_ = n; 00352 ready_to_format = true; 00353 return *this; 00354 } 00355 00356 00357 /***************************************************************************** 00358 * FormatNumber Implementation [streaming] 00359 *****************************************************************************/ 00360 template <typename OutputStream, typename N> 00361 OutputStream& operator << (OutputStream &ostream, FormatNumber<N>& formatter ) ecl_assert_throw_decl(StandardException) 00362 { 00363 bool ready = formatter.ready_to_format; 00364 00365 ecl_assert_throw(ready, StandardException(LOC,UsageError,"The formatter cannot print any data - " 00366 "either there is no data available, or you have tried to use the " 00367 "formatter more than once in a single streaming operation. " 00368 "C++ produces unspecified results when functors are used multiply " 00369 "in the same stream sequence, so this is not permitted here.") ); 00370 00371 if ( ready ) 00372 { 00373 switch(*(formatter.base_) ) 00374 { 00375 case(Bin) : { 00376 formatter.formatBin(ostream); 00377 break; 00378 } 00379 case(Hex) : { 00380 formatter.formatHex(ostream); 00381 break; 00382 } 00383 case(Dec) : { 00384 formatter.formatDec(ostream); 00385 break; 00386 } 00387 } 00388 if ( formatter.width_ != &(formatter.prm_width) ) { 00389 formatter.width_ = &(formatter.prm_width); 00390 formatter.alignment_ = &(formatter.prm_alignment); 00391 formatter.base_ = &(formatter.prm_base); 00392 } 00393 formatter.ready_to_format = false; 00394 } 00395 return ostream; 00396 } 00397 00398 } // namespace interfaces 00399 00400 /***************************************************************************** 00401 * Format Classes 00402 *****************************************************************************/ 00407 template <> 00408 class Format<short> : public interfaces::FormatNumber<short> 00409 { 00410 public: 00417 Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<short>(w, a, b) {} 00418 virtual ~Format() {} 00419 }; 00424 template <> 00425 class Format<int> : public interfaces::FormatNumber<int> 00426 { 00427 public: 00434 Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<int>(w, a, b) {} 00435 virtual ~Format() {} 00436 }; 00441 template <> 00442 class Format<long> : public interfaces::FormatNumber<long> 00443 { 00444 public: 00451 Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<long>(w, a, b) {} 00452 virtual ~Format() {} 00453 }; 00454 00459 template <> 00460 class Format<char> : public interfaces::FormatNumber<char> 00461 { 00462 public: 00469 Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<char>(w, a, b) {} 00470 virtual ~Format() {} 00471 }; 00472 00477 template <> 00478 class Format<signed char> : public interfaces::FormatNumber<signed char> 00479 { 00480 public: 00487 Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<signed char>(w, a, b) {} 00488 virtual ~Format() {} 00489 }; 00490 00495 template <> 00496 class Format<unsigned short> : public interfaces::FormatNumber<unsigned short> 00497 { 00498 public: 00505 Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<unsigned short>(w, a, b) {} 00506 virtual ~Format() {} 00507 }; 00508 00513 template <> 00514 class Format<unsigned int> : public interfaces::FormatNumber<unsigned int> 00515 { 00516 public: 00523 Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<unsigned int>(w, a, b) {} 00524 virtual ~Format() {} 00525 }; 00530 template <> 00531 class Format<unsigned long> : public interfaces::FormatNumber<unsigned long> 00532 { 00533 public: 00540 Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<unsigned long>(w, a, b) {} 00541 virtual ~Format() {} 00542 }; 00547 template <> 00548 class Format<unsigned char> : public interfaces::FormatNumber<unsigned char> 00549 { 00550 public: 00551 Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<unsigned char>(w, a, b) {} 00552 virtual ~Format() {} 00553 }; 00554 00555 }; // namespace ecl 00556 00557 #endif /*ECL_FORMATTERS_NUMBER_HPP_*/