00001
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <config.h>
00022
00023 #include <xapian/queryparser.h>
00024
00025 #include <float.h>
00026 #include <math.h>
00027
00028 #include <string>
00029
00030 #include "omassert.h"
00031
00032 using namespace std;
00033
00034 #if FLT_RADIX != 2
00035 # error Code currently assumes FLT_RADIX == 2
00036 #endif
00037
00038 #ifdef _MSC_VER
00039
00040 # pragma warning(disable:4146)
00041 #endif
00042
00043 string
00044 Xapian::sortable_serialise(double value)
00045 {
00046 double mantissa;
00047 int exponent;
00048
00049
00050 if (value < -DBL_MAX) return string();
00051
00052 mantissa = frexp(value, &exponent);
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 if (mantissa == 0.0 || exponent < -2039) return "\x80";
00063
00064 bool negative = (mantissa < 0);
00065 if (negative) mantissa = -mantissa;
00066
00067
00068 if (value > DBL_MAX || exponent > 2055) {
00069 if (negative) {
00070
00071
00072 return string();
00073 } else {
00074 return string(9, '\xff');
00075 }
00076 }
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086 unsigned char next = (negative ? 0 : 0xe0);
00087
00088
00089 exponent -= 8;
00090 bool exponent_negative = (exponent < 0);
00091 if (exponent_negative) {
00092 exponent = -exponent;
00093 next ^= 0x60;
00094 }
00095
00096 string result;
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106 Assert(exponent >= 0);
00107 if (exponent < 8) {
00108 next ^= 0x20;
00109 next |= (exponent << 2);
00110 if (negative ^ exponent_negative) next ^= 0x1c;
00111 } else {
00112 Assert((exponent >> 11) == 0);
00113
00114
00115 next |= char(exponent >> 6);
00116 if (negative ^ exponent_negative) next ^= 0x1f;
00117 result += next;
00118
00119
00120 next = char(exponent) << 2;
00121 if (negative ^ exponent_negative) next ^= 0xfc;
00122 }
00123
00124
00125 mantissa *= 1 << (negative ? 26 : 27);
00126 unsigned word1 = (unsigned)mantissa;
00127 mantissa -= word1;
00128 unsigned word2 = (unsigned)(mantissa * 4294967296.0);
00129
00130
00131
00132
00133
00134
00135
00136 Assert(negative || (word1 & (1<<26)));
00137 if (negative) {
00138
00139
00140 word1 = -word1;
00141 if (word2 != 0) ++word1;
00142 word2 = -word2;
00143 }
00144
00145 word1 &= 0x03ffffff;
00146 next |= (word1 >> 24);
00147 result += next;
00148 result.push_back(word1 >> 16);
00149 result.push_back(word1 >> 8);
00150 result.push_back(word1);
00151
00152 result.push_back(word2 >> 24);
00153 result.push_back(word2 >> 16);
00154 result.push_back(word2 >> 8);
00155 result.push_back(word2);
00156
00157
00158 size_t len = result.size();
00159 while (len > 0 && result[len - 1] == '\0') {
00160 --len;
00161 }
00162 result.resize(len);
00163
00164 return result;
00165 }
00166
00169 static inline unsigned char
00170 numfromstr(const std::string & str, std::string::size_type pos)
00171 {
00172 return (pos < str.size()) ? static_cast<unsigned char>(str[pos]) : 0;
00173 }
00174
00175 double
00176 Xapian::sortable_unserialise(const std::string & value)
00177 {
00178
00179 if (value == "\x80") return 0.0;
00180
00181
00182 if (value == string(9, '\xff')) {
00183 #ifdef INFINITY
00184
00185
00186
00187 if (double(INFINITY) > HUGE_VAL) return INFINITY;
00188 #endif
00189 return HUGE_VAL;
00190 }
00191
00192
00193 if (value.empty()) {
00194 #ifdef INFINITY
00195 if (double(INFINITY) > HUGE_VAL) return -INFINITY;
00196 #endif
00197 return -HUGE_VAL;
00198 }
00199
00200 unsigned char first = numfromstr(value, 0);
00201 size_t i = 0;
00202
00203 first ^= (first & 0xc0) >> 1;
00204 bool negative = !(first & 0x80);
00205 bool exponent_negative = (first & 0x40);
00206 bool explen = !(first & 0x20);
00207 int exponent = first & 0x1f;
00208 if (!explen) {
00209 exponent >>= 2;
00210 if (negative ^ exponent_negative) exponent ^= 0x07;
00211 } else {
00212 first = numfromstr(value, ++i);
00213 exponent <<= 6;
00214 exponent |= (first >> 2);
00215 if (negative ^ exponent_negative) exponent ^= 0x07ff;
00216 }
00217
00218 unsigned word1;
00219 word1 = (unsigned(first & 0x03) << 24);
00220 word1 |= numfromstr(value, ++i) << 16;
00221 word1 |= numfromstr(value, ++i) << 8;
00222 word1 |= numfromstr(value, ++i);
00223
00224 unsigned word2 = 0;
00225 if (i < value.size()) {
00226 word2 = numfromstr(value, ++i) << 24;
00227 word2 |= numfromstr(value, ++i) << 16;
00228 word2 |= numfromstr(value, ++i) << 8;
00229 word2 |= numfromstr(value, ++i);
00230 }
00231
00232 if (negative) {
00233 word1 = -word1;
00234 if (word2 != 0) ++word1;
00235 word2 = -word2;
00236 Assert((word1 & 0xf0000000) != 0);
00237 word1 &= 0x03ffffff;
00238 }
00239 if (!negative) word1 |= 1<<26;
00240
00241 double mantissa = 0;
00242 if (word2) mantissa = word2 / 4294967296.0;
00243 mantissa += word1;
00244 mantissa /= 1 << (negative ? 26 : 27);
00245
00246 if (exponent_negative) exponent = -exponent;
00247 exponent += 8;
00248
00249 if (negative) mantissa = -mantissa;
00250
00251 return ldexp(mantissa, exponent);
00252 }