OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 class _Constants { |
| 6 static final int MIN_SINT32 = -2147483648; |
| 7 static final int MAX_SINT32 = 2147483647; |
| 8 static final int MAX_UINT32 = 4294967295; |
| 9 static final int MIN_SINT64 = -9223372036854775808; |
| 10 static final int MAX_SINT64 = 9223372036854775807; |
| 11 static final int MAX_UINT64 = 18446744073709551615; |
| 12 static final double MIN_FLOAT_DENORM = 1.401298464324817E-45; |
| 13 static final double MAX_FLOAT = 3.4028234663852886E38; |
| 14 |
| 15 static final int POWER_64_INT = 18446744073709551616; |
| 16 static final int POWER_63_INT = 9223372036854775808; |
| 17 static final int POWER_32_INT = 4294967296; |
| 18 static final int POWER_31_INT = 2147483648; |
| 19 static final int POWER_25_INT = 33554432; |
| 20 // use literal to avoid browser issues |
| 21 static final int MAX_BITS_32 = 0xffffffff; |
| 22 static final int MAX_BITS_64 = (1 << 64) - 1; |
| 23 static final int MAX_BITS_8 = (1 << 8) - 1; |
| 24 static final int MAX_BITS_7 = (1 << 7) - 1; |
| 25 static final int MIN_BITS_8 = (1 << 7); |
| 26 static final int OCTET_BIT_COUNT = 8; |
| 27 static final int SEPTET_BIT_COUNT = 7; |
| 28 static final int BYTES_IN_32_BITS = 4; |
| 29 static final int BYTES_IN_64_BITS = 8; |
| 30 static final List<int> trueBytes = const [0x01]; |
| 31 static final List<int> falseBytes = const [0x00]; |
| 32 |
| 33 // 2^512, 2^-512 |
| 34 static final double POWER_512 = 1.3407807929942597E154; |
| 35 static final double POWER_MINUS_512 = 7.458340731200207E-155; |
| 36 // 2^256, 2^-256 |
| 37 static final double POWER_256 = 1.157920892373162E77; |
| 38 static final double POWER_MINUS_256 = 8.636168555094445E-78; |
| 39 // 2^128, 2^-128 |
| 40 static final double POWER_128 = 3.4028236692093846E38; |
| 41 static final double POWER_MINUS_128 = 2.9387358770557188E-39; |
| 42 // 2^64, 2^-64 |
| 43 static final double POWER_64 = 18446744073709551616.0; |
| 44 static final double POWER_MINUS_64 = 5.421010862427522E-20; |
| 45 // 2^52, 2^-52 |
| 46 static final double POWER_52 = 4503599627370496.0; |
| 47 static final double POWER_MINUS_52 = 2.220446049250313E-16; |
| 48 // 2^32, 2^-32 |
| 49 static final double POWER_32 = 4294967296.0; |
| 50 static final double POWER_MINUS_32 = 2.3283064365386963E-10; |
| 51 // 2^31 |
| 52 static final double POWER_31 = 2147483648.0; |
| 53 // 2^20, 2^-20 |
| 54 static final double POWER_20 = 1048576.0; |
| 55 static final double POWER_MINUS_20 = 9.5367431640625E-7; |
| 56 // 2^16, 2^-16 |
| 57 static final double POWER_16 = 65536.0; |
| 58 static final double POWER_MINUS_16 = 0.0000152587890625; |
| 59 // 2^8, 2^-8 |
| 60 static final double POWER_8 = 256.0; |
| 61 static final double POWER_MINUS_8 = 0.00390625; |
| 62 // 2^4, 2^-4 |
| 63 static final double POWER_4 = 16.0; |
| 64 static final double POWER_MINUS_4 = 0.0625; |
| 65 // 2^2, 2^-2 |
| 66 static final double POWER_2 = 4.0; |
| 67 static final double POWER_MINUS_2 = 0.25; |
| 68 // 2^1, 2^-1 |
| 69 static final double POWER_1 = 2.0; |
| 70 static final double POWER_MINUS_1 = 0.5; |
| 71 // 2^-149 (smallest single non-denorm) |
| 72 static final double POWER_MINUS_149 = 1.401298464324817E-45; |
| 73 // 2^-1022 (smallest double non-denorm) |
| 74 static final double POWER_MINUS_1022 = 2.2250738585072014E-308; |
| 75 |
| 76 static final List<double> powers = const [ |
| 77 POWER_512, POWER_256, POWER_128, POWER_64, POWER_32, POWER_16, POWER_8, |
| 78 POWER_4, POWER_2, POWER_1 |
| 79 ]; |
| 80 |
| 81 static final List<double> invPowers = const [ |
| 82 POWER_MINUS_512, POWER_MINUS_256, POWER_MINUS_128, POWER_MINUS_64, |
| 83 POWER_MINUS_32, POWER_MINUS_16, POWER_MINUS_8, POWER_MINUS_4, POWER_MINUS_2, |
| 84 POWER_MINUS_1 |
| 85 ]; |
| 86 } |
| 87 |
| 88 /** |
| 89 * An unsigned 64-bit number, stored internally as two unsigned 32-bit numbers. |
| 90 */ |
| 91 class Packed64 { |
| 92 |
| 93 int64 _packed; |
| 94 |
| 95 // Determine whether the platform supports ints greater than 2^53 |
| 96 // without loss of precision. |
| 97 static bool _haveBigIntsCached = null; |
| 98 |
| 99 static bool get _haveBigInts() { |
| 100 if (_haveBigIntsCached == null) { |
| 101 var x = 9007199254740992; |
| 102 // Defeat compile-time constant folding. |
| 103 if (2 + 2 != 4) { |
| 104 x = 0; |
| 105 } |
| 106 var y = x + 1; |
| 107 var same = y == x; |
| 108 _haveBigIntsCached = !same; |
| 109 } |
| 110 return _haveBigIntsCached; |
| 111 } |
| 112 |
| 113 static final bool _allowSoftInts = true; |
| 114 |
| 115 bool get _softInts() => |
| 116 (null !== _haveBigIntsCached && _haveBigIntsCached) || |
| 117 (null !== _allowSoftInts && _allowSoftInts); |
| 118 |
| 119 /** |
| 120 * Constructs a [Packed64] instance with given high and low 32-bit words. |
| 121 * Throws [:IllegalArgumentException:] if either the [lo] or [hi] int is |
| 122 * outside the range of a signed 32-bit INT. |
| 123 */ |
| 124 Packed64(int hi, int lo) { |
| 125 if (hi < -_Constants.POWER_32_INT || hi >= _Constants.POWER_32_INT) { |
| 126 throw new IllegalArgumentException("Hi value out of range: $hi"); |
| 127 } |
| 128 if (lo < -_Constants.POWER_32_INT || lo >= _Constants.POWER_32_INT) { |
| 129 throw new IllegalArgumentException("Lo value out of range: $lo"); |
| 130 } |
| 131 _packed = new int64.fromInts(hi, lo); |
| 132 } |
| 133 |
| 134 /** |
| 135 * Constructs a [Packed64] instance from a list of byte values, LSB first. |
| 136 */ |
| 137 Packed64.fromBytes(List<int> b) { |
| 138 _packed = new int64.fromBytes(b); |
| 139 } |
| 140 |
| 141 /** |
| 142 * Constructs a [Packed64] instance that will have the bit pattern of the |
| 143 * given [double] value. All [:NaN:] values are converted to a canonical |
| 144 * bit pattern. |
| 145 */ |
| 146 factory Packed64.fromDouble(double d) { |
| 147 if (d.isNaN()) { |
| 148 return new Packed64(0x7ff80000, 0x0); |
| 149 } |
| 150 |
| 151 bool negative = false; |
| 152 if (d.isNegative()) { |
| 153 negative = true; |
| 154 d = -d; |
| 155 } |
| 156 if (d == 0.0) { |
| 157 if (negative) { |
| 158 return new Packed64(_Constants.POWER_31_INT, 0x0); |
| 159 } else { |
| 160 return new Packed64(0x0, 0x0); |
| 161 } |
| 162 } |
| 163 if (d.isInfinite()) { |
| 164 if (negative) { |
| 165 return new Packed64(0xfff00000, 0x0); |
| 166 } else { |
| 167 return new Packed64(0x7ff00000, 0x0); |
| 168 } |
| 169 } |
| 170 |
| 171 int exp = 0; |
| 172 |
| 173 // Scale d by powers of 2 into the range [1.0, 2.0) |
| 174 // If the exponent would go below -1023, scale into (0.0, 1.0) instead |
| 175 if (d < 1.0) { |
| 176 int bit = 512; |
| 177 for (int i = 0; i < 10; i++, bit >>= 1) { |
| 178 if (d < _Constants.invPowers[i] && exp - bit >= -1023) { |
| 179 d *= _Constants.powers[i]; |
| 180 exp -= bit; |
| 181 } |
| 182 } |
| 183 // Force into [1.0, 2.0) range |
| 184 if (d < 1.0 && exp - 1 >= -1023) { |
| 185 d *= 2.0; |
| 186 exp--; |
| 187 } |
| 188 } else if (d >= 2.0) { |
| 189 int bit = 512; |
| 190 for (int i = 0; i < 10; i++, bit >>= 1) { |
| 191 if (d >= _Constants.powers[i]) { |
| 192 d *= _Constants.invPowers[i]; |
| 193 exp += bit; |
| 194 } |
| 195 } |
| 196 } |
| 197 |
| 198 if (exp > -1023) { |
| 199 // Remove significand of non-denormalized mantissa |
| 200 d -= 1.0; |
| 201 } else { |
| 202 // Insert 0 bit as significand of denormalized mantissa |
| 203 d *= 0.5; |
| 204 } |
| 205 |
| 206 // Extract high 20 bits of mantissa |
| 207 int ihi = (d * _Constants.POWER_20).toInt(); |
| 208 |
| 209 // Extract low 32 bits of mantissa |
| 210 d -= ihi * _Constants.POWER_MINUS_20; |
| 211 int ilo = (d * _Constants.POWER_52).toInt(); |
| 212 |
| 213 // Exponent bits |
| 214 ihi |= (exp + 1023) << 20; |
| 215 // Sign bit |
| 216 if (negative) { |
| 217 ihi += _Constants.POWER_31_INT; |
| 218 } |
| 219 |
| 220 return new Packed64(ihi, ilo); |
| 221 } |
| 222 |
| 223 void _orShifted(int bits, int shift) { |
| 224 _packed |= new int64.fromInt(bits) << shift; |
| 225 } |
| 226 |
| 227 /** |
| 228 * Constructs a [Packed64] instance from a variable-length representation. |
| 229 * Throws an [:IllegalArgumentException:] if the encoding is invalid. |
| 230 */ |
| 231 Packed64.fromVarintBytes(List<int> b) { |
| 232 try { |
| 233 _packed = int64.ZERO; |
| 234 int i = 0; |
| 235 bool lastByte = ((b[i] & _Constants.MIN_BITS_8) === 0); |
| 236 while (i < 10 && !lastByte) { |
| 237 _orShifted(b[i] & _Constants.MAX_BITS_7, |
| 238 _Constants.SEPTET_BIT_COUNT * i); |
| 239 i++; |
| 240 lastByte = (b[i] & _Constants.MIN_BITS_8) === 0; |
| 241 } |
| 242 _orShifted(b[i] & _Constants.MAX_BITS_7, |
| 243 _Constants.SEPTET_BIT_COUNT * i); |
| 244 } catch (IndexOutOfRangeException e) { |
| 245 throw new IllegalArgumentException("Invalid Encoding"); |
| 246 } |
| 247 } |
| 248 |
| 249 /** |
| 250 * Constructs a [Packed64] instance whose value is equivalent to the given |
| 251 * value. Throws an [:IllegalArgumentException:] if the value is < |
| 252 * -9223372036854775808 (MIN_SINT64) or > 18446744073709551615 |
| 253 * (MAZ_UINT64). |
| 254 */ |
| 255 Packed64.fromInt(int x) { |
| 256 if (x < -9223372036854775808 || x > 18446744073709551615) { |
| 257 throw new IllegalArgumentException("Out of range: $x"); |
| 258 } |
| 259 _packed = new int64.fromInt(x); |
| 260 } |
| 261 |
| 262 /** |
| 263 * Compares this [Packed64] with a given [Packed64] or [int] value. |
| 264 */ |
| 265 bool operator ==(var other) { |
| 266 if (other is num) { |
| 267 return this.toInt() == new Packed64.fromInt(other); |
| 268 } |
| 269 if (other is !Packed64) { |
| 270 return false; |
| 271 } |
| 272 return other._packed == _packed; |
| 273 } |
| 274 |
| 275 int hashCode() { |
| 276 return _packed.hashCode(); |
| 277 } |
| 278 |
| 279 /** |
| 280 * Returns the 32 high bits of this [Packed64] value as an unsigned integer |
| 281 * in the range [0, 2^31 - 1]. |
| 282 */ |
| 283 int get hi() => ((_packed >> 32) & 0xffffffff).toInt(); |
| 284 |
| 285 /** |
| 286 * Returns the 32 low bits of this [Packed64] value as an unsigned integer |
| 287 * in the range [0, 2^31 - 1]. |
| 288 */ |
| 289 int get lo() => (_packed & 0xffffffff).toInt(); |
| 290 |
| 291 /** |
| 292 * Decodes this [Packed64] from the zig-zag representation |
| 293 * [:(n << 1) ^ (n >> 63):]. |
| 294 */ |
| 295 Packed64 decodeZigZag() { |
| 296 int ihi = this.hi; |
| 297 int ilo = this.lo; |
| 298 |
| 299 int sign = ilo % 2; |
| 300 ilo = ((ihi % 2 == 1) ? _Constants.POWER_31_INT : 0) + (ilo ~/ 2); |
| 301 ihi = ihi ~/ 2; |
| 302 if (sign == 1) { |
| 303 ihi = _bitFlip(ihi); |
| 304 ilo = _bitFlip(ilo); |
| 305 } |
| 306 Packed64 result = new Packed64(ihi, ilo); |
| 307 return result; |
| 308 } |
| 309 |
| 310 static int _bitFlip(int x) => _Constants.MAX_BITS_32 - x; |
| 311 |
| 312 /** |
| 313 * Encodes this [Packed64] in the zig-zag representation |
| 314 * [:(n << 1) ^ (n >> 63):]. |
| 315 */ |
| 316 Packed64 encodeZigZag() { |
| 317 int ihi = hi; |
| 318 int ilo = lo; |
| 319 bool negative = ihi >= _Constants.POWER_31_INT; |
| 320 ihi = ihi * 2 + (ilo >= _Constants.POWER_31_INT ? 1 : 0); |
| 321 ilo = ilo * 2; |
| 322 if (ihi >= _Constants.POWER_32_INT) { |
| 323 ihi -= _Constants.POWER_32_INT; |
| 324 } |
| 325 if (ilo >= _Constants.POWER_32_INT) { |
| 326 ilo -= _Constants.POWER_32_INT; |
| 327 } |
| 328 if (negative) { |
| 329 ihi = _bitFlip(ihi); |
| 330 ilo = _bitFlip(ilo); |
| 331 } |
| 332 return new Packed64(ihi, ilo); |
| 333 } |
| 334 |
| 335 /** |
| 336 * Returns [true] if this [Packed64] can safely be converted to a signed |
| 337 * integer in the range [-2^51, 2^51 - 1]. |
| 338 */ |
| 339 bool isSafeAsInt() { |
| 340 if (_haveBigInts) { |
| 341 return true; |
| 342 } else { |
| 343 int top = (hi >> 20) & 0xfff; |
| 344 return top == 0x0 || top == 0xfff; |
| 345 } |
| 346 } |
| 347 |
| 348 /** |
| 349 * Returns [true] if this [Packed64] can safely be converted to an unsigned |
| 350 * integer in the range [0, 2^52 - 1]. |
| 351 */ |
| 352 bool isSafeAsUint() { |
| 353 if (_haveBigInts) { |
| 354 return true; |
| 355 } else { |
| 356 int top = (hi >> 20) & 0xfff; |
| 357 return top == 0x0; |
| 358 } |
| 359 } |
| 360 |
| 361 /** |
| 362 * Return the number of bytes required to encdode this [Packed64] using |
| 363 * the variable-length representation. |
| 364 */ |
| 365 int sizeOfVarint() { |
| 366 int ihi = this.hi; |
| 367 int ilo = this.lo; |
| 368 |
| 369 int i = 0; |
| 370 while (i < 10) { |
| 371 ilo = ((ihi % 128) * _Constants.POWER_25_INT) + (ilo ~/ 128); |
| 372 ihi ~/= 128; |
| 373 i++; |
| 374 if (ihi === 0 && ilo === 0) { |
| 375 return i; |
| 376 } |
| 377 } |
| 378 return i; |
| 379 } |
| 380 |
| 381 /** |
| 382 * Return this [Packed64] as a list of 8 ints, LSB first. |
| 383 */ |
| 384 List<int> toBytes() => _packed.toBytes(); |
| 385 |
| 386 /** |
| 387 * Return this [Packed64] interpreted as an IEEE double-precision value. |
| 388 */ |
| 389 double toDouble() { |
| 390 int ihi = this.hi; |
| 391 int ilo = this.lo; |
| 392 if (ihi < 0) { |
| 393 ihi += _Constants.POWER_32_INT; |
| 394 } |
| 395 if (ilo < 0) { |
| 396 ilo += _Constants.POWER_32_INT; |
| 397 } |
| 398 |
| 399 bool negative = (ihi & _Constants.POWER_31_INT) != 0; |
| 400 int exp = (ihi >> 20) & 0x7ff; |
| 401 ihi &= 0xfffff; // remove sign bit and exponent |
| 402 |
| 403 if (exp == 0x0) { |
| 404 double d = (ihi * _Constants.POWER_MINUS_20) + |
| 405 (ilo * _Constants.POWER_MINUS_52); |
| 406 d *= _Constants.POWER_MINUS_1022; |
| 407 return negative ? (d == 0.0 ? -0.0 : -d) : d; |
| 408 } else if (exp == 0x7ff) { |
| 409 if (ihi == 0 && ilo == 0) { |
| 410 return negative ? double.NEGATIVE_INFINITY : double.INFINITY; |
| 411 } else { |
| 412 return double.NAN; |
| 413 } |
| 414 } |
| 415 |
| 416 // Normalize exponent |
| 417 exp -= 1023; |
| 418 |
| 419 double d = 1.0 + (ihi * _Constants.POWER_MINUS_20) + |
| 420 (ilo * _Constants.POWER_MINUS_52); |
| 421 if (exp > 0) { |
| 422 int bit = 512; |
| 423 for (int i = 0; i < 10; i++, bit >>= 1) { |
| 424 if (exp >= bit) { |
| 425 d *= _Constants.powers[i]; |
| 426 exp -= bit; |
| 427 } |
| 428 } |
| 429 } else if (exp < 0) { |
| 430 while (exp < 0) { |
| 431 int bit = 512; |
| 432 for (int i = 0; i < 10; i++, bit >>= 1) { |
| 433 if (exp <= -bit) { |
| 434 d *= _Constants.invPowers[i]; |
| 435 exp += bit; |
| 436 } |
| 437 } |
| 438 } |
| 439 } |
| 440 return negative ? -d : d; |
| 441 } |
| 442 |
| 443 /** |
| 444 * Return the value of this [Packed64] as an int if the resulting value |
| 445 * is in the legal range of [-2^51, 2^51 -1], otherwise throw an |
| 446 * IllegalArgumentException. |
| 447 */ |
| 448 int toInt() => _packed.toInt(); |
| 449 |
| 450 /** |
| 451 * Return the value of this [Packed64] as an int if the resulting value |
| 452 * is in the legal range of [-2^51, 2^51 -1], otherwise return [this]. |
| 453 */ |
| 454 Dynamic toIntIfSafe() { |
| 455 if (_softInts && this.isSafeAsInt()) { |
| 456 return this.toInt(); |
| 457 } |
| 458 return this; |
| 459 } |
| 460 |
| 461 /** |
| 462 * Return the value of this [Packed64] as an int if the resulting value |
| 463 * is in the legal range of [0, 2^52 -1], otherwise throw an |
| 464 * IllegalArgumentException. |
| 465 */ |
| 466 int toUint() { |
| 467 if (!isSafeAsUint()) { |
| 468 throw new IllegalArgumentException("Out of range"); |
| 469 } |
| 470 int value = this.hi * _Constants.POWER_32_INT + this.lo; |
| 471 return value; |
| 472 } |
| 473 |
| 474 /** |
| 475 * Return the value of this [Packed64] as an int if the resulting value |
| 476 * is in the legal range of [0, 2^52 -1], otherwise return [this]. |
| 477 */ |
| 478 Dynamic toUintIfSafe() { |
| 479 if (_softInts && this.isSafeAsUint()) { |
| 480 return this.toUint(); |
| 481 } |
| 482 return this; |
| 483 } |
| 484 |
| 485 /** |
| 486 * Return a list of up to 10 ints encoding this [Packed64] using a |
| 487 * variable-length representation. |
| 488 */ |
| 489 List<int> toVarintBytes() { |
| 490 int ihi = this.hi; |
| 491 int ilo = this.lo; |
| 492 |
| 493 List<int> b = []; |
| 494 int i = 0; |
| 495 while (true) { |
| 496 i++; |
| 497 if ((ihi != 0 || ilo >= 128) && i < 10) { |
| 498 int v = 128 + (ilo % 128); |
| 499 b.add(v); |
| 500 } else { |
| 501 int v = ilo % 128; |
| 502 b.add(v); |
| 503 break; |
| 504 } |
| 505 ilo = ((ihi % 128) * 33554432) + (ilo ~/ 128); |
| 506 ihi ~/= 128; |
| 507 } |
| 508 return b; |
| 509 } |
| 510 |
| 511 /** |
| 512 * Return a String useful for debugging. |
| 513 */ |
| 514 String toDebugString() { |
| 515 return "Packed64[0x${hi.toRadixString(16)},0x${lo.toRadixString(16)}]"; |
| 516 } |
| 517 |
| 518 /** |
| 519 * Return a String in decimal representation. |
| 520 */ |
| 521 String toString() { |
| 522 return _packed.toString(); |
| 523 } |
| 524 } |
| 525 |
| 526 /* |
| 527 * Provides conversion utilities from dart types to/from protocol buffer wire |
| 528 * format. |
| 529 */ |
| 530 class PbCodec { |
| 531 static bool toBool(List<int> b) => b[0] !== 0; |
| 532 |
| 533 static int toFixed32(List<int> b) => packedToUint32(bytesToPacked(b)); |
| 534 |
| 535 // return value may be an int or a Packed64 |
| 536 static Dynamic toFixed64(List<int> b) => int64ToUint64(bytesToPacked64(b)); |
| 537 |
| 538 static int toInt32(List<int> b) => packedToInt32(varintBytesToPacked(b)); |
| 539 |
| 540 // return value may be an int or a Packed64 |
| 541 static Dynamic toInt64(List<int> b) => |
| 542 int64ToSigned(varintBytesToPacked64(b)); |
| 543 |
| 544 static int toSfixed32(List<int> b) => packedToInt32(bytesToPacked(b)); |
| 545 |
| 546 // return value may be an int or a Packed64 |
| 547 static Dynamic toSfixed64(List<int> b) => bytesToPacked64(b); |
| 548 |
| 549 static int toSint32(List<int> b) => packedToSint32(varintBytesToPacked(b)); |
| 550 |
| 551 // return value may be an int or a Packed64 |
| 552 static Dynamic toSint64(List<int> b) => |
| 553 int64ToSint64(varintBytesToPacked64(b)); |
| 554 |
| 555 static int toUint32(List<int> b) => packedToUint32(varintBytesToPacked(b)); |
| 556 |
| 557 // return value may be an int or a Packed64 |
| 558 static Dynamic toUint64(List<int> b) => |
| 559 int64ToUint64(varintBytesToPacked64(b)); |
| 560 |
| 561 static double toFloat(List<int> b) => packedToFloat(bytesToPacked(b)); |
| 562 |
| 563 static double toDouble(List<int> b) => int64ToDouble(bytesToPacked64(b)); |
| 564 |
| 565 static List<int> boolToBytes(bool value) => |
| 566 value ? _Constants.trueBytes : _Constants.falseBytes; |
| 567 |
| 568 static List<int> fixed32ToBytes(int value) => |
| 569 packed32ToBytes(uint32ToPacked(value)); |
| 570 |
| 571 // value may be an int or a Packed64 |
| 572 static List<int> fixed64ToBytes(var value) => packed64ToBytes(value); |
| 573 |
| 574 static List<int> int32ToBytes(int value) => |
| 575 packedToVarintBytes(int32ToPacked(value)); |
| 576 |
| 577 // value may be an int or a Packed64 |
| 578 static List<int> int64ToBytes(var value) => |
| 579 int64ToVarintBytes(value); |
| 580 |
| 581 static List<int> sfixed32ToBytes(int value) => |
| 582 packed32ToBytes(int32ToPacked(value)); |
| 583 |
| 584 // value may be an int or a Packed64 |
| 585 static List<int> sfixed64ToBytes(var value) => |
| 586 packed64ToBytes(value); |
| 587 |
| 588 static List<int> sint32ToBytes(int value) => |
| 589 packedToVarintBytes(sint32ToPacked(value)); |
| 590 |
| 591 // value may be an int or a Packed64 |
| 592 static List<int> sint64ToBytes(var value) => |
| 593 int64ToVarintBytes(sint64ToPacked64(value)); |
| 594 |
| 595 static List<int> uint32ToBytes(int value) => |
| 596 packedToVarintBytes(uint32ToPacked(value)); |
| 597 |
| 598 // value may be an int or a Packed64 |
| 599 static List<int> uint64ToBytes(var value) => |
| 600 int64ToVarintBytes(uint64ToPacked64(value)); |
| 601 |
| 602 static List<int> floatToBytes(double value) => |
| 603 packed32ToBytes(floatToPacked(value)); |
| 604 |
| 605 static List<int> doubleToBytes(double value) => |
| 606 packed64ToBytes(doubleToPacked64(value)); |
| 607 |
| 608 static final int sizeOfBool = 1; |
| 609 |
| 610 static int sizeOfFixed32 = _Constants.BYTES_IN_32_BITS; |
| 611 |
| 612 static int sizeOfFixed64 = _Constants.BYTES_IN_64_BITS; |
| 613 |
| 614 static int sizeOfSfixed32 = _Constants.BYTES_IN_32_BITS; |
| 615 |
| 616 static int sizeOfSfixed64 = _Constants.BYTES_IN_64_BITS; |
| 617 |
| 618 static int sizeOfInt32(int value) => value < 0 ? 5 : sizeOfVarint(value); |
| 619 |
| 620 // value may be an int or a Packed64 |
| 621 static int sizeOfInt64(var value) { |
| 622 if (value is Packed64) { |
| 623 return value.sizeOfVarint(); |
| 624 } else if (value is num) { |
| 625 if (value < 0) { |
| 626 return 10; |
| 627 } else { |
| 628 return sizeOfVarint64(new Packed64.fromInt(value.toInt())); |
| 629 } |
| 630 } else { |
| 631 throw new IllegalArgumentException("Expected Packed64 or int"); |
| 632 } |
| 633 } |
| 634 |
| 635 static int sizeOfSint32(int value) => sizeOfVarint(encodeZigZag32(value)); |
| 636 |
| 637 // value may be an int or a Packed64 |
| 638 static int sizeOfSint64(var value) => sizeOfVarint64(encodeZigZag64(value)); |
| 639 |
| 640 static int sizeOfUint32(int value) => sizeOfVarint(value); |
| 641 |
| 642 // value may be an int or a Packed64 |
| 643 static int sizeOfUint64(var value) => sizeOfVarint64(value); |
| 644 |
| 645 static int sizeOfVarint(int value) { |
| 646 int i = 0; |
| 647 while (i < 10) { |
| 648 value >>= _Constants.SEPTET_BIT_COUNT; |
| 649 i++; |
| 650 if (value === 0) return i; |
| 651 } |
| 652 return i; |
| 653 } |
| 654 |
| 655 // value may be an int or a Packed64 |
| 656 static int sizeOfVarint64(var value) { |
| 657 if (value is Packed64) { |
| 658 return value.sizeOfVarint(); |
| 659 } else if (value is num) { |
| 660 return new Packed64.fromInt(value.toInt()).sizeOfVarint(); |
| 661 } else { |
| 662 throw new IllegalArgumentException("Expected Packed64 or int"); |
| 663 } |
| 664 } |
| 665 |
| 666 static int int32ToPacked(int value) { |
| 667 if (value < 0) { |
| 668 return _Constants.POWER_32_INT + value; |
| 669 } |
| 670 return value; |
| 671 } |
| 672 |
| 673 static int sint32ToPacked(int value) => encodeZigZag32(value); |
| 674 |
| 675 // value and return may be an int or a Packed64 |
| 676 static Dynamic sint64ToPacked64(var value) => encodeZigZag64(value); |
| 677 |
| 678 static int uint32ToPacked(int value) => value; |
| 679 |
| 680 // value and return may be an int or a Packed64 |
| 681 static Dynamic uint64ToPacked64(var value) => value; |
| 682 |
| 683 static int packedToInt32(int packed) { |
| 684 if (packed >= _Constants.POWER_32_INT) { |
| 685 packed &= _Constants.MAX_BITS_32; |
| 686 } |
| 687 if (packed < 0 || ((packed & _Constants.POWER_31_INT) == 0)) { |
| 688 return packed; |
| 689 } else { |
| 690 return packed - _Constants.POWER_32_INT; |
| 691 } |
| 692 } |
| 693 |
| 694 static int packedToSint32(int packed) => decodeZigZag32(packed); |
| 695 |
| 696 static int packedToUint32(int packed) => packed; |
| 697 |
| 698 // value and return may be an int or a Packed64 |
| 699 static Dynamic int64ToSint64(var packed) => decodeZigZag64(packed); |
| 700 |
| 701 // value and return may be an int or a Packed64 |
| 702 static Dynamic int64ToUint64(var packed) { |
| 703 if (packed is Packed64) { |
| 704 return packed; |
| 705 } else if (packed < 0) { |
| 706 return _Constants.POWER_64_INT + packed; |
| 707 } else { |
| 708 return packed; |
| 709 } |
| 710 } |
| 711 |
| 712 // value and return may be an int or a Packed64 |
| 713 static Dynamic int64ToSigned(var packed) { |
| 714 if (packed is Packed64) { |
| 715 return packed; |
| 716 } else if (packed >= _Constants.POWER_63_INT) { |
| 717 return packed - _Constants.POWER_64_INT; |
| 718 } else { |
| 719 return packed; |
| 720 } |
| 721 } |
| 722 |
| 723 static int bytesToPacked(List<int> b) { |
| 724 int result = 0; |
| 725 int factor = 1; |
| 726 for (int i = 0; i < b.length && i < _Constants.BYTES_IN_64_BITS; |
| 727 i++, factor *= 256) { |
| 728 result += (b[i] & _Constants.MAX_BITS_8) * factor; |
| 729 } |
| 730 return result; |
| 731 } |
| 732 |
| 733 static Dynamic bytesToPacked64(List<int> b) => |
| 734 new Packed64.fromBytes(b).toIntIfSafe(); |
| 735 |
| 736 static int _unsigned(int x) => x < 0 ? x + _Constants.POWER_32_INT : x; |
| 737 |
| 738 static int varintBytesToPacked(List<int> b) { |
| 739 try { |
| 740 int result = 0; |
| 741 int i = 0; |
| 742 bool lastByte = ((b[i] & _Constants.MIN_BITS_8) === 0); |
| 743 while (i < 10 && !lastByte) { |
| 744 result |= (((b[i] & _Constants.MAX_BITS_7) << |
| 745 (_Constants.SEPTET_BIT_COUNT * i))); |
| 746 i++; |
| 747 lastByte = (b[i] & _Constants.MIN_BITS_8) === 0; |
| 748 } |
| 749 result |= (b[i] & _Constants.MAX_BITS_7) << |
| 750 (_Constants.SEPTET_BIT_COUNT * i); |
| 751 return _unsigned(result); |
| 752 } catch (IndexOutOfRangeException e) { |
| 753 throw new IllegalArgumentException("Invalid Encoding"); |
| 754 } |
| 755 } |
| 756 |
| 757 static Dynamic varintBytesToPacked64(List<int> b) => |
| 758 new Packed64.fromVarintBytes(b).toUintIfSafe(); |
| 759 |
| 760 static List<int> packed32ToBytes(int value) { |
| 761 List<int> b = new List(4); |
| 762 for (int i = 0; i < 4; i++) { |
| 763 if (value === 0) { |
| 764 while (i < 4) { |
| 765 b[i] = 0; |
| 766 i++; |
| 767 } |
| 768 } else { |
| 769 b[i] = value & _Constants.MAX_BITS_8; |
| 770 value >>= _Constants.OCTET_BIT_COUNT; |
| 771 } |
| 772 } |
| 773 return b; |
| 774 } |
| 775 |
| 776 // value may be an int or a Packed64 |
| 777 static List<int> packed64ToBytes(var value) { |
| 778 if (value is Packed64) { |
| 779 return value.toBytes(); |
| 780 } else if (value is num) { |
| 781 return new Packed64.fromInt(value.toInt()).toBytes(); |
| 782 } else { |
| 783 throw new IllegalArgumentException("Expected Packed64 or int"); |
| 784 } |
| 785 } |
| 786 |
| 787 static List<int> packedToVarintBytes(int value) { |
| 788 List<int> b = []; |
| 789 int i = 0; |
| 790 while (true) { |
| 791 i++; |
| 792 int nextVal = value ~/ 128; |
| 793 if (nextVal !== 0 && i < 10) { |
| 794 int v = 128 + (value % 128); |
| 795 b.add(v); |
| 796 } else { |
| 797 int v = value % 128; |
| 798 b.add(v); |
| 799 break; |
| 800 } |
| 801 value = nextVal; |
| 802 } |
| 803 return b; |
| 804 } |
| 805 |
| 806 static List<int> int64ToVarintBytes(var value) { |
| 807 if (value is Packed64) { |
| 808 return value.toVarintBytes(); |
| 809 } else if (value is num) { |
| 810 return new Packed64.fromInt(value.toInt()).toVarintBytes(); |
| 811 } else { |
| 812 throw new IllegalArgumentException("Expected Packed64 or int"); |
| 813 } |
| 814 } |
| 815 |
| 816 static int encodeZigZag32(int value) { |
| 817 if (value < 0) { |
| 818 return -(value * 2) - 1; |
| 819 } else { |
| 820 return value * 2; |
| 821 } |
| 822 } |
| 823 |
| 824 // value and return may be an int or a Packed64 |
| 825 static Dynamic encodeZigZag64(var value) { |
| 826 if (value is Packed64) { |
| 827 return value.encodeZigZag().toUintIfSafe(); |
| 828 } else if (value is num) { |
| 829 return new Packed64.fromInt(value.toInt()).encodeZigZag().toUint(); |
| 830 } else { |
| 831 throw new IllegalArgumentException("Expected Packed64 or int"); |
| 832 } |
| 833 } |
| 834 |
| 835 static int decodeZigZag32(int value) { |
| 836 if ((value & 0x1) == 0) { |
| 837 return value ~/ 2; |
| 838 } else { |
| 839 value = (value - 1) ~/ 2; |
| 840 if (value < _Constants.POWER_32_INT) { |
| 841 return -value - 1; |
| 842 } else { |
| 843 return value; |
| 844 } |
| 845 } |
| 846 } |
| 847 |
| 848 // value and return may be an int or a Packed64 |
| 849 static Dynamic decodeZigZag64(var value) { |
| 850 if (value is Packed64) { |
| 851 return value.decodeZigZag().toIntIfSafe(); |
| 852 } else if (value is num) { |
| 853 return new Packed64.fromInt(value.toInt()).decodeZigZag().toIntIfSafe(); |
| 854 } else { |
| 855 throw new IllegalArgumentException("Expected Packed64 or int"); |
| 856 } |
| 857 } |
| 858 |
| 859 // value may be an int or a Packed64 |
| 860 static double int64ToDouble(var value) { |
| 861 if (value is Packed64) { |
| 862 return value.toDouble(); |
| 863 } else if (value is num) { |
| 864 return new Packed64.fromInt(value.toInt()).toDouble(); |
| 865 } else { |
| 866 throw new IllegalArgumentException("Expected Packed64 or int"); |
| 867 } |
| 868 } |
| 869 |
| 870 static double packedToFloat(int packed) { |
| 871 bool negative = (packed & _Constants.POWER_31_INT) != 0; |
| 872 int exp = (packed >> 23) & 0xff; |
| 873 packed &= 0x7fffff; |
| 874 |
| 875 if (exp == 0x0) { |
| 876 // Handle +/- 0 here, denorms below |
| 877 if (packed == 0) { |
| 878 return negative ? -0.0 : 0.0; |
| 879 } |
| 880 } else if (exp == 0xff) { |
| 881 // Inf & NaN |
| 882 if (packed == 0) { |
| 883 return negative ? double.NEGATIVE_INFINITY : double.INFINITY; |
| 884 } else { |
| 885 return double.NAN; |
| 886 } |
| 887 } |
| 888 |
| 889 // Build the bits of a 64-bit double from the incoming bits |
| 890 int ihi = negative ? _Constants.POWER_31_INT : 0x0; |
| 891 int ilo = 0x0; |
| 892 if (exp == 0) { |
| 893 // Input is denormalized, renormalize by shifting left until there is a |
| 894 // leading 1 |
| 895 exp = 897; |
| 896 while ((packed & 0x800000) == 0) { |
| 897 packed <<= 1; |
| 898 exp--; |
| 899 } |
| 900 packed &= 0x7fffff; |
| 901 ihi |= exp << 20; |
| 902 ihi |= packed >> 3; |
| 903 ilo = (packed & 0x7) << 29; |
| 904 } else { |
| 905 // Normalized number, rebias exponent and shift mantissa into place |
| 906 ihi |= (exp + 896) << 20; |
| 907 ihi |= packed >> 3; |
| 908 ilo = (packed & 0x7) << 29; |
| 909 } |
| 910 return int64ToDouble(new Packed64(ihi, ilo)); |
| 911 } |
| 912 |
| 913 /** |
| 914 * Return the 32-bit IEEE single-precision representation that represents |
| 915 * the value [d] truncated to 23 fractional bits. |
| 916 */ |
| 917 static int floatToPacked(double d) { |
| 918 // Return a canonical NaN since we have no way to detect anything else |
| 919 if (d.isNaN()) { |
| 920 return 0x7fc00000; |
| 921 } |
| 922 |
| 923 bool negative = false; |
| 924 if (d.isNegative()) { |
| 925 negative = true; |
| 926 d = -d; |
| 927 } |
| 928 // Numbers below min float map to 0.0 |
| 929 if (d < _Constants.MIN_FLOAT_DENORM) { |
| 930 return negative ? _Constants.POWER_31_INT : 0x0; |
| 931 } |
| 932 // Numbers above max float map to Infinity |
| 933 if (d.isInfinite() || d > _Constants.MAX_FLOAT) { |
| 934 return negative ? 0xff800000 : 0x7f800000; |
| 935 } |
| 936 |
| 937 // Obtain the 64-bit representation and extract its exponent and |
| 938 // mantissa. |
| 939 var packed = doubleToPacked64(d); |
| 940 int exp, mantissa; |
| 941 if (packed is Packed64) { |
| 942 Packed64 packed64 = packed; |
| 943 exp = ((packed64.hi >> 20) & 0x7ff) - 1023; |
| 944 mantissa = ((packed64.hi & 0xfffff) << 3) | ((packed64.lo >> 29) & 0x7); |
| 945 } else if (packed is num) { |
| 946 var ipacked = packed.toInt(); |
| 947 exp = ((ipacked >> 52) & 0x7ff) - 1023; |
| 948 mantissa = (ipacked & 0xfffffffffffff) >> 29; |
| 949 } |
| 950 |
| 951 // If the number will be a denorm in the float representation |
| 952 // (i.e., its exponent is -127 or smaller), add a leading 1 to the |
| 953 // mantissa and shift it right to maintain an exponent of -127. |
| 954 if (exp <= -127) { |
| 955 mantissa = (0x800000 | mantissa) >> (-127 - exp + 1); |
| 956 exp = -127; |
| 957 } |
| 958 |
| 959 // Construct the 32-bit representation |
| 960 int packed32 = negative ? _Constants.POWER_31_INT : 0x0; |
| 961 packed32 |= (exp + 127) << 23; |
| 962 packed32 |= mantissa; |
| 963 if (packed32 < 0) { |
| 964 packed32 += _Constants.POWER_32_INT; |
| 965 } |
| 966 return packed32; |
| 967 } |
| 968 |
| 969 static Dynamic doubleToPacked64(double d) { |
| 970 Packed64 packed = new Packed64.fromDouble(d); |
| 971 if (packed.isSafeAsUint()) { |
| 972 return packed.toUint(); |
| 973 } |
| 974 return packed; |
| 975 } |
| 976 |
| 977 // JSON |
| 978 |
| 979 // ('0' + x) or ('a' + x - 10) |
| 980 static int _hexDigit(int x) => x < 10 ? 48 + x : 87 + x; |
| 981 |
| 982 // Escape a string to be suitable as a JSON value |
| 983 static String escapeString(String x) { |
| 984 List<int> chars = x.charCodes(); |
| 985 List<int> output = new List<int>(); |
| 986 for (int i = 0; i < chars.length; i++) { |
| 987 int c = chars[i]; |
| 988 // Escape control characters, double-quote, and backslash |
| 989 if (c < 32) { // control characters |
| 990 output.add(92); // '\' |
| 991 switch (c) { |
| 992 case 8: // backspace |
| 993 output.add(98); // 'b' |
| 994 break; |
| 995 case 9: // tab |
| 996 output.add(116); // 't' |
| 997 break; |
| 998 case 10: // newline |
| 999 output.add(110); // 'n' |
| 1000 break; |
| 1001 case 12: // formfeed |
| 1002 output.add(102); // 'f' |
| 1003 break; |
| 1004 case 13: // carriage return |
| 1005 output.add(114); // 'r' |
| 1006 break; |
| 1007 default: |
| 1008 output.add(117); // 'u' |
| 1009 output.add(_hexDigit((c >> 12) & 0xf)); |
| 1010 output.add(_hexDigit((c >> 8) & 0xf)); |
| 1011 output.add(_hexDigit((c >> 4) & 0xf)); |
| 1012 output.add(_hexDigit(c & 0xf)); |
| 1013 break; |
| 1014 } |
| 1015 } else if (c == 34 || c == 92) { // double-quote or backslash |
| 1016 output.add(92); // '\' |
| 1017 output.add(c); |
| 1018 } else { |
| 1019 output.add(c); |
| 1020 } |
| 1021 } |
| 1022 return new String.fromCharCodes(output); |
| 1023 } |
| 1024 } |
| 1025 |
| 1026 // TODO - make this a separate library |
| 1027 class Base64Codec { |
| 1028 |
| 1029 // MIME Base64 characters plus padding char '=' (RFC 2045) |
| 1030 static final String MIME_ALPHABET = |
| 1031 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; |
| 1032 |
| 1033 static Base64Codec _defaultInstance = null; |
| 1034 |
| 1035 static Base64Codec get defaultInstance() { |
| 1036 if (_defaultInstance == null) { |
| 1037 _defaultInstance = new Base64Codec(); |
| 1038 } |
| 1039 return _defaultInstance; |
| 1040 } |
| 1041 |
| 1042 List<int> _base64Chars = null; |
| 1043 List<int> _base64InverseChars = null; |
| 1044 int _padding; |
| 1045 |
| 1046 Base64Codec([String alphabet = null]) { |
| 1047 assert(alphabet == null || alphabet.length == 65); |
| 1048 if (alphabet == null) { |
| 1049 alphabet = MIME_ALPHABET; |
| 1050 } |
| 1051 _initTables(alphabet); |
| 1052 } |
| 1053 |
| 1054 void _initTables(String alphabet) { |
| 1055 _base64Chars = alphabet.charCodes(); |
| 1056 _base64InverseChars = new List<int>(128); |
| 1057 // Use -1 to indicate an illegal character |
| 1058 for (int i = 0; i < 128; i++) { |
| 1059 _base64InverseChars[i] = -1; |
| 1060 } |
| 1061 for (int i = 0; i < 64; i++) { |
| 1062 _base64InverseChars[_base64Chars[i]] = i; |
| 1063 } |
| 1064 // The padding character is interpreted as 0 |
| 1065 _padding = alphabet.charCodeAt(64); |
| 1066 _base64InverseChars[_padding] = 0; |
| 1067 } |
| 1068 |
| 1069 int _base64Inverse(int x) { |
| 1070 // Look at 7 low bits only |
| 1071 int result = _base64InverseChars[x & 0x7f]; |
| 1072 if (result == -1) { |
| 1073 throw new IllegalArgumentException("Unknown character code: ${x & 0x7f}"); |
| 1074 } |
| 1075 return result; |
| 1076 } |
| 1077 |
| 1078 List<int> decodeAsList(String s) { |
| 1079 int olen = 3 * (s.length ~/ 4); |
| 1080 // Inspect the last two characters of the input for padding |
| 1081 for (int i = Math.max(0, s.length - 2); i < s.length; i++) { |
| 1082 if (s.charCodeAt(i) == _padding) { |
| 1083 --olen; |
| 1084 } |
| 1085 } |
| 1086 |
| 1087 int iidx = 0; |
| 1088 int oidx = 0; |
| 1089 List<int> data = createIntArray(olen); |
| 1090 int lastStartIndex = s.length - 3; |
| 1091 while (iidx < lastStartIndex) { |
| 1092 int c0 = _base64Inverse(s.charCodeAt(iidx++)); |
| 1093 int c1 = _base64Inverse(s.charCodeAt(iidx++)); |
| 1094 int c2 = _base64Inverse(s.charCodeAt(iidx++)); |
| 1095 int c3 = _base64Inverse(s.charCodeAt(iidx++)); |
| 1096 int c24 = (c0 << 18) | (c1 << 12) | (c2 << 6) | c3; |
| 1097 |
| 1098 data[oidx++] = (c24 >> 16) & 0xff; |
| 1099 if (oidx == olen) { |
| 1100 break; |
| 1101 } |
| 1102 data[oidx++] = (c24 >> 8) & 0xff; |
| 1103 if (oidx == olen) { |
| 1104 break; |
| 1105 } |
| 1106 data[oidx++] = c24 & 0xff; |
| 1107 } |
| 1108 |
| 1109 return data; |
| 1110 } |
| 1111 |
| 1112 String decode(String s) => new String.fromCharCodes(decodeAsList(s)); |
| 1113 |
| 1114 // Encode a String as a Base64 string. Only the low 8 bits of each |
| 1115 // character code are used. |
| 1116 String encodeList(List<int> x, [bool pad = true]) { |
| 1117 int idx = 0; |
| 1118 int bytesLeft = x.length; |
| 1119 List<int> data = new List<int>(); |
| 1120 while (bytesLeft > 0) { |
| 1121 // Concatenate up to 3 input characters into a 24-bit chunk |
| 1122 int b0 = x[idx++] & 0xff; |
| 1123 int b1 = (bytesLeft > 1) ? x[idx++] & 0xff : 0; |
| 1124 int b2 = (bytesLeft > 2) ? x[idx++] & 0xff : 0; |
| 1125 int b24 = (b0 << 16) | (b1 << 8) | b2; |
| 1126 |
| 1127 // Extract 4 6-bit chunks |
| 1128 int c0 = (b24 >> 18) & 0x3f; |
| 1129 int c1 = (b24 >> 12) & 0x3f; |
| 1130 int c2 = (b24 >> 6) & 0x3f; |
| 1131 int c3 = b24 & 0x3f; |
| 1132 |
| 1133 // Ouput 4 characters, padding unused bits with "=" |
| 1134 data.add(_base64Chars[c0]); |
| 1135 data.add(_base64Chars[c1]); |
| 1136 if (bytesLeft > 1 || pad) { |
| 1137 data.add(bytesLeft > 1 ? _base64Chars[c2] : _padding); |
| 1138 } |
| 1139 if (bytesLeft > 2 || pad) { |
| 1140 data.add(bytesLeft > 2 ? _base64Chars[c3] : _padding); |
| 1141 } |
| 1142 bytesLeft -= 3; |
| 1143 } |
| 1144 return new String.fromCharCodes(data); |
| 1145 } |
| 1146 |
| 1147 String encode(String s, [bool pad = true]) => encodeList(s.charCodes(), pad); |
| 1148 } |
OLD | NEW |