User Manual, Developers Guide and API Documentation

Enumerator.hpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002  * This file is part of openWNS (open Wireless Network Simulator)
00003  * _____________________________________________________________________________
00004  *
00005  * Copyright (C) 2004-2007
00006  * Chair of Communication Networks (ComNets)
00007  * Kopernikusstr. 16, D-52074 Aachen, Germany
00008  * phone: ++49-241-80-27910,
00009  * fax: ++49-241-80-22242
00010  * email: info@openwns.org
00011  * www: http://www.openwns.org
00012  * _____________________________________________________________________________
00013  *
00014  * openWNS is free software; you can redistribute it and/or modify it under the
00015  * terms of the GNU Lesser General Public License version 2 as published by the
00016  * Free Software Foundation;
00017  *
00018  * openWNS is distributed in the hope that it will be useful, but WITHOUT ANY
00019  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
00020  * A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00021  * details.
00022  *
00023  * You should have received a copy of the GNU Lesser General Public License
00024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00025  *
00026  ******************************************************************************/
00027 
00028 #ifndef _ENUMERATOR_HPP
00029 #define _ENUMERATOR_HPP
00030 
00031 #include <limits>
00032 #include <cmath>
00033 #include <stdexcept>
00034 
00035 #include <WNS/Types.hpp>
00036 
00037 namespace wns
00038 {
00039 
00047     class Enumerator
00048     {
00049     public:
00050 
00056     template<typename T>
00057     static inline T succ(const T& v) { T temp = v; return ++temp; }
00058     
00059     static inline float succ(const float& v) { return fp_succ(v); }
00060 
00061     static inline double succ(const double& v) { return fp_succ(v); }
00062 
00063     static inline long double succ(const long double& v) { return fp_succ(v); }
00064 
00070     template<typename T>
00071     static inline T pred(const T& v) { T temp = v; return --temp; }
00072 
00073     static inline float pred(const float& v) { return fp_pred(v); }
00074 
00075     static inline double pred(const double& v) { return fp_pred(v); }
00076 
00077     static inline long double pred(const long double& v) { return fp_pred(v); }
00078 
00079     private:
00080 
00081     // For IEEE 754/IEC 559 compatible representations of
00082     // floating point numbers enumeration could be done
00083     // by simply incrementing/decrementing the binary
00084     // representation (and take care of the bounds 0, +/-inf).
00085     // But as IEEE 754/IEC 559 compatibility is not required
00086     // by C++ (otherwise we wouldn't need much of numeric_limits),
00087     // the enumeration is implemented more generic
00088     // (which also means less low-level); especially since I do not
00089     // expect these functions to be used in time critical
00090     // situations (inner loops etc.).
00091     // If they ever are, one could consider bloating these functions/
00092     // this class with specialised increment/decrement for IEEE/IEC FP.
00093     // (if (numeric_limits<T>::is_iec559) ...)
00094 
00095     template<typename T>
00096     static inline T fp_succ(const T& v)
00097     {
00098         // NaNs don't have successors
00099         if ((std::numeric_limits<T>::has_quiet_NaN
00100          && (v == std::numeric_limits<T>::quiet_NaN()))
00101         || (std::numeric_limits<T>::has_signaling_NaN
00102             && (v == std::numeric_limits<T>::signaling_NaN())))
00103         throw std::invalid_argument("No successor for a NaN");
00104         // take care of upper bound (inf/max)
00105         if (std::numeric_limits<T>::has_infinity) {
00106         // type has infinity
00107         if (v == std::numeric_limits<T>::max())
00108             return std::numeric_limits<T>::infinity();
00109         else if (v == -std::numeric_limits<T>::infinity())
00110             return -std::numeric_limits<T>::max();
00111         else if (v == std::numeric_limits<T>::infinity())
00112             throw std::out_of_range("No successor of infinity");
00113         }
00114         else if (v == std::numeric_limits<T>::max())
00115         // type does not have infinity and thus no larger "value"
00116         throw std::out_of_range("No successor of largest value");
00117 
00118         // take care of "-" -> "0" -> "+" transition
00119         if (v == -std::numeric_limits<T>::denorm_min()) return 0.0;
00120         else if (v == 0.0) return std::numeric_limits<T>::denorm_min();
00121         else {
00122         // let's increase the least significant digit of the mantissa
00123 
00124         const SizeType digitsSign = 1;
00125         const SizeType digitsMantissa = std::numeric_limits<T>::digits - digitsSign;
00126         const SizeType radix = std::numeric_limits<T>::radix;
00127 
00128         // get the exponent (a silly C function which returns the exp through call-by-reference...)
00129         int exp; (void)std::frexp(v, &exp);
00130         // calculate the increment
00131         const T increment = std::max(std::pow((T)radix, (T)exp - (T)digitsMantissa - 1),
00132                          std::numeric_limits<T>::denorm_min());
00133         return v + increment;
00134         }
00135     }
00136 
00137     template<typename T>
00138     static inline T fp_pred(const T& v)
00139     {
00140         // NaNs don't have predecessors
00141         if ((std::numeric_limits<T>::has_quiet_NaN
00142          && (v == std::numeric_limits<T>::quiet_NaN()))
00143         || (std::numeric_limits<T>::has_signaling_NaN
00144             && (v == std::numeric_limits<T>::signaling_NaN())))
00145         throw std::invalid_argument("No predecessor for a NaN");
00146         // take care of lower bound (-inf/-max)
00147         if (std::numeric_limits<T>::has_infinity) {
00148         // type has infinity
00149         if (v == -std::numeric_limits<T>::max())
00150             return -std::numeric_limits<T>::infinity();
00151         else if (v == std::numeric_limits<T>::infinity())
00152             return std::numeric_limits<T>::max();
00153         else if (v == -std::numeric_limits<T>::infinity())
00154             throw std::out_of_range("No predecessor of -infinity");
00155         }
00156         else if (v == -std::numeric_limits<T>::max())
00157         // type does not have infinity and thus no smaller "value"
00158         throw std::out_of_range("No predecessor of smallest value");
00159 
00160         // take care of "+" -> "0" -> "-" transition
00161         if (v == std::numeric_limits<T>::denorm_min()) return 0.0;
00162         else if (v == 0.0) return -std::numeric_limits<T>::denorm_min();
00163         else {
00164         // let's decrease the least significant digit of the mantissa
00165 
00166         const SizeType digitsSign = 1;
00167         const SizeType digitsMantissa = std::numeric_limits<T>::digits - digitsSign;
00168         const SizeType radix = std::numeric_limits<T>::radix;
00169 
00170         // get the exponent (a silly C function which returns the exp through call-by-reference...)
00171         int exp; (void)std::frexp(v, &exp);
00172         // calculate the increment
00173         const T decrement = std::max(std::pow((T)radix, (T)exp - (T)digitsMantissa - 1),
00174                          std::numeric_limits<T>::denorm_min());
00175         return v - decrement;
00176         }
00177     }
00178     };
00179 
00192     template<typename T>
00193     class Enumerable
00194     {
00195     public:
00196     typedef T ValueType;
00197 
00203     explicit Enumerable(const ValueType& value)
00204         : value(value)
00205     {}
00206 
00212     operator ValueType() const
00213     {
00214         return value;
00215     }
00216 
00225     ValueType& operator++()
00226     {
00227         return value = Enumerator::succ(value);
00228     }
00229 
00238     ValueType operator++(int)
00239     {
00240         ValueType temp = value;
00241         ++value;
00242         return temp;
00243     }
00244 
00253     ValueType& operator--()
00254     {
00255         return value = Enumerator::pred(value);
00256     }
00257 
00266     ValueType operator--(int)
00267     {
00268         ValueType temp = value;
00269         --value;
00270         return temp;
00271     }
00272 
00278     ValueType get() const
00279     { 
00280         return value; 
00281     }
00282 
00288     void set(const ValueType& value) 
00289     { 
00290         this->value = value; 
00291     }
00292 
00293     private:
00294     ValueType value;
00295     };
00296 
00306     template<typename T>
00307     Enumerable<T> makeEnumerable(const T& v)
00308     {
00309     return Enumerable<T>(v);
00310     }
00311 
00312 }
00313 
00314 #endif // _ENUMERATOR_HPP

Generated on Wed May 23 03:31:34 2012 for openWNS by  doxygen 1.5.5