![]() |
User Manual, Developers Guide and API Documentation |
![]() |
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
1.5.5