├── .github ├── dependabot.yml └── workflows │ ├── publish.yaml │ └── test-package.yml ├── .gitignore ├── AUTHORS ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── lib ├── fixnum.dart └── src │ ├── int32.dart │ ├── int64.dart │ ├── intx.dart │ └── utilities.dart ├── pubspec.yaml └── test ├── all_tests.dart ├── int32_test.dart ├── int64_test.dart └── int_64_vm_test.dart /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Dependabot configuration file. 2 | # See https://docs.github.com/en/code-security/dependabot/dependabot-version-updates 3 | version: 2 4 | 5 | updates: 6 | - package-ecosystem: github-actions 7 | directory: / 8 | schedule: 9 | interval: monthly 10 | labels: 11 | - autosubmit 12 | groups: 13 | github-actions: 14 | patterns: 15 | - "*" 16 | -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | # A CI configuration to auto-publish pub packages. 2 | 3 | name: Publish 4 | 5 | on: 6 | pull_request: 7 | branches: [ master ] 8 | push: 9 | tags: [ 'v[0-9]+.[0-9]+.[0-9]+*' ] 10 | 11 | jobs: 12 | publish: 13 | if: ${{ github.repository_owner == 'dart-lang' }} 14 | uses: dart-lang/ecosystem/.github/workflows/publish.yaml@main 15 | -------------------------------------------------------------------------------- /.github/workflows/test-package.yml: -------------------------------------------------------------------------------- 1 | name: Dart CI 2 | 3 | on: 4 | # Run on PRs and pushes to the default branch. 5 | push: 6 | branches: [ master ] 7 | pull_request: 8 | branches: [ master ] 9 | schedule: 10 | - cron: "0 0 * * 0" 11 | 12 | env: 13 | PUB_ENVIRONMENT: bot.github 14 | 15 | jobs: 16 | # Check code formatting and static analysis on a single OS (linux) 17 | # against Dart dev. 18 | analyze: 19 | runs-on: ubuntu-latest 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | sdk: [3.1.0, dev] 24 | steps: 25 | - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 26 | - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 27 | with: 28 | sdk: ${{ matrix.sdk }} 29 | - id: install 30 | name: Install dependencies 31 | run: dart pub get 32 | - name: Check formatting 33 | run: dart format --output=none --set-exit-if-changed . 34 | if: always() && steps.install.outcome == 'success' 35 | - name: Analyze code 36 | run: dart analyze --fatal-infos 37 | if: always() && steps.install.outcome == 'success' 38 | 39 | # Run tests on a matrix consisting of two dimensions: 40 | # 1. OS: ubuntu-latest, (macos-latest, windows-latest) 41 | # 2. release channel: dev 42 | test: 43 | needs: analyze 44 | runs-on: ${{ matrix.os }} 45 | strategy: 46 | fail-fast: false 47 | matrix: 48 | # Add macos-latest and/or windows-latest if relevant for this package. 49 | os: [ubuntu-latest] 50 | sdk: [3.1.0, dev] 51 | steps: 52 | - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 53 | - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 54 | with: 55 | sdk: ${{ matrix.sdk }} 56 | - id: install 57 | name: Install dependencies 58 | run: dart pub get 59 | - name: Run VM tests 60 | run: dart test --platform vm 61 | if: always() && steps.install.outcome == 'success' 62 | - name: Run Chrome tests 63 | run: dart test --platform chrome 64 | if: always() && steps.install.outcome == 'success' 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .dart_tool/ 2 | .packages 3 | pubspec.lock 4 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # Names should be added to this file with this pattern: 2 | # 3 | # For individuals: 4 | # Name 5 | # 6 | # For organizations: 7 | # Organization 8 | # 9 | Google Inc. <*@google.com> -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.1.1-wip 2 | 3 | * Require Dart `^3.1.0` 4 | 5 | ## 1.1.0 6 | 7 | * Add `tryParseRadix`, `tryParseInt` and `tryParseHex` static methods 8 | to both `Int32` and `Int64`. 9 | * Document exception and overflow behavior of parse functions, 10 | and of `toHexString`. 11 | * Make `Int32` parse functions consistent with documentation (accept 12 | leading minus sign, do not accept empty inputs). 13 | * Update the minimum SDK constraint to 2.19. 14 | * Update to package:lints 2.0.0. 15 | 16 | ## 1.0.1 17 | 18 | * Switch to using `package:lints`. 19 | * Populate the pubspec `repository` field. 20 | 21 | ## 1.0.0 22 | 23 | * Stable null safety release. 24 | 25 | ## 1.0.0-nullsafety.0 26 | 27 | * Migrate to null safety. 28 | * This is meant to be mostly non-breaking, for opted in users runtime errors 29 | will be promoted to static errors. For non-opted in users the runtime 30 | errors are still present in their original form. 31 | 32 | ## 0.10.11 33 | 34 | * Update minimum SDK constraint to version 2.1.1. 35 | 36 | ## 0.10.10 37 | 38 | * Fix `Int64` parsing to throw `FormatException` on an empty string or single 39 | minus sign. Previous incorrect behaviour was to throw a `RangeError` or 40 | silently return zero. 41 | 42 | ## 0.10.9 43 | 44 | * Add `Int64.toStringUnsigned()` and `Int64.toRadixStringUnsigned()` functions. 45 | 46 | ## 0.10.8 47 | 48 | * Set SDK version constraint to `>=2.0.0-dev.65 <3.0.0`. 49 | 50 | ## 0.10.7 51 | 52 | * Bug fix: Make bit shifts work at bitwidth boundaries. Previously, 53 | `new Int64(3) << 64 == Int64(3)`. This ensures that the result is 0 in such 54 | cases. 55 | * Updated maximum SDK constraint from 2.0.0-dev.infinity to 2.0.0. 56 | 57 | ## 0.10.6 58 | 59 | * Fix `Int64([int value])` constructor to avoid rounding error on intermediate 60 | results for large negative inputs when compiled to JavaScript. `new 61 | Int64(-1000000000000000000)` used to produce the same value as 62 | `Int64.parseInt("-1000000000000000001")` 63 | 64 | ## 0.10.5 65 | 66 | * Fix strong mode warning in overridden `compareTo()` methods. 67 | 68 | *No changelog entries for previous versions...* 69 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | ### Sign our Contributor License Agreement (CLA) 4 | 5 | Even for small changes, we ask that you please sign the CLA electronically 6 | [here](https://developers.google.com/open-source/cla/individual). 7 | The CLA is necessary because you own the copyright to your changes, even 8 | after your contribution becomes part of our codebase, so we need your permission 9 | to use and distribute your code. You can find more details 10 | [here](https://code.google.com/p/dart/wiki/Contributing). 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014, the Dart project authors. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following 11 | disclaimer in the documentation and/or other materials provided 12 | with the distribution. 13 | * Neither the name of Google LLC nor the names of its 14 | contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!IMPORTANT] 2 | > This repo has moved to https://github.com/dart-lang/core/tree/main/pkgs/fixnum 3 | 4 | [![Dart CI](https://github.com/dart-lang/fixnum/actions/workflows/test-package.yml/badge.svg)](https://github.com/dart-lang/fixnum/actions/workflows/test-package.yml) 5 | [![Pub](https://img.shields.io/pub/v/fixnum.svg)](https://pub.dev/packages/fixnum) 6 | [![package publisher](https://img.shields.io/pub/publisher/fixnum.svg)](https://pub.dev/packages/fixnum/publisher) 7 | 8 | A fixed-width 32- and 64- bit integer library for Dart. 9 | 10 | Provides data types for signed 32- and 64-bit integers. 11 | The integer implementations in this library are designed to work identically 12 | whether executed on the Dart VM or compiled to JavaScript. 13 | 14 | ## Publishing automation 15 | 16 | For information about our publishing automation and release process, see 17 | https://github.com/dart-lang/ecosystem/wiki/Publishing-automation. 18 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:dart_flutter_team_lints/analysis_options.yaml 2 | 3 | analyzer: 4 | language: 5 | strict-casts: true 6 | 7 | linter: 8 | rules: 9 | - avoid_private_typedef_functions 10 | - avoid_unused_constructor_parameters 11 | - cancel_subscriptions 12 | - cascade_invocations 13 | - join_return_with_assignment 14 | - missing_whitespace_between_adjacent_strings 15 | - no_adjacent_strings_in_list 16 | - no_runtimeType_toString 17 | - package_api_docs 18 | - prefer_const_declarations 19 | - prefer_expression_function_bodies 20 | - unnecessary_raw_strings 21 | - use_string_buffers 22 | -------------------------------------------------------------------------------- /lib/fixnum.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, 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 | /// Signed 32- and 64-bit integer support. 6 | /// 7 | /// The integer implementations in this library are designed to work 8 | /// identically whether executed on the Dart VM or compiled to JavaScript. 9 | library; 10 | 11 | export 'src/int32.dart'; 12 | export 'src/int64.dart'; 13 | export 'src/intx.dart'; 14 | -------------------------------------------------------------------------------- /lib/src/int32.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, 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 | // ignore_for_file: constant_identifier_names 6 | 7 | import 'int64.dart'; 8 | import 'intx.dart'; 9 | import 'utilities.dart' as u; 10 | 11 | /// An immutable 32-bit signed integer, in the range [-2^31, 2^31 - 1]. 12 | /// Arithmetic operations may overflow in order to maintain this range. 13 | class Int32 implements IntX { 14 | /// The maximum positive value attainable by an [Int32], namely 15 | /// 2147483647. 16 | static const Int32 MAX_VALUE = Int32._internal(0x7FFFFFFF); 17 | 18 | /// The minimum positive value attainable by an [Int32], namely 19 | /// -2147483648. 20 | static const Int32 MIN_VALUE = Int32._internal(-0x80000000); 21 | 22 | /// An [Int32] constant equal to 0. 23 | static const Int32 ZERO = Int32._internal(0); 24 | 25 | /// An [Int32] constant equal to 1. 26 | static const Int32 ONE = Int32._internal(1); 27 | 28 | /// An [Int32] constant equal to 2. 29 | static const Int32 TWO = Int32._internal(2); 30 | 31 | // Mask to 32-bits. 32 | static const int _MASK_U32 = 0xFFFFFFFF; 33 | 34 | /// Parses [source] in a given [radix] between 2 and 36. 35 | /// 36 | /// Returns an [Int32] with the numerical value of [source]. 37 | /// If the numerical value of [source] does not fit 38 | /// in a signed 32 bit integer, 39 | /// the numerical value is truncated to the lowest 32 bits 40 | /// of the value's binary representation, 41 | /// interpreted as a 32-bit two's complement integer. 42 | /// 43 | /// The [source] string must contain a sequence of base-[radix] 44 | /// digits (using letters from `a` to `z` as digits with values 10 through 45 | /// 25 for radixes above 10), possibly prefixed by a `-` sign. 46 | /// 47 | /// Throws a [FormatException] if the input is not a valid 48 | /// integer numeral in base [radix]. 49 | static Int32 parseRadix(String source, int radix) => 50 | _parseRadix(source, u.validateRadix(radix), true)!; 51 | 52 | /// Parses [source] in a given [radix] between 2 and 36. 53 | /// 54 | /// Returns an [Int32] with the numerical value of [source]. 55 | /// If the numerical value of [source] does not fit 56 | /// in a signed 32 bit integer, 57 | /// the numerical value is truncated to the lowest 32 bits 58 | /// of the value's binary representation, 59 | /// interpreted as a 32-bit two's complement integer. 60 | /// 61 | /// The [source] string must contain a sequence of base-[radix] 62 | /// digits (using letters from `a` to `z` as digits with values 10 through 63 | /// 25 for radixes above 10), possibly prefixed by a `-` sign. 64 | /// 65 | /// Throws a [FormatException] if the input is not a valid 66 | /// integer numeral in base [radix]. 67 | static Int32? tryParseRadix(String source, int radix) => 68 | _parseRadix(source, u.validateRadix(radix), false); 69 | 70 | // TODO(rice) - Make this faster by converting several digits at once. 71 | static Int32? _parseRadix(String s, int radix, bool throwOnError) { 72 | var index = 0; 73 | var negative = false; 74 | if (s.startsWith('-')) { 75 | negative = true; 76 | index = 1; 77 | } 78 | if (index == s.length) { 79 | if (!throwOnError) return null; 80 | throw FormatException('No digits', s, index); 81 | } 82 | var result = 0; 83 | for (; index < s.length; index++) { 84 | var c = s.codeUnitAt(index); 85 | var digit = u.decodeDigit(c); 86 | if (digit < radix) { 87 | /// Doesn't matter whether the result is unsigned 88 | /// or signed (as on the web), only the bits matter 89 | /// to the [Int32.new] constructor. 90 | result = (result * radix + digit) & _MASK_U32; 91 | } else { 92 | if (!throwOnError) return null; 93 | throw FormatException('Non radix code unit', s, index); 94 | } 95 | } 96 | if (negative) result = -result; 97 | return Int32(result); 98 | } 99 | 100 | /// Parses [source] as a decimal numeral. 101 | /// 102 | /// Returns an [Int32] with the numerical value of [source]. 103 | /// If the numerical value of [source] does not fit 104 | /// in a signed 32 bit integer, 105 | /// the numerical value is truncated to the lowest 32 bits 106 | /// of the value's binary representation, 107 | /// interpreted as a 32-bit two's complement integer. 108 | /// 109 | /// The [source] string must contain a sequence of digits (`0`-`9`), 110 | /// possibly prefixed by a `-` sign. 111 | /// 112 | /// Throws a [FormatException] if the input is not a valid 113 | /// decimal integer numeral. 114 | static Int32 parseInt(String source) => _parseRadix(source, 10, true)!; 115 | 116 | /// Parses [source] as a decimal numeral. 117 | /// 118 | /// Returns an [Int32] with the numerical value of [source]. 119 | /// If the numerical value of [source] does not fit 120 | /// in a signed 32 bit integer, 121 | /// the numerical value is truncated to the lowest 32 bits 122 | /// of the value's binary representation, 123 | /// interpreted as a 32-bit two's complement integer. 124 | /// 125 | /// The [source] string must contain a sequence of digits (`0`-`9`), 126 | /// possibly prefixed by a `-` sign. 127 | /// 128 | /// Throws a [FormatException] if the input is not a valid 129 | /// decimal integer numeral. 130 | static Int32? tryParseInt(String source) => _parseRadix(source, 10, false); 131 | 132 | /// Parses [source] as a hexadecimal numeral. 133 | /// 134 | /// Returns an [Int32] with the numerical value of [source]. 135 | /// If the numerical value of [source] does not fit 136 | /// in a signed 32 bit integer, 137 | /// the numerical value is truncated to the lowest 32 bits 138 | /// of the value's binary representation, 139 | /// interpreted as a 32-bit two's complement integer. 140 | /// 141 | /// The [source] string must contain a sequence of hexadecimal 142 | /// digits (`0`-`9`, `a`-`f` or `A`-`F`), possibly prefixed by a `-` sign. 143 | /// 144 | /// Returns `null` if the input is not a valid 145 | /// hexadecimal integer numeral. 146 | static Int32 parseHex(String source) => _parseRadix(source, 16, true)!; 147 | 148 | /// Parses [source] as a hexadecimal numeral. 149 | /// 150 | /// Returns an [Int32] with the numerical value of [source]. 151 | /// If the numerical value of [source] does not fit 152 | /// in a signed 32 bit integer, 153 | /// the numerical value is truncated to the lowest 32 bits 154 | /// of the value's binary representation, 155 | /// interpreted as a 32-bit two's complement integer. 156 | /// 157 | /// The [source] string must contain a sequence of hexadecimal 158 | /// digits (`0`-`9`, `a`-`f` or `A`-`F`), possibly prefixed by a `-` sign. 159 | /// 160 | /// Returns `null` if the input is not a valid 161 | /// hexadecimal integer numeral. 162 | static Int32? tryParseHex(String source) => _parseRadix(source, 16, false); 163 | 164 | // The internal value, kept in the range [MIN_VALUE, MAX_VALUE]. 165 | final int _i; 166 | 167 | const Int32._internal(int i) : _i = i; 168 | 169 | /// Constructs an [Int32] from an [int]. Only the low 32 bits of the input 170 | /// are used. 171 | Int32([int i = 0]) : _i = (i & 0x7fffffff) - (i & 0x80000000); 172 | 173 | // Returns the [int] representation of the specified value. Throws 174 | // [ArgumentError] for non-integer arguments. 175 | int _toInt(Object val) { 176 | if (val is Int32) { 177 | return val._i; 178 | } else if (val is int) { 179 | return val; 180 | } 181 | throw ArgumentError.value(val, 'other', 'Not an int, Int32 or Int64'); 182 | } 183 | 184 | // The +, -, * , &, |, and ^ operaters deal with types as follows: 185 | // 186 | // Int32 + int => Int32 187 | // Int32 + Int32 => Int32 188 | // Int32 + Int64 => Int64 189 | // 190 | // The %, ~/ and remainder operators return an Int32 even with an Int64 191 | // argument, since the result cannot be greater than the value on the 192 | // left-hand side: 193 | // 194 | // Int32 % int => Int32 195 | // Int32 % Int32 => Int32 196 | // Int32 % Int64 => Int32 197 | 198 | @override 199 | IntX operator +(Object other) { 200 | if (other is Int64) { 201 | return toInt64() + other; 202 | } 203 | return Int32(_i + _toInt(other)); 204 | } 205 | 206 | @override 207 | IntX operator -(Object other) { 208 | if (other is Int64) { 209 | return toInt64() - other; 210 | } 211 | return Int32(_i - _toInt(other)); 212 | } 213 | 214 | @override 215 | Int32 operator -() => Int32(-_i); 216 | 217 | @override 218 | IntX operator *(Object other) { 219 | if (other is Int64) { 220 | return toInt64() * other; 221 | } 222 | // TODO(rice) - optimize 223 | return (toInt64() * other).toInt32(); 224 | } 225 | 226 | @override 227 | Int32 operator %(Object other) { 228 | if (other is Int64) { 229 | // Result will be Int32 230 | return (toInt64() % other).toInt32(); 231 | } 232 | return Int32(_i % _toInt(other)); 233 | } 234 | 235 | @override 236 | Int32 operator ~/(Object other) { 237 | if (other is Int64) { 238 | return (toInt64() ~/ other).toInt32(); 239 | } 240 | return Int32(_i ~/ _toInt(other)); 241 | } 242 | 243 | @override 244 | Int32 remainder(Object other) { 245 | if (other is Int64) { 246 | var t = toInt64(); 247 | return (t - (t ~/ other) * other).toInt32(); 248 | } 249 | return this - (this ~/ other) * other as Int32; 250 | } 251 | 252 | @override 253 | Int32 operator &(Object other) { 254 | if (other is Int64) { 255 | return (toInt64() & other).toInt32(); 256 | } 257 | return Int32(_i & _toInt(other)); 258 | } 259 | 260 | @override 261 | Int32 operator |(Object other) { 262 | if (other is Int64) { 263 | return (toInt64() | other).toInt32(); 264 | } 265 | return Int32(_i | _toInt(other)); 266 | } 267 | 268 | @override 269 | Int32 operator ^(Object other) { 270 | if (other is Int64) { 271 | return (toInt64() ^ other).toInt32(); 272 | } 273 | return Int32(_i ^ _toInt(other)); 274 | } 275 | 276 | @override 277 | Int32 operator ~() => Int32(~_i); 278 | 279 | @override 280 | Int32 operator <<(int n) { 281 | if (n < 0) { 282 | throw ArgumentError(n); 283 | } 284 | if (n >= 32) { 285 | return ZERO; 286 | } 287 | return Int32(_i << n); 288 | } 289 | 290 | @override 291 | Int32 operator >>(int n) { 292 | if (n < 0) { 293 | throw ArgumentError(n); 294 | } 295 | if (n >= 32) { 296 | return isNegative ? const Int32._internal(-1) : ZERO; 297 | } 298 | int value; 299 | if (_i >= 0) { 300 | value = _i >> n; 301 | } else { 302 | value = (_i >> n) | (0xffffffff << (32 - n)); 303 | } 304 | return Int32(value); 305 | } 306 | 307 | @override 308 | Int32 shiftRightUnsigned(int n) { 309 | if (n < 0) { 310 | throw ArgumentError(n); 311 | } 312 | if (n >= 32) { 313 | return ZERO; 314 | } 315 | int value; 316 | if (_i >= 0) { 317 | value = _i >> n; 318 | } else { 319 | value = (_i >> n) & ((1 << (32 - n)) - 1); 320 | } 321 | return Int32(value); 322 | } 323 | 324 | /// Returns [:true:] if this [Int32] has the same numeric value as the 325 | /// given object. The argument may be an [int] or an [IntX]. 326 | @override 327 | bool operator ==(Object other) { 328 | if (other is Int32) { 329 | return _i == other._i; 330 | } else if (other is Int64) { 331 | return toInt64() == other; 332 | } else if (other is int) { 333 | return _i == other; 334 | } 335 | return false; 336 | } 337 | 338 | @override 339 | int compareTo(Object other) { 340 | if (other is Int64) { 341 | return toInt64().compareTo(other); 342 | } 343 | return _i.compareTo(_toInt(other)); 344 | } 345 | 346 | @override 347 | bool operator <(Object other) { 348 | if (other is Int64) { 349 | return toInt64() < other; 350 | } 351 | return _i < _toInt(other); 352 | } 353 | 354 | @override 355 | bool operator <=(Object other) { 356 | if (other is Int64) { 357 | return toInt64() <= other; 358 | } 359 | return _i <= _toInt(other); 360 | } 361 | 362 | @override 363 | bool operator >(Object other) { 364 | if (other is Int64) { 365 | return toInt64() > other; 366 | } 367 | return _i > _toInt(other); 368 | } 369 | 370 | @override 371 | bool operator >=(Object other) { 372 | if (other is Int64) { 373 | return toInt64() >= other; 374 | } 375 | return _i >= _toInt(other); 376 | } 377 | 378 | @override 379 | bool get isEven => (_i & 0x1) == 0; 380 | 381 | @override 382 | bool get isMaxValue => _i == 2147483647; 383 | 384 | @override 385 | bool get isMinValue => _i == -2147483648; 386 | 387 | @override 388 | bool get isNegative => _i < 0; 389 | 390 | @override 391 | bool get isOdd => (_i & 0x1) == 1; 392 | 393 | @override 394 | bool get isZero => _i == 0; 395 | 396 | @override 397 | int get bitLength => _i.bitLength; 398 | 399 | @override 400 | int get hashCode => _i; 401 | 402 | @override 403 | Int32 abs() => _i < 0 ? Int32(-_i) : this; 404 | 405 | @override 406 | Int32 clamp(Object lowerLimit, Object upperLimit) { 407 | if (this < lowerLimit) { 408 | if (lowerLimit is IntX) return lowerLimit.toInt32(); 409 | if (lowerLimit is int) return Int32(lowerLimit); 410 | throw ArgumentError(lowerLimit); 411 | } else if (this > upperLimit) { 412 | if (upperLimit is IntX) return upperLimit.toInt32(); 413 | if (upperLimit is int) return Int32(upperLimit); 414 | throw ArgumentError(upperLimit); 415 | } 416 | return this; 417 | } 418 | 419 | @override 420 | int numberOfLeadingZeros() => u.numberOfLeadingZeros(_i); 421 | 422 | @override 423 | int numberOfTrailingZeros() => u.numberOfTrailingZeros(_i); 424 | 425 | @override 426 | Int32 toSigned(int width) { 427 | if (width < 1 || width > 32) throw RangeError.range(width, 1, 32); 428 | return Int32(_i.toSigned(width)); 429 | } 430 | 431 | @override 432 | Int32 toUnsigned(int width) { 433 | if (width < 0 || width > 32) throw RangeError.range(width, 0, 32); 434 | return Int32(_i.toUnsigned(width)); 435 | } 436 | 437 | @override 438 | List toBytes() { 439 | var result = List.filled(4, 0); 440 | result[0] = _i & 0xff; 441 | result[1] = (_i >> 8) & 0xff; 442 | result[2] = (_i >> 16) & 0xff; 443 | result[3] = (_i >> 24) & 0xff; 444 | return result; 445 | } 446 | 447 | @override 448 | double toDouble() => _i.toDouble(); 449 | 450 | @override 451 | int toInt() => _i; 452 | 453 | @override 454 | Int32 toInt32() => this; 455 | 456 | @override 457 | Int64 toInt64() => Int64(_i); 458 | 459 | @override 460 | String toString() => _i.toString(); 461 | 462 | @override 463 | String toHexString() => _i.toRadixString(16); 464 | 465 | @override 466 | String toRadixString(int radix) => _i.toRadixString(radix); 467 | } 468 | -------------------------------------------------------------------------------- /lib/src/int64.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, 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 | // ignore_for_file: constant_identifier_names 6 | 7 | // Many locals are declared as `int` or `double`. We keep local variable types 8 | // because the types are critical to the efficiency of many operations. 9 | // 10 | // ignore_for_file: omit_local_variable_types 11 | 12 | import 'int32.dart'; 13 | import 'intx.dart'; 14 | import 'utilities.dart' as u; 15 | 16 | /// An immutable 64-bit signed integer, in the range [-2^63, 2^63 - 1]. 17 | /// Arithmetic operations may overflow in order to maintain this range. 18 | class Int64 implements IntX { 19 | // A 64-bit integer is represented internally as three non-negative 20 | // integers, storing the 22 low, 22 middle, and 20 high bits of the 21 | // 64-bit value. _l (low) and _m (middle) are in the range 22 | // [0, 2^22 - 1] and _h (high) is in the range [0, 2^20 - 1]. 23 | // 24 | // The values being assigned to _l, _m and _h in initialization are masked to 25 | // force them into the above ranges. Sometimes we know that the value is a 26 | // small non-negative integer but the dart2js compiler can't infer that, so a 27 | // few of the masking operations are not needed for correctness but are 28 | // helpful for dart2js code quality. 29 | 30 | final int _l, _m, _h; 31 | 32 | // Note: several functions require _BITS == 22 -- do not change this value. 33 | static const int _BITS = 22; 34 | static const int _BITS01 = 44; // 2 * _BITS 35 | static const int _BITS2 = 20; // 64 - _BITS01 36 | static const int _MASK = 4194303; // (1 << _BITS) - 1 37 | static const int _MASK2 = 1048575; // (1 << _BITS2) - 1 38 | static const int _SIGN_BIT = 19; // _BITS2 - 1 39 | static const int _SIGN_BIT_MASK = 1 << _SIGN_BIT; 40 | 41 | /// The maximum positive value attainable by an [Int64], namely 42 | /// 9,223,372,036,854,775,807. 43 | static const Int64 MAX_VALUE = Int64._bits(_MASK, _MASK, _MASK2 >> 1); 44 | 45 | /// The minimum positive value attainable by an [Int64], namely 46 | /// -9,223,372,036,854,775,808. 47 | static const Int64 MIN_VALUE = Int64._bits(0, 0, _SIGN_BIT_MASK); 48 | 49 | /// An [Int64] constant equal to 0. 50 | static const Int64 ZERO = Int64._bits(0, 0, 0); 51 | 52 | /// An [Int64] constant equal to 1. 53 | static const Int64 ONE = Int64._bits(1, 0, 0); 54 | 55 | /// An [Int64] constant equal to 2. 56 | static const Int64 TWO = Int64._bits(2, 0, 0); 57 | 58 | /// Constructs an [Int64] with a given bitwise representation. No validation 59 | /// is performed. 60 | const Int64._bits(this._l, this._m, this._h); 61 | 62 | /// Parses [source] in a given [radix] between 2 and 36. 63 | /// 64 | /// Returns an [Int64] with the numerical value of [source]. 65 | /// If the numerical value of [source] does not fit 66 | /// in a signed 64 bit integer, 67 | /// the numerical value is truncated to the lowest 64 bits 68 | /// of the value's binary representation, 69 | /// interpreted as a 64-bit two's complement integer. 70 | /// 71 | /// The [source] string must contain a sequence of base-[radix] 72 | /// digits (using letters from `a` to `z` as digits with values 10 through 73 | /// 25 for radixes above 10), possibly prefixed by a `-` sign. 74 | /// 75 | /// Throws a [FormatException] if the input is not recognized as a valid 76 | /// integer numeral. 77 | static Int64 parseRadix(String source, int radix) => 78 | _parseRadix(source, u.validateRadix(radix), true)!; 79 | 80 | /// Parses [source] in a given [radix] between 2 and 36. 81 | /// 82 | /// Returns an [Int64] with the numerical value of [source]. 83 | /// If the numerical value of [source] does not fit 84 | /// in a signed 64 bit integer, 85 | /// the numerical value is truncated to the lowest 64 bits 86 | /// of the value's binary representation, 87 | /// interpreted as a 64-bit two's complement integer. 88 | /// 89 | /// The [source] string must contain a sequence of base-[radix] 90 | /// digits (using letters from `a` to `z` as digits with values 10 through 91 | /// 25 for radixes above 10), possibly prefixed by a `-` sign. 92 | /// 93 | /// Returns `null` if the input is not recognized as a valid 94 | /// integer numeral. 95 | static Int64? tryParseRadix(String source, int radix) => 96 | _parseRadix(source, u.validateRadix(radix), false); 97 | 98 | static Int64? _parseRadix(String s, int radix, bool throwOnError) { 99 | int i = 0; 100 | bool negative = false; 101 | if (s.startsWith('-')) { 102 | negative = true; 103 | i++; 104 | } 105 | 106 | if (i >= s.length) { 107 | if (!throwOnError) return null; 108 | throw FormatException('No digits', s, i); 109 | } 110 | 111 | int d0 = 0, d1 = 0, d2 = 0; // low, middle, high components. 112 | for (; i < s.length; i++) { 113 | int c = s.codeUnitAt(i); 114 | int digit = u.decodeDigit(c); 115 | if (digit < radix) { 116 | // [radix] and [digit] are at most 6 bits, component is 22, so we can 117 | // multiply and add within 30 bit temporary values. 118 | d0 = d0 * radix + digit; 119 | int carry = d0 >> _BITS; 120 | d0 = _MASK & d0; 121 | 122 | d1 = d1 * radix + carry; 123 | carry = d1 >> _BITS; 124 | d1 = _MASK & d1; 125 | 126 | d2 = d2 * radix + carry; 127 | d2 = _MASK2 & d2; 128 | } else { 129 | if (!throwOnError) return null; 130 | throw FormatException('Not radix digit', s, i); 131 | } 132 | } 133 | 134 | if (negative) return _negate(d0, d1, d2); 135 | 136 | return Int64._masked(d0, d1, d2); 137 | } 138 | 139 | /// Parses [source] as a decimal numeral. 140 | /// 141 | /// Returns an [Int64] with the numerical value of [source]. 142 | /// If the numerical value of [source] does not fit 143 | /// in a signed 64 bit integer, 144 | /// the numerical value is truncated to the lowest 64 bits 145 | /// of the value's binary representation, 146 | /// interpreted as a 64-bit two's complement integer. 147 | /// 148 | /// The [source] string must contain a sequence of digits (`0`-`9`), 149 | /// possibly prefixed by a `-` sign. 150 | /// 151 | /// Throws a [FormatException] if the input is not a valid 152 | /// decimal integer numeral. 153 | static Int64 parseInt(String source) => _parseRadix(source, 10, true)!; 154 | 155 | /// Parses [source] as a decimal numeral. 156 | /// 157 | /// Returns an [Int64] with the numerical value of [source]. 158 | /// If the numerical value of [source] does not fit 159 | /// in a signed 64 bit integer, 160 | /// the numerical value is truncated to the lowest 64 bits 161 | /// of the value's binary representation, 162 | /// interpreted as a 64-bit two's complement integer. 163 | /// 164 | /// The [source] string must contain a sequence of digits (`0`-`9`), 165 | /// possibly prefixed by a `-` sign. 166 | /// 167 | /// Returns `null` if the input is not a valid 168 | /// decimal integer numeral. 169 | static Int64? tryParseInt(String source) => _parseRadix(source, 10, false); 170 | 171 | /// Parses [source] as a hexadecimal numeral. 172 | /// 173 | /// Returns an [Int64] with the numerical value of [source]. 174 | /// If the numerical value of [source] does not fit 175 | /// in a signed 64 bit integer, 176 | /// the numerical value is truncated to the lowest 64 bits 177 | /// of the value's binary representation, 178 | /// interpreted as a 64-bit two's complement integer. 179 | /// 180 | /// The [source] string must contain a sequence of hexadecimal 181 | /// digits (`0`-`9`, `a`-`f` or `A`-`F`), possibly prefixed by a `-` sign. 182 | /// 183 | /// Throws a [FormatException] if the input is not a valid 184 | /// hexadecimal integer numeral. 185 | static Int64 parseHex(String source) => _parseRadix(source, 16, true)!; 186 | 187 | /// Parses [source] as a hexadecimal numeral. 188 | /// 189 | /// Returns an [Int64] with the numerical value of [source]. 190 | /// If the numerical value of [source] does not fit 191 | /// in a signed 64 bit integer, 192 | /// the numerical value is truncated to the lowest 64 bits 193 | /// of the value's binary representation, 194 | /// interpreted as a 64-bit two's complement integer. 195 | /// 196 | /// The [source] string must contain a sequence of hexadecimal 197 | /// digits (`0`-`9`, `a`-`f` or `A`-`F`), possibly prefixed by a `-` sign. 198 | /// 199 | /// Returns `null` if the input is not a valid 200 | /// hexadecimal integer numeral. 201 | static Int64? tryParseHex(String source) => _parseRadix(source, 16, false); 202 | 203 | // 204 | // Public constructors 205 | // 206 | 207 | /// Constructs an [Int64] with a given [int] value; zero by default. 208 | factory Int64([int value = 0]) { 209 | int v0 = 0, v1 = 0, v2 = 0; 210 | bool negative = false; 211 | if (value < 0) { 212 | negative = true; 213 | value = -value; 214 | } 215 | // Avoid using bitwise operations that in JavaScript coerce their input to 216 | // 32 bits. 217 | v2 = value ~/ 17592186044416; // 2^44 218 | value -= v2 * 17592186044416; 219 | v1 = value ~/ 4194304; // 2^22 220 | value -= v1 * 4194304; 221 | v0 = value; 222 | 223 | return negative 224 | ? Int64._negate(_MASK & v0, _MASK & v1, _MASK2 & v2) 225 | : Int64._masked(v0, v1, v2); 226 | } 227 | 228 | factory Int64.fromBytes(List bytes) { 229 | // 20 bits into top, 22 into middle and bottom. 230 | var split1 = bytes[5] & 0xFF; 231 | var high = 232 | ((bytes[7] & 0xFF) << 12) | ((bytes[6] & 0xFF) << 4) | (split1 >> 4); 233 | var split2 = bytes[2] & 0xFF; 234 | var middle = (split1 << 18) | 235 | ((bytes[4] & 0xFF) << 10) | 236 | ((bytes[3] & 0xFF) << 2) | 237 | (split2 >> 6); 238 | var low = (split2 << 16) | ((bytes[1] & 0xFF) << 8) | (bytes[0] & 0xFF); 239 | // Top bits from above will be masked off here. 240 | return Int64._masked(low, middle, high); 241 | } 242 | 243 | factory Int64.fromBytesBigEndian(List bytes) { 244 | var split1 = bytes[2] & 0xFF; 245 | var high = 246 | ((bytes[0] & 0xFF) << 12) | ((bytes[1] & 0xFF) << 4) | (split1 >> 4); 247 | var split2 = bytes[5] & 0xFF; 248 | var middle = (split1 << 18) | 249 | ((bytes[3] & 0xFF) << 10) | 250 | ((bytes[4] & 0xFF) << 2) | 251 | (split2 >> 6); 252 | var low = (split2 << 16) | ((bytes[6] & 0xFF) << 8) | (bytes[7] & 0xFF); 253 | // Top bits from above will be masked off here. 254 | return Int64._masked(low, middle, high); 255 | } 256 | 257 | /// Constructs an [Int64] from a pair of 32-bit integers having the value 258 | /// [:((top & 0xffffffff) << 32) | (bottom & 0xffffffff):]. 259 | factory Int64.fromInts(int top, int bottom) { 260 | top &= 0xffffffff; 261 | bottom &= 0xffffffff; 262 | int d0 = _MASK & bottom; 263 | int d1 = ((0xfff & top) << 10) | (0x3ff & (bottom >> _BITS)); 264 | int d2 = _MASK2 & (top >> 12); 265 | return Int64._masked(d0, d1, d2); 266 | } 267 | 268 | // Returns the [Int64] representation of the specified value. Throws 269 | // [ArgumentError] for non-integer arguments. 270 | static Int64 _promote(Object value) { 271 | if (value is Int64) { 272 | return value; 273 | } else if (value is int) { 274 | return Int64(value); 275 | } else if (value is Int32) { 276 | return value.toInt64(); 277 | } 278 | throw ArgumentError.value(value, 'other', 'not an int, Int32 or Int64'); 279 | } 280 | 281 | @override 282 | Int64 operator +(Object other) { 283 | Int64 o = _promote(other); 284 | int sum0 = _l + o._l; 285 | int sum1 = _m + o._m + (sum0 >> _BITS); 286 | int sum2 = _h + o._h + (sum1 >> _BITS); 287 | return Int64._masked(sum0, sum1, sum2); 288 | } 289 | 290 | @override 291 | Int64 operator -(Object other) { 292 | Int64 o = _promote(other); 293 | return _sub(_l, _m, _h, o._l, o._m, o._h); 294 | } 295 | 296 | @override 297 | Int64 operator -() => _negate(_l, _m, _h); 298 | 299 | @override 300 | Int64 operator *(Object other) { 301 | Int64 o = _promote(other); 302 | 303 | // Grab 13-bit chunks. 304 | int a0 = _l & 0x1fff; 305 | int a1 = (_l >> 13) | ((_m & 0xf) << 9); 306 | int a2 = (_m >> 4) & 0x1fff; 307 | int a3 = (_m >> 17) | ((_h & 0xff) << 5); 308 | int a4 = (_h & 0xfff00) >> 8; 309 | 310 | int b0 = o._l & 0x1fff; 311 | int b1 = (o._l >> 13) | ((o._m & 0xf) << 9); 312 | int b2 = (o._m >> 4) & 0x1fff; 313 | int b3 = (o._m >> 17) | ((o._h & 0xff) << 5); 314 | int b4 = (o._h & 0xfff00) >> 8; 315 | 316 | // Compute partial products. 317 | // Optimization: if b is small, avoid multiplying by parts that are 0. 318 | int p0 = a0 * b0; // << 0 319 | int p1 = a1 * b0; // << 13 320 | int p2 = a2 * b0; // << 26 321 | int p3 = a3 * b0; // << 39 322 | int p4 = a4 * b0; // << 52 323 | 324 | if (b1 != 0) { 325 | p1 += a0 * b1; 326 | p2 += a1 * b1; 327 | p3 += a2 * b1; 328 | p4 += a3 * b1; 329 | } 330 | if (b2 != 0) { 331 | p2 += a0 * b2; 332 | p3 += a1 * b2; 333 | p4 += a2 * b2; 334 | } 335 | if (b3 != 0) { 336 | p3 += a0 * b3; 337 | p4 += a1 * b3; 338 | } 339 | if (b4 != 0) { 340 | p4 += a0 * b4; 341 | } 342 | 343 | // Accumulate into 22-bit chunks: 344 | // .........................................c10|...................c00| 345 | // |....................|..................xxxx|xxxxxxxxxxxxxxxxxxxxxx| p0 346 | // |....................|......................|......................| 347 | // |....................|...................c11|......c01.............| 348 | // |....................|....xxxxxxxxxxxxxxxxxx|xxxxxxxxx.............| p1 349 | // |....................|......................|......................| 350 | // |.................c22|...............c12....|......................| 351 | // |..........xxxxxxxxxx|xxxxxxxxxxxxxxxxxx....|......................| p2 352 | // |....................|......................|......................| 353 | // |.................c23|..c13.................|......................| 354 | // |xxxxxxxxxxxxxxxxxxxx|xxxxx.................|......................| p3 355 | // |....................|......................|......................| 356 | // |.........c24........|......................|......................| 357 | // |xxxxxxxxxxxx........|......................|......................| p4 358 | 359 | int c00 = p0 & 0x3fffff; 360 | int c01 = (p1 & 0x1ff) << 13; 361 | int c0 = c00 + c01; 362 | 363 | int c10 = p0 >> 22; 364 | int c11 = p1 >> 9; 365 | int c12 = (p2 & 0x3ffff) << 4; 366 | int c13 = (p3 & 0x1f) << 17; 367 | int c1 = c10 + c11 + c12 + c13; 368 | 369 | int c22 = p2 >> 18; 370 | int c23 = p3 >> 5; 371 | int c24 = (p4 & 0xfff) << 8; 372 | int c2 = c22 + c23 + c24; 373 | 374 | // Propagate high bits from c0 -> c1, c1 -> c2. 375 | c1 += c0 >> _BITS; 376 | c2 += c1 >> _BITS; 377 | 378 | return Int64._masked(c0, c1, c2); 379 | } 380 | 381 | @override 382 | Int64 operator %(Object other) => _divide(this, other, _RETURN_MOD); 383 | 384 | @override 385 | Int64 operator ~/(Object other) => _divide(this, other, _RETURN_DIV); 386 | 387 | @override 388 | Int64 remainder(Object other) => _divide(this, other, _RETURN_REM); 389 | 390 | @override 391 | Int64 operator &(Object other) { 392 | Int64 o = _promote(other); 393 | int a0 = _l & o._l; 394 | int a1 = _m & o._m; 395 | int a2 = _h & o._h; 396 | return Int64._masked(a0, a1, a2); 397 | } 398 | 399 | @override 400 | Int64 operator |(Object other) { 401 | Int64 o = _promote(other); 402 | int a0 = _l | o._l; 403 | int a1 = _m | o._m; 404 | int a2 = _h | o._h; 405 | return Int64._masked(a0, a1, a2); 406 | } 407 | 408 | @override 409 | Int64 operator ^(Object other) { 410 | Int64 o = _promote(other); 411 | int a0 = _l ^ o._l; 412 | int a1 = _m ^ o._m; 413 | int a2 = _h ^ o._h; 414 | return Int64._masked(a0, a1, a2); 415 | } 416 | 417 | @override 418 | Int64 operator ~() => Int64._masked(~_l, ~_m, ~_h); 419 | 420 | @override 421 | Int64 operator <<(int n) { 422 | if (n < 0) { 423 | throw ArgumentError.value(n); 424 | } 425 | if (n >= 64) { 426 | return ZERO; 427 | } 428 | 429 | int res0, res1, res2; 430 | if (n < _BITS) { 431 | res0 = _l << n; 432 | res1 = (_m << n) | (_l >> (_BITS - n)); 433 | res2 = (_h << n) | (_m >> (_BITS - n)); 434 | } else if (n < _BITS01) { 435 | res0 = 0; 436 | res1 = _l << (n - _BITS); 437 | res2 = (_m << (n - _BITS)) | (_l >> (_BITS01 - n)); 438 | } else { 439 | res0 = 0; 440 | res1 = 0; 441 | res2 = _l << (n - _BITS01); 442 | } 443 | 444 | return Int64._masked(res0, res1, res2); 445 | } 446 | 447 | @override 448 | Int64 operator >>(int n) { 449 | if (n < 0) { 450 | throw ArgumentError.value(n); 451 | } 452 | if (n >= 64) { 453 | return isNegative ? const Int64._bits(_MASK, _MASK, _MASK2) : ZERO; 454 | } 455 | 456 | int res0, res1, res2; 457 | 458 | // Sign extend h(a). 459 | int a2 = _h; 460 | bool negative = (a2 & _SIGN_BIT_MASK) != 0; 461 | if (negative && _MASK > _MASK2) { 462 | // Add extra one bits on the left so the sign gets shifted into the wider 463 | // lower words. 464 | a2 += _MASK - _MASK2; 465 | } 466 | 467 | if (n < _BITS) { 468 | res2 = _shiftRight(a2, n); 469 | if (negative) { 470 | res2 |= _MASK2 & ~(_MASK2 >> n); 471 | } 472 | res1 = _shiftRight(_m, n) | (a2 << (_BITS - n)); 473 | res0 = _shiftRight(_l, n) | (_m << (_BITS - n)); 474 | } else if (n < _BITS01) { 475 | res2 = negative ? _MASK2 : 0; 476 | res1 = _shiftRight(a2, n - _BITS); 477 | if (negative) { 478 | res1 |= _MASK & ~(_MASK >> (n - _BITS)); 479 | } 480 | res0 = _shiftRight(_m, n - _BITS) | (a2 << (_BITS01 - n)); 481 | } else { 482 | res2 = negative ? _MASK2 : 0; 483 | res1 = negative ? _MASK : 0; 484 | res0 = _shiftRight(a2, n - _BITS01); 485 | if (negative) { 486 | res0 |= _MASK & ~(_MASK >> (n - _BITS01)); 487 | } 488 | } 489 | 490 | return Int64._masked(res0, res1, res2); 491 | } 492 | 493 | @override 494 | Int64 shiftRightUnsigned(int n) { 495 | if (n < 0) { 496 | throw ArgumentError.value(n); 497 | } 498 | if (n >= 64) { 499 | return ZERO; 500 | } 501 | 502 | int res0, res1, res2; 503 | int a2 = _MASK2 & _h; // Ensure a2 is positive. 504 | if (n < _BITS) { 505 | res2 = a2 >> n; 506 | res1 = (_m >> n) | (a2 << (_BITS - n)); 507 | res0 = (_l >> n) | (_m << (_BITS - n)); 508 | } else if (n < _BITS01) { 509 | res2 = 0; 510 | res1 = a2 >> (n - _BITS); 511 | res0 = (_m >> (n - _BITS)) | (_h << (_BITS01 - n)); 512 | } else { 513 | res2 = 0; 514 | res1 = 0; 515 | res0 = a2 >> (n - _BITS01); 516 | } 517 | 518 | return Int64._masked(res0, res1, res2); 519 | } 520 | 521 | /// Returns [:true:] if this [Int64] has the same numeric value as the 522 | /// given object. The argument may be an [int] or an [IntX]. 523 | @override 524 | bool operator ==(Object other) { 525 | Int64? o; 526 | if (other is Int64) { 527 | o = other; 528 | } else if (other is int) { 529 | if (_h == 0 && _m == 0) return _l == other; 530 | // Since we know one of [_h] or [_m] is non-zero, if [other] fits in the 531 | // low word then it can't be numerically equal. 532 | if ((_MASK & other) == other) return false; 533 | o = Int64(other); 534 | } else if (other is Int32) { 535 | o = other.toInt64(); 536 | } 537 | if (o != null) { 538 | return _l == o._l && _m == o._m && _h == o._h; 539 | } 540 | return false; 541 | } 542 | 543 | @override 544 | int compareTo(Object other) => _compareTo(other); 545 | 546 | int _compareTo(Object other) { 547 | Int64 o = _promote(other); 548 | int signa = _h >> (_BITS2 - 1); 549 | int signb = o._h >> (_BITS2 - 1); 550 | if (signa != signb) { 551 | return signa == 0 ? 1 : -1; 552 | } 553 | if (_h > o._h) { 554 | return 1; 555 | } else if (_h < o._h) { 556 | return -1; 557 | } 558 | if (_m > o._m) { 559 | return 1; 560 | } else if (_m < o._m) { 561 | return -1; 562 | } 563 | if (_l > o._l) { 564 | return 1; 565 | } else if (_l < o._l) { 566 | return -1; 567 | } 568 | return 0; 569 | } 570 | 571 | @override 572 | bool operator <(Object other) => _compareTo(other) < 0; 573 | 574 | @override 575 | bool operator <=(Object other) => _compareTo(other) <= 0; 576 | 577 | @override 578 | bool operator >(Object other) => _compareTo(other) > 0; 579 | 580 | @override 581 | bool operator >=(Object other) => _compareTo(other) >= 0; 582 | 583 | @override 584 | bool get isEven => (_l & 0x1) == 0; 585 | 586 | @override 587 | bool get isMaxValue => (_h == _MASK2 >> 1) && _m == _MASK && _l == _MASK; 588 | 589 | @override 590 | bool get isMinValue => _h == _SIGN_BIT_MASK && _m == 0 && _l == 0; 591 | 592 | @override 593 | bool get isNegative => (_h & _SIGN_BIT_MASK) != 0; 594 | 595 | @override 596 | bool get isOdd => (_l & 0x1) == 1; 597 | 598 | @override 599 | bool get isZero => _h == 0 && _m == 0 && _l == 0; 600 | 601 | @override 602 | int get bitLength { 603 | if (isZero) return 0; 604 | int a0 = _l, a1 = _m, a2 = _h; 605 | if (isNegative) { 606 | a0 = _MASK & ~a0; 607 | a1 = _MASK & ~a1; 608 | a2 = _MASK2 & ~a2; 609 | } 610 | if (a2 != 0) return _BITS01 + a2.bitLength; 611 | if (a1 != 0) return _BITS + a1.bitLength; 612 | return a0.bitLength; 613 | } 614 | 615 | /// Returns a hash code based on all the bits of this [Int64]. 616 | @override 617 | int get hashCode { 618 | // TODO(sra): Should we ensure that hashCode values match corresponding int? 619 | // i.e. should `new Int64(x).hashCode == x.hashCode`? 620 | int bottom = ((_m & 0x3ff) << _BITS) | _l; 621 | int top = (_h << 12) | ((_m >> 10) & 0xfff); 622 | return bottom ^ top; 623 | } 624 | 625 | @override 626 | Int64 abs() => isNegative ? -this : this; 627 | 628 | @override 629 | Int64 clamp(Object lowerLimit, Object upperLimit) { 630 | Int64 lower = _promote(lowerLimit); 631 | Int64 upper = _promote(upperLimit); 632 | if (this < lower) return lower; 633 | if (this > upper) return upper; 634 | return this; 635 | } 636 | 637 | /// Returns the number of leading zeros in this [Int64] as an [int] 638 | /// between 0 and 64. 639 | @override 640 | int numberOfLeadingZeros() { 641 | int b2 = u.numberOfLeadingZeros(_h); 642 | if (b2 == 32) { 643 | int b1 = u.numberOfLeadingZeros(_m); 644 | if (b1 == 32) { 645 | return u.numberOfLeadingZeros(_l) + 32; 646 | } else { 647 | return b1 + _BITS2 - (32 - _BITS); 648 | } 649 | } else { 650 | return b2 - (32 - _BITS2); 651 | } 652 | } 653 | 654 | /// Returns the number of trailing zeros in this [Int64] as an [int] 655 | /// between 0 and 64. 656 | @override 657 | int numberOfTrailingZeros() { 658 | int zeros = u.numberOfTrailingZeros(_l); 659 | if (zeros < 32) { 660 | return zeros; 661 | } 662 | 663 | zeros = u.numberOfTrailingZeros(_m); 664 | if (zeros < 32) { 665 | return _BITS + zeros; 666 | } 667 | 668 | zeros = u.numberOfTrailingZeros(_h); 669 | if (zeros < 32) { 670 | return _BITS01 + zeros; 671 | } 672 | // All zeros 673 | return 64; 674 | } 675 | 676 | @override 677 | Int64 toSigned(int width) { 678 | if (width < 1 || width > 64) throw RangeError.range(width, 1, 64); 679 | if (width > _BITS01) { 680 | return Int64._masked(_l, _m, _h.toSigned(width - _BITS01)); 681 | } else if (width > _BITS) { 682 | int m = _m.toSigned(width - _BITS); 683 | return m.isNegative 684 | ? Int64._masked(_l, m, _MASK2) 685 | : Int64._masked(_l, m, 0); // Masking for type inferrer. 686 | } else { 687 | int l = _l.toSigned(width); 688 | return l.isNegative 689 | ? Int64._masked(l, _MASK, _MASK2) 690 | : Int64._masked(l, 0, 0); // Masking for type inferrer. 691 | } 692 | } 693 | 694 | @override 695 | Int64 toUnsigned(int width) { 696 | if (width < 0 || width > 64) throw RangeError.range(width, 0, 64); 697 | if (width > _BITS01) { 698 | int h = _h.toUnsigned(width - _BITS01); 699 | return Int64._masked(_l, _m, h); 700 | } else if (width > _BITS) { 701 | int m = _m.toUnsigned(width - _BITS); 702 | return Int64._masked(_l, m, 0); 703 | } else { 704 | int l = _l.toUnsigned(width); 705 | return Int64._masked(l, 0, 0); 706 | } 707 | } 708 | 709 | @override 710 | List toBytes() { 711 | var result = List.filled(8, 0); 712 | result[0] = _l & 0xff; 713 | result[1] = (_l >> 8) & 0xff; 714 | result[2] = ((_m << 6) & 0xfc) | ((_l >> 16) & 0x3f); 715 | result[3] = (_m >> 2) & 0xff; 716 | result[4] = (_m >> 10) & 0xff; 717 | result[5] = ((_h << 4) & 0xf0) | ((_m >> 18) & 0xf); 718 | result[6] = (_h >> 4) & 0xff; 719 | result[7] = (_h >> 12) & 0xff; 720 | return result; 721 | } 722 | 723 | @override 724 | double toDouble() => toInt().toDouble(); 725 | 726 | @override 727 | int toInt() { 728 | int l = _l; 729 | int m = _m; 730 | int h = _h; 731 | // In the sum we add least significant to most significant so that in 732 | // JavaScript double arithmetic rounding occurs on only the last addition. 733 | if ((_h & _SIGN_BIT_MASK) != 0) { 734 | l = _MASK & ~_l; 735 | m = _MASK & ~_m; 736 | h = _MASK2 & ~_h; 737 | return -((1 + l) + (4194304 * m) + (17592186044416 * h)); 738 | } else { 739 | return l + (4194304 * m) + (17592186044416 * h); 740 | } 741 | } 742 | 743 | /// Returns an [Int32] containing the low 32 bits of this [Int64]. 744 | @override 745 | Int32 toInt32() => Int32(((_m & 0x3ff) << _BITS) | _l); 746 | 747 | /// Returns `this`. 748 | @override 749 | Int64 toInt64() => this; 750 | 751 | /// Returns the value of this [Int64] as a decimal [String]. 752 | @override 753 | String toString() => _toRadixString(10); 754 | 755 | @override 756 | String toHexString() { 757 | if (isZero) return '0'; 758 | Int64 x = this; 759 | String hexStr = ''; 760 | while (!x.isZero) { 761 | int digit = x._l & 0xf; 762 | hexStr = '${_hexDigit(digit)}$hexStr'; 763 | x = x.shiftRightUnsigned(4); 764 | } 765 | return hexStr; 766 | } 767 | 768 | /// Returns the digits of `this` when interpreted as an unsigned 64-bit value. 769 | @pragma('dart2js:noInline') 770 | String toStringUnsigned() => _toRadixStringUnsigned(10, _l, _m, _h, ''); 771 | 772 | @pragma('dart2js:noInline') 773 | String toRadixStringUnsigned(int radix) => 774 | _toRadixStringUnsigned(u.validateRadix(radix), _l, _m, _h, ''); 775 | 776 | @override 777 | String toRadixString(int radix) => _toRadixString(u.validateRadix(radix)); 778 | 779 | String _toRadixString(int radix) { 780 | int d0 = _l; 781 | int d1 = _m; 782 | int d2 = _h; 783 | 784 | String sign = ''; 785 | if ((d2 & _SIGN_BIT_MASK) != 0) { 786 | sign = '-'; 787 | 788 | // Negate in-place. 789 | d0 = 0 - d0; 790 | int borrow = (d0 >> _BITS) & 1; 791 | d0 &= _MASK; 792 | d1 = 0 - d1 - borrow; 793 | borrow = (d1 >> _BITS) & 1; 794 | d1 &= _MASK; 795 | d2 = 0 - d2 - borrow; 796 | d2 &= _MASK2; 797 | // d2, d1, d0 now are an unsigned 64 bit integer for MIN_VALUE and an 798 | // unsigned 63 bit integer for other values. 799 | } 800 | return _toRadixStringUnsigned(radix, d0, d1, d2, sign); 801 | } 802 | 803 | static String _toRadixStringUnsigned( 804 | int radix, int d0, int d1, int d2, String sign) { 805 | if (d0 == 0 && d1 == 0 && d2 == 0) return '0'; 806 | 807 | // Rearrange components into five components where all but the most 808 | // significant are 10 bits wide. 809 | // 810 | // d4, d3, d4, d1, d0: 24 + 10 + 10 + 10 + 10 bits 811 | // 812 | // The choice of 10 bits allows a remainder of 20 bits to be scaled by 10 813 | // bits and added during division while keeping all intermediate values 814 | // within 30 bits (unsigned small integer range for 32 bit implementations 815 | // of Dart VM and V8). 816 | // 817 | // 6 6 5 4 3 2 1 818 | // 3210987654321098765432109876543210987654321098765432109876543210 819 | // [--------d2--------][---------d1---------][---------d0---------] 820 | // --> 821 | // [----------d4----------][---d3---][---d2---][---d1---][---d0---] 822 | 823 | int d4 = (d2 << 4) | (d1 >> 18); 824 | int d3 = (d1 >> 8) & 0x3ff; 825 | d2 = ((d1 << 2) | (d0 >> 20)) & 0x3ff; 826 | d1 = (d0 >> 10) & 0x3ff; 827 | d0 = d0 & 0x3ff; 828 | 829 | int fatRadix = _fatRadixTable[radix]; 830 | 831 | // Generate chunks of digits. In radix 10, generate 6 digits per chunk. 832 | // 833 | // This loop generates at most 3 chunks, so we store the chunks in locals 834 | // rather than a list. We are trying to generate digits 20 bits at a time 835 | // until we have only 30 bits left. 20 + 20 + 30 > 64 would imply that we 836 | // need only two chunks, but radix values 17-19 and 33-36 generate only 15 837 | // or 16 bits per iteration, so sometimes the third chunk is needed. 838 | 839 | String chunk1 = '', chunk2 = '', chunk3 = ''; 840 | 841 | while (!(d4 == 0 && d3 == 0)) { 842 | int q = d4 ~/ fatRadix; 843 | int r = d4 - q * fatRadix; 844 | d4 = q; 845 | d3 += r << 10; 846 | 847 | q = d3 ~/ fatRadix; 848 | r = d3 - q * fatRadix; 849 | d3 = q; 850 | d2 += r << 10; 851 | 852 | q = d2 ~/ fatRadix; 853 | r = d2 - q * fatRadix; 854 | d2 = q; 855 | d1 += r << 10; 856 | 857 | q = d1 ~/ fatRadix; 858 | r = d1 - q * fatRadix; 859 | d1 = q; 860 | d0 += r << 10; 861 | 862 | q = d0 ~/ fatRadix; 863 | r = d0 - q * fatRadix; 864 | d0 = q; 865 | 866 | assert(chunk3 == ''); 867 | chunk3 = chunk2; 868 | chunk2 = chunk1; 869 | // Adding [fatRadix] Forces an extra digit which we discard to get a fixed 870 | // width. E.g. (1000000 + 123) -> "1000123" -> "000123". An alternative 871 | // would be to pad to the left with zeroes. 872 | chunk1 = (fatRadix + r).toRadixString(radix).substring(1); 873 | } 874 | int residue = (d2 << 20) + (d1 << 10) + d0; 875 | String leadingDigits = residue == 0 ? '' : residue.toRadixString(radix); 876 | return '$sign$leadingDigits$chunk1$chunk2$chunk3'; 877 | } 878 | 879 | // Table of 'fat' radix values. Each entry for index `i` is the largest power 880 | // of `i` whose remainder fits in 20 bits. 881 | static const _fatRadixTable = [ 882 | 0, 883 | 0, 884 | 2 * 885 | 2 * 886 | 2 * 887 | 2 * 888 | 2 * 889 | 2 * 890 | 2 * 891 | 2 * 892 | 2 * 893 | 2 * 894 | 2 * 895 | 2 * 896 | 2 * 897 | 2 * 898 | 2 * 899 | 2 * 900 | 2 * 901 | 2 * 902 | 2 * 903 | 2, 904 | 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3, 905 | 4 * 4 * 4 * 4 * 4 * 4 * 4 * 4 * 4 * 4, 906 | 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 907 | 6 * 6 * 6 * 6 * 6 * 6 * 6, 908 | 7 * 7 * 7 * 7 * 7 * 7 * 7, 909 | 8 * 8 * 8 * 8 * 8 * 8, 910 | 9 * 9 * 9 * 9 * 9 * 9, 911 | 10 * 10 * 10 * 10 * 10 * 10, 912 | 11 * 11 * 11 * 11 * 11, 913 | 12 * 12 * 12 * 12 * 12, 914 | 13 * 13 * 13 * 13 * 13, 915 | 14 * 14 * 14 * 14 * 14, 916 | 15 * 15 * 15 * 15 * 15, 917 | 16 * 16 * 16 * 16 * 16, 918 | 17 * 17 * 17 * 17, 919 | 18 * 18 * 18 * 18, 920 | 19 * 19 * 19 * 19, 921 | 20 * 20 * 20 * 20, 922 | 21 * 21 * 21 * 21, 923 | 22 * 22 * 22 * 22, 924 | 23 * 23 * 23 * 23, 925 | 24 * 24 * 24 * 24, 926 | 25 * 25 * 25 * 25, 927 | 26 * 26 * 26 * 26, 928 | 27 * 27 * 27 * 27, 929 | 28 * 28 * 28 * 28, 930 | 29 * 29 * 29 * 29, 931 | 30 * 30 * 30 * 30, 932 | 31 * 31 * 31 * 31, 933 | 32 * 32 * 32 * 32, 934 | 33 * 33 * 33, 935 | 34 * 34 * 34, 936 | 35 * 35 * 35, 937 | 36 * 36 * 36 938 | ]; 939 | 940 | String toDebugString() => 'Int64[_l=$_l, _m=$_m, _h=$_h]'; 941 | 942 | static Int64 _masked(int low, int medium, int high) => 943 | Int64._bits(_MASK & low, _MASK & medium, _MASK2 & high); 944 | 945 | static Int64 _sub(int a0, int a1, int a2, int b0, int b1, int b2) { 946 | int diff0 = a0 - b0; 947 | int diff1 = a1 - b1 - ((diff0 >> _BITS) & 1); 948 | int diff2 = a2 - b2 - ((diff1 >> _BITS) & 1); 949 | return _masked(diff0, diff1, diff2); 950 | } 951 | 952 | static Int64 _negate(int b0, int b1, int b2) => _sub(0, 0, 0, b0, b1, b2); 953 | 954 | String _hexDigit(int digit) => '0123456789ABCDEF'[digit]; 955 | 956 | // Work around dart2js bugs with negative arguments to '>>' operator. 957 | static int _shiftRight(int x, int n) { 958 | if (x >= 0) { 959 | return x >> n; 960 | } else { 961 | int shifted = x >> n; 962 | if (shifted >= 0x80000000) { 963 | shifted -= 4294967296; 964 | } 965 | return shifted; 966 | } 967 | } 968 | 969 | // Implementation of '~/', '%' and 'remainder'. 970 | 971 | static Int64 _divide(Int64 a, Object other, int what) { 972 | Int64 b = _promote(other); 973 | if (b.isZero) { 974 | throw UnsupportedError('Division by zero'); 975 | } 976 | if (a.isZero) return ZERO; 977 | 978 | bool aNeg = a.isNegative; 979 | bool bNeg = b.isNegative; 980 | a = a.abs(); 981 | b = b.abs(); 982 | 983 | int a0 = a._l; 984 | int a1 = a._m; 985 | int a2 = a._h; 986 | 987 | int b0 = b._l; 988 | int b1 = b._m; 989 | int b2 = b._h; 990 | return _divideHelper(a0, a1, a2, aNeg, b0, b1, b2, bNeg, what); 991 | } 992 | 993 | static const _RETURN_DIV = 1; 994 | static const _RETURN_REM = 2; 995 | static const _RETURN_MOD = 3; 996 | 997 | static Int64 _divideHelper( 998 | // up to 64 bits unsigned in a2/a1/a0 and b2/b1/b0 999 | int a0, 1000 | int a1, 1001 | int a2, 1002 | bool aNeg, // input A. 1003 | int b0, 1004 | int b1, 1005 | int b2, 1006 | bool bNeg, // input B. 1007 | int what) { 1008 | int q0 = 0, q1 = 0, q2 = 0; // result Q. 1009 | int r0 = 0, r1 = 0, r2 = 0; // result R. 1010 | 1011 | if (b2 == 0 && b1 == 0 && b0 < (1 << (30 - _BITS))) { 1012 | // Small divisor can be handled by single-digit division within Smi range. 1013 | // 1014 | // Handling small divisors here helps the estimate version below by 1015 | // handling cases where the estimate is off by more than a small amount. 1016 | 1017 | q2 = a2 ~/ b0; 1018 | int carry = a2 - q2 * b0; 1019 | int d1 = a1 + (carry << _BITS); 1020 | q1 = d1 ~/ b0; 1021 | carry = d1 - q1 * b0; 1022 | int d0 = a0 + (carry << _BITS); 1023 | q0 = d0 ~/ b0; 1024 | r0 = d0 - q0 * b0; 1025 | } else { 1026 | // Approximate Q = A ~/ B and R = A - Q * B using doubles. 1027 | 1028 | // The floating point approximation is very close to the correct value 1029 | // when floor(A/B) fits in fewer that 53 bits. 1030 | 1031 | // We use double arithmetic for intermediate values. Double arithmetic on 1032 | // non-negative values is exact under the following conditions: 1033 | // 1034 | // - The values are integer values that fit in 53 bits. 1035 | // - Dividing by powers of two (adjusts exponent only). 1036 | // - Floor (zeroes bits with fractional weight). 1037 | 1038 | const double K2 = 17592186044416.0; // 2^44 1039 | const double K1 = 4194304.0; // 2^22 1040 | 1041 | // Approximate double values for [a] and [b]. 1042 | double ad = a0 + K1 * a1 + K2 * a2; 1043 | double bd = b0 + K1 * b1 + K2 * b2; 1044 | // Approximate quotient. 1045 | double qd = (ad / bd).floorToDouble(); 1046 | 1047 | // Extract components of [qd] using double arithmetic. 1048 | double q2d = (qd / K2).floorToDouble(); 1049 | qd = qd - K2 * q2d; 1050 | double q1d = (qd / K1).floorToDouble(); 1051 | double q0d = qd - K1 * q1d; 1052 | q2 = q2d.toInt(); 1053 | q1 = q1d.toInt(); 1054 | q0 = q0d.toInt(); 1055 | 1056 | assert(q0 + K1 * q1 + K2 * q2 == (ad / bd).floorToDouble()); 1057 | assert(q2 == 0 || b2 == 0); // Q and B can't both be big since Q*B <= A. 1058 | 1059 | // P = Q * B, using doubles to hold intermediates. 1060 | // We don't need all partial sums since Q*B <= A. 1061 | double p0d = q0d * b0; 1062 | double p0carry = (p0d / K1).floorToDouble(); 1063 | p0d = p0d - p0carry * K1; 1064 | double p1d = q1d * b0 + q0d * b1 + p0carry; 1065 | double p1carry = (p1d / K1).floorToDouble(); 1066 | p1d = p1d - p1carry * K1; 1067 | double p2d = q2d * b0 + q1d * b1 + q0d * b2 + p1carry; 1068 | assert(p2d <= _MASK2); // No partial sum overflow. 1069 | 1070 | // R = A - P 1071 | int diff0 = a0 - p0d.toInt(); 1072 | int diff1 = a1 - p1d.toInt() - ((diff0 >> _BITS) & 1); 1073 | int diff2 = a2 - p2d.toInt() - ((diff1 >> _BITS) & 1); 1074 | r0 = _MASK & diff0; 1075 | r1 = _MASK & diff1; 1076 | r2 = _MASK2 & diff2; 1077 | 1078 | // while (R < 0 || R >= B) 1079 | // adjust R towards [0, B) 1080 | while (r2 >= _SIGN_BIT_MASK || 1081 | r2 > b2 || 1082 | (r2 == b2 && (r1 > b1 || (r1 == b1 && r0 >= b0)))) { 1083 | // Direction multiplier for adjustment. 1084 | int m = (r2 & _SIGN_BIT_MASK) == 0 ? 1 : -1; 1085 | // R = R - B or R = R + B 1086 | int d0 = r0 - m * b0; 1087 | int d1 = r1 - m * (b1 + ((d0 >> _BITS) & 1)); 1088 | int d2 = r2 - m * (b2 + ((d1 >> _BITS) & 1)); 1089 | r0 = _MASK & d0; 1090 | r1 = _MASK & d1; 1091 | r2 = _MASK2 & d2; 1092 | 1093 | // Q = Q + 1 or Q = Q - 1 1094 | d0 = q0 + m; 1095 | d1 = q1 + m * ((d0 >> _BITS) & 1); 1096 | d2 = q2 + m * ((d1 >> _BITS) & 1); 1097 | q0 = _MASK & d0; 1098 | q1 = _MASK & d1; 1099 | q2 = _MASK2 & d2; 1100 | } 1101 | } 1102 | 1103 | // 0 <= R < B 1104 | assert(Int64.ZERO <= Int64._bits(r0, r1, r2)); 1105 | assert(r2 < b2 || // Handles case where B = -(MIN_VALUE) 1106 | Int64._bits(r0, r1, r2) < Int64._bits(b0, b1, b2)); 1107 | 1108 | assert(what == _RETURN_DIV || what == _RETURN_MOD || what == _RETURN_REM); 1109 | if (what == _RETURN_DIV) { 1110 | if (aNeg != bNeg) return _negate(q0, q1, q2); 1111 | return Int64._masked(q0, q1, q2); // Masking for type inferrer. 1112 | } 1113 | 1114 | if (!aNeg) { 1115 | return Int64._masked(r0, r1, r2); // Masking for type inferrer. 1116 | } 1117 | 1118 | if (what == _RETURN_MOD) { 1119 | if (r0 == 0 && r1 == 0 && r2 == 0) { 1120 | return ZERO; 1121 | } else { 1122 | return _sub(b0, b1, b2, r0, r1, r2); 1123 | } 1124 | } else { 1125 | return _negate(r0, r1, r2); 1126 | } 1127 | } 1128 | } 1129 | -------------------------------------------------------------------------------- /lib/src/intx.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, 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 | import 'int32.dart'; 6 | import 'int64.dart'; 7 | 8 | /// A fixed-precision integer. 9 | abstract class IntX implements Comparable { 10 | /// Addition operator. 11 | IntX operator +(Object other); 12 | 13 | /// Subtraction operator. 14 | IntX operator -(Object other); 15 | 16 | /// Negate operator. 17 | /// 18 | /// Note that `-MIN_VALUE` is equal to `MIN_VALUE` due to overflow. 19 | IntX operator -(); 20 | 21 | /// Multiplication operator. 22 | IntX operator *(Object other); 23 | 24 | /// Euclidean modulo operator. 25 | /// 26 | /// Returns the remainder of the euclidean division. The euclidean division 27 | /// of two integers `a` and `b` yields two integers `q` and `r` such that 28 | /// `a == b * q + r` and `0 <= r < a.abs()`. 29 | IntX operator %(Object other); 30 | 31 | /// Truncating division operator. 32 | IntX operator ~/(Object other); 33 | 34 | /// Returns the remainder of the truncating division of this integer by 35 | /// [other]. 36 | IntX remainder(Object other); 37 | 38 | /// Bitwise and operator. 39 | IntX operator &(Object other); 40 | 41 | /// Bitwise or operator. 42 | IntX operator |(Object other); 43 | 44 | /// Bitwise xor operator. 45 | IntX operator ^(Object other); 46 | 47 | /// Bitwise negate operator. 48 | IntX operator ~(); 49 | 50 | /// Left bit-shift operator. 51 | /// 52 | /// Returns the result of shifting the bits of this integer by [shiftAmount] 53 | /// bits to the left. Low-order bits are filled with zeros. 54 | IntX operator <<(int shiftAmount); 55 | 56 | /// Right bit-shift operator. 57 | /// 58 | /// Returns the result of shifting the bits of this integer by [shiftAmount] 59 | /// bits to the right. High-order bits are filled with zero in the case where 60 | /// this integer is positive, or one in the case where it is negative. 61 | IntX operator >>(int shiftAmount); 62 | 63 | /// Unsigned right-shift operator. 64 | /// 65 | /// Returns the result of shifting the bits of this integer by [shiftAmount] 66 | /// bits to the right. High-order bits are filled with zeros. 67 | IntX shiftRightUnsigned(int shiftAmount); 68 | 69 | @override 70 | int compareTo(Object other); 71 | 72 | /// Returns `true` if and only if [other] is an int or IntX equal in 73 | /// value to this integer. 74 | @override 75 | bool operator ==(Object other); 76 | 77 | /// Relational less than operator. 78 | bool operator <(Object other); 79 | 80 | /// Relational less than or equal to operator. 81 | bool operator <=(Object other); 82 | 83 | /// Relational greater than operator. 84 | bool operator >(Object other); 85 | 86 | /// Relational greater than or equal to operator. 87 | bool operator >=(Object other); 88 | 89 | /// Returns `true` if and only if this integer is even. 90 | bool get isEven; 91 | 92 | /// Returns `true` if and only if this integer is the maximum signed value 93 | /// that can be represented within its bit size. 94 | bool get isMaxValue; 95 | 96 | /// Returns `true` if and only if this integer is the minimum signed value 97 | /// that can be represented within its bit size. 98 | bool get isMinValue; 99 | 100 | /// Returns `true` if and only if this integer is less than zero. 101 | bool get isNegative; 102 | 103 | /// Returns `true` if and only if this integer is odd. 104 | bool get isOdd; 105 | 106 | /// Returns `true` if and only if this integer is zero. 107 | bool get isZero; 108 | 109 | @override 110 | int get hashCode; 111 | 112 | /// Returns the absolute value of this integer. 113 | IntX abs(); 114 | 115 | /// Clamps this integer to be in the range [lowerLimit] - [upperLimit]. 116 | IntX clamp(Object lowerLimit, Object upperLimit); 117 | 118 | /// Returns the minimum number of bits required to store this integer. 119 | /// 120 | /// The number of bits excludes the sign bit, which gives the natural length 121 | /// for non-negative (unsigned) values. Negative values are complemented to 122 | /// return the bit position of the first bit that differs from the sign bit. 123 | /// 124 | /// To find the the number of bits needed to store the value as a signed 125 | /// value, add one, i.e. use `x.bitLength + 1`. 126 | int get bitLength; 127 | 128 | /// Returns the number of high-order zeros in this integer's bit 129 | /// representation. 130 | int numberOfLeadingZeros(); 131 | 132 | /// Returns the number of low-order zeros in this integer's bit 133 | /// representation. 134 | int numberOfTrailingZeros(); 135 | 136 | /// Returns the least significant [width] bits of this integer, extending the 137 | /// highest retained bit to the sign. This is the same as truncating the 138 | /// value to fit in [width] bits using an signed 2-s complement 139 | /// representation. The returned value has the same bit value in all positions 140 | /// higher than [width]. 141 | /// 142 | /// If the input value fits in [width] bits without truncation, the result is 143 | /// the same as the input. The minimum width needed to avoid truncation of 144 | /// `x` is `x.bitLength + 1`, i.e. 145 | /// 146 | /// x == x.toSigned(x.bitLength + 1); 147 | IntX toSigned(int width); 148 | 149 | /// Returns the least significant [width] bits of this integer as a 150 | /// non-negative number (i.e. unsigned representation). The returned value has 151 | /// zeros in all bit positions higher than [width]. 152 | /// 153 | /// If the input fits in [width] bits without truncation, the result is the 154 | /// same as the input. The minimum width needed to avoid truncation of `x` is 155 | /// given by `x.bitLength`, i.e. 156 | /// 157 | /// x == x.toUnsigned(x.bitLength); 158 | IntX toUnsigned(int width); 159 | 160 | /// Returns a byte-sequence representation of this integer. 161 | /// 162 | /// Returns a list of int, starting with the least significant byte. 163 | List toBytes(); 164 | 165 | /// Returns the double representation of this integer. 166 | /// 167 | /// On some platforms, inputs with large absolute values (i.e., > 2^52) may 168 | /// lose some of their low-order bits. 169 | double toDouble(); 170 | 171 | /// Returns the int representation of this integer. 172 | /// 173 | /// On some platforms, inputs with large absolute values (i.e., > 2^52) may 174 | /// lose some of their low-order bits. 175 | int toInt(); 176 | 177 | /// Returns an Int32 representation of this integer. 178 | /// 179 | /// Narrower values are sign-extended and wider values have their high bits 180 | /// truncated. 181 | Int32 toInt32(); 182 | 183 | /// Returns an Int64 representation of this integer. 184 | Int64 toInt64(); 185 | 186 | /// Returns a string representing the value of this integer in decimal 187 | /// notation; example: `'13'`. 188 | @override 189 | String toString(); 190 | 191 | /// Returns a string representing the value of this integer in hexadecimal 192 | /// notation. 193 | /// 194 | /// Example: `Int64(0xf01d).toHexString()` returns `'F01D'`. 195 | /// 196 | /// The string may interprets the number as *unsigned*, and has no leading 197 | /// minus, even if the value [isNegative]. 198 | /// 199 | /// Example: `Int64(-1).toHexString()` returns `'FFFFFFFFFFFFFFFF'`. 200 | String toHexString(); 201 | 202 | /// Returns a string representing the value of this integer in the given 203 | /// radix. 204 | /// 205 | /// [radix] must be an integer in the range 2 .. 16, inclusive. 206 | String toRadixString(int radix); 207 | } 208 | -------------------------------------------------------------------------------- /lib/src/utilities.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, 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 | // Shared functionality used by multiple classes and their implementations. 6 | 7 | int validateRadix(int radix) => 8 | RangeError.checkValueInInterval(radix, 2, 36, 'radix'); 9 | 10 | /// Converts radix digits into their numeric values. 11 | /// 12 | /// Converts the characters `0`-`9` into the values 0 through 9, 13 | /// and the letters `a`-`z` or `A`-`Z` into values 10 through 35, 14 | /// and return that value. 15 | /// Any other character returns a value above 35, which means it's 16 | /// not a valid digit in any radix in the range 2 through 36. 17 | int decodeDigit(int c) { 18 | // Hex digit char codes 19 | const c0 = 48; // '0'.codeUnitAt(0) 20 | const ca = 97; // 'a'.codeUnitAt(0) 21 | 22 | var digit = c ^ c0; 23 | if (digit < 10) return digit; 24 | var letter = (c | 0x20) - ca; 25 | if (letter >= 0) { 26 | // Returns values above 36 for invalid digits. 27 | // The value is checked against the actual radix where the return 28 | // value is used, so this is safe. 29 | return letter + 10; 30 | } else { 31 | return 255; // Never a valid radix. 32 | } 33 | } 34 | 35 | // Assumes i is <= 32-bit 36 | int numberOfLeadingZeros(int i) { 37 | i |= i >> 1; 38 | i |= i >> 2; 39 | i |= i >> 4; 40 | i |= i >> 8; 41 | i |= i >> 16; 42 | return bitCount(~i); 43 | } 44 | 45 | int numberOfTrailingZeros(int i) => bitCount((i & -i) - 1); 46 | 47 | // Assumes i is <= 32-bit. 48 | int bitCount(int i) { 49 | // See "Hacker's Delight", section 5-1, "Counting 1-Bits". 50 | 51 | // The basic strategy is to use "divide and conquer" to 52 | // add pairs (then quads, etc.) of bits together to obtain 53 | // sub-counts. 54 | // 55 | // A straightforward approach would look like: 56 | // 57 | // i = (i & 0x55555555) + ((i >> 1) & 0x55555555); 58 | // i = (i & 0x33333333) + ((i >> 2) & 0x33333333); 59 | // i = (i & 0x0F0F0F0F) + ((i >> 4) & 0x0F0F0F0F); 60 | // i = (i & 0x00FF00FF) + ((i >> 8) & 0x00FF00FF); 61 | // i = (i & 0x0000FFFF) + ((i >> 16) & 0x0000FFFF); 62 | // 63 | // The code below removes unnecessary &'s and uses a 64 | // trick to remove one instruction in the first line. 65 | 66 | i -= (i >> 1) & 0x55555555; 67 | i = (i & 0x33333333) + ((i >> 2) & 0x33333333); 68 | i = (i + (i >> 4)) & 0x0F0F0F0F; 69 | i += i >> 8; 70 | i += i >> 16; 71 | return i & 0x0000003F; 72 | } 73 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: fixnum 2 | version: 1.1.1-wip 3 | description: >- 4 | Library for 32- and 64-bit signed fixed-width integers with consistent 5 | behavior between native and JS runtimes. 6 | repository: https://github.com/dart-lang/fixnum 7 | 8 | environment: 9 | sdk: ^3.1.0 10 | 11 | dev_dependencies: 12 | dart_flutter_team_lints: ^3.0.0 13 | test: ^1.16.6 14 | -------------------------------------------------------------------------------- /test/all_tests.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, 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 | import 'int32_test.dart' as int32_test; 6 | import 'int64_test.dart' as int64_test; 7 | 8 | void main() { 9 | int32_test.main(); 10 | int64_test.main(); 11 | } 12 | -------------------------------------------------------------------------------- /test/int32_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, 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 | import 'package:fixnum/fixnum.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | void main() { 9 | group('isX tests', () { 10 | test('isEven', () { 11 | expect((-Int32.ONE).isEven, false); 12 | expect(Int32.ZERO.isEven, true); 13 | expect(Int32.ONE.isEven, false); 14 | expect(Int32.TWO.isEven, true); 15 | }); 16 | test('isMaxValue', () { 17 | expect(Int32.MIN_VALUE.isMaxValue, false); 18 | expect(Int32.ZERO.isMaxValue, false); 19 | expect(Int32.MAX_VALUE.isMaxValue, true); 20 | }); 21 | test('isMinValue', () { 22 | expect(Int32.MIN_VALUE.isMinValue, true); 23 | expect(Int32.ZERO.isMinValue, false); 24 | expect(Int32.MAX_VALUE.isMinValue, false); 25 | }); 26 | test('isNegative', () { 27 | expect(Int32.MIN_VALUE.isNegative, true); 28 | expect(Int32.ZERO.isNegative, false); 29 | expect(Int32.ONE.isNegative, false); 30 | }); 31 | test('isOdd', () { 32 | expect((-Int32.ONE).isOdd, true); 33 | expect(Int32.ZERO.isOdd, false); 34 | expect(Int32.ONE.isOdd, true); 35 | expect(Int32.TWO.isOdd, false); 36 | }); 37 | test('isZero', () { 38 | expect(Int32.MIN_VALUE.isZero, false); 39 | expect(Int32.ZERO.isZero, true); 40 | expect(Int32.MAX_VALUE.isZero, false); 41 | }); 42 | test('bitLength', () { 43 | expect(Int32(-2).bitLength, 1); 44 | expect((-Int32.ONE).bitLength, 0); 45 | expect(Int32.ZERO.bitLength, 0); 46 | expect(Int32.ONE.bitLength, 1); 47 | expect(Int32(2).bitLength, 2); 48 | expect(Int32.MAX_VALUE.bitLength, 31); 49 | expect(Int32.MIN_VALUE.bitLength, 31); 50 | }); 51 | }); 52 | 53 | group('arithmetic operators', () { 54 | var n1 = Int32(1234); 55 | var n2 = Int32(9876); 56 | var n3 = Int32(-1234); 57 | var n4 = Int32(-9876); 58 | 59 | test('+', () { 60 | expect(n1 + n2, Int32(11110)); 61 | expect(n3 + n2, Int32(8642)); 62 | expect(n3 + n4, Int32(-11110)); 63 | expect(n3 + Int64(1), Int64(-1233)); 64 | expect(Int32.MAX_VALUE + 1, Int32.MIN_VALUE); 65 | }); 66 | 67 | test('-', () { 68 | expect(n1 - n2, Int32(-8642)); 69 | expect(n3 - n2, Int32(-11110)); 70 | expect(n3 - n4, Int32(8642)); 71 | expect(n3 - Int64(1), Int64(-1235)); 72 | expect(Int32.MIN_VALUE - 1, Int32.MAX_VALUE); 73 | }); 74 | 75 | test('unary -', () { 76 | expect(-n1, Int32(-1234)); 77 | expect(-Int32.ZERO, Int32.ZERO); 78 | }); 79 | 80 | test('*', () { 81 | expect(n1 * n2, Int32(12186984)); 82 | expect(n2 * n3, Int32(-12186984)); 83 | expect(n3 * n3, Int32(1522756)); 84 | expect(n3 * n2, Int32(-12186984)); 85 | expect(Int32(0x12345678) * Int32(0x22222222), Int32(-899716112)); 86 | expect(Int32(123456789) * Int32(987654321), Int32(-67153019)); 87 | expect(Int32(0x12345678) * Int64(0x22222222), 88 | Int64.fromInts(0x026D60DC, 0xCA5F6BF0)); 89 | expect(Int32(123456789) * 987654321, Int32(-67153019)); 90 | }); 91 | 92 | test('~/', () { 93 | expect(Int32(829893893) ~/ Int32(1919), Int32(432461)); 94 | expect(Int32(0x12345678) ~/ Int32(0x22), Int32(0x12345678 ~/ 0x22)); 95 | expect(Int32(829893893) ~/ Int64(1919), Int32(432461)); 96 | expect(Int32(0x12345678) ~/ Int64(0x22), Int32(0x12345678 ~/ 0x22)); 97 | expect(Int32(829893893) ~/ 1919, Int32(432461)); 98 | expect(() => Int32(17) ~/ Int32.ZERO, throwsA(isUnsupportedError)); 99 | }); 100 | 101 | test('%', () { 102 | expect(Int32(0x12345678) % Int32(0x22), Int32(0x12345678 % 0x22)); 103 | expect(Int32(0x12345678) % Int64(0x22), Int32(0x12345678 % 0x22)); 104 | }); 105 | 106 | test('remainder', () { 107 | expect(Int32(0x12345678).remainder(Int32(0x22)), 108 | Int32(0x12345678.remainder(0x22))); 109 | expect(Int32(0x12345678).remainder(Int32(-0x22)), 110 | Int32(0x12345678.remainder(-0x22))); 111 | expect(Int32(-0x12345678).remainder(Int32(-0x22)), 112 | Int32(-0x12345678.remainder(-0x22))); 113 | expect(Int32(-0x12345678).remainder(Int32(0x22)), 114 | Int32(-0x12345678.remainder(0x22))); 115 | expect(Int32(0x12345678).remainder(Int64(0x22)), 116 | Int32(0x12345678.remainder(0x22))); 117 | }); 118 | 119 | test('abs', () { 120 | // NOTE: Int32.MIN_VALUE.abs() is undefined 121 | expect((Int32.MIN_VALUE + 1).abs(), Int32.MAX_VALUE); 122 | expect(Int32(-1).abs(), Int32(1)); 123 | expect(Int32(0).abs(), Int32(0)); 124 | expect(Int32(1).abs(), Int32(1)); 125 | expect(Int32.MAX_VALUE.abs(), Int32.MAX_VALUE); 126 | }); 127 | 128 | test('clamp', () { 129 | var val = Int32(17); 130 | expect(val.clamp(20, 30), Int32(20)); 131 | expect(val.clamp(10, 20), Int32(17)); 132 | expect(val.clamp(10, 15), Int32(15)); 133 | 134 | expect(val.clamp(Int32(20), Int32(30)), Int32(20)); 135 | expect(val.clamp(Int32(10), Int32(20)), Int32(17)); 136 | expect(val.clamp(Int32(10), Int32(15)), Int32(15)); 137 | 138 | expect(val.clamp(Int64(20), Int64(30)), Int32(20)); 139 | expect(val.clamp(Int64(10), Int64(20)), Int32(17)); 140 | expect(val.clamp(Int64(10), Int64(15)), Int32(15)); 141 | expect(val.clamp(Int64.MIN_VALUE, Int64(30)), Int32(17)); 142 | expect(val.clamp(Int64(10), Int64.MAX_VALUE), Int32(17)); 143 | 144 | expect(() => val.clamp(30.5, 40.5), throwsArgumentError); 145 | expect(() => val.clamp(5.5, 10.5), throwsArgumentError); 146 | expect(() => val.clamp('a', 1), throwsArgumentError); 147 | expect(() => val.clamp(1, 'b'), throwsArgumentError); 148 | expect(() => val.clamp('a', 1), throwsArgumentError); 149 | }); 150 | }); 151 | 152 | group('leading/trailing zeros', () { 153 | test('numberOfLeadingZeros', () { 154 | expect(Int32(0).numberOfLeadingZeros(), 32); 155 | expect(Int32(1).numberOfLeadingZeros(), 31); 156 | expect(Int32(0xffff).numberOfLeadingZeros(), 16); 157 | expect(Int32(-1).numberOfLeadingZeros(), 0); 158 | }); 159 | test('numberOfTrailingZeros', () { 160 | expect(Int32(0).numberOfTrailingZeros(), 32); 161 | expect(Int32(0x80000000).numberOfTrailingZeros(), 31); 162 | expect(Int32(1).numberOfTrailingZeros(), 0); 163 | expect(Int32(0x10000).numberOfTrailingZeros(), 16); 164 | }); 165 | }); 166 | 167 | group('comparison operators', () { 168 | test('compareTo', () { 169 | expect(Int32(0).compareTo(-1), 1); 170 | expect(Int32(0).compareTo(0), 0); 171 | expect(Int32(0).compareTo(1), -1); 172 | expect(Int32(0).compareTo(Int32(-1)), 1); 173 | expect(Int32(0).compareTo(Int32(0)), 0); 174 | expect(Int32(0).compareTo(Int32(1)), -1); 175 | expect(Int32(0).compareTo(Int64(-1)), 1); 176 | expect(Int32(0).compareTo(Int64(0)), 0); 177 | expect(Int32(0).compareTo(Int64(1)), -1); 178 | }); 179 | 180 | test('<', () { 181 | expect(Int32(17) < Int32(18), true); 182 | expect(Int32(17) < Int32(17), false); 183 | expect(Int32(17) < Int32(16), false); 184 | expect(Int32(17) < Int64(18), true); 185 | expect(Int32(17) < Int64(17), false); 186 | expect(Int32(17) < Int64(16), false); 187 | expect(Int32.MIN_VALUE < Int32.MAX_VALUE, true); 188 | expect(Int32.MAX_VALUE < Int32.MIN_VALUE, false); 189 | }); 190 | 191 | test('<=', () { 192 | expect(Int32(17) <= Int32(18), true); 193 | expect(Int32(17) <= Int32(17), true); 194 | expect(Int32(17) <= Int32(16), false); 195 | expect(Int32(17) <= Int64(18), true); 196 | expect(Int32(17) <= Int64(17), true); 197 | expect(Int32(17) <= Int64(16), false); 198 | expect(Int32.MIN_VALUE <= Int32.MAX_VALUE, true); 199 | expect(Int32.MAX_VALUE <= Int32.MIN_VALUE, false); 200 | }); 201 | 202 | test('==', () { 203 | expect(Int32(17), isNot(equals(Int32(18)))); 204 | expect(Int32(17), equals(Int32(17))); 205 | expect(Int32(17), isNot(equals(Int32(16)))); 206 | expect(Int32(17), isNot(equals(Int64(18)))); 207 | expect(Int32(17), equals(Int64(17))); 208 | expect(Int32(17), isNot(equals(Int64(16)))); 209 | expect(Int32.MIN_VALUE, isNot(equals(Int32.MAX_VALUE))); 210 | expect(Int32(17), isNot(equals(18))); 211 | expect(Int32(17) == 17, isTrue); // ignore: unrelated_type_equality_checks 212 | expect(Int32(17), isNot(equals(16))); 213 | expect(Int32(17), isNot(equals(Object()))); 214 | expect(Int32(17), isNot(equals(null))); 215 | }); 216 | 217 | test('>=', () { 218 | expect(Int32(17) >= Int32(18), false); 219 | expect(Int32(17) >= Int32(17), true); 220 | expect(Int32(17) >= Int32(16), true); 221 | expect(Int32(17) >= Int64(18), false); 222 | expect(Int32(17) >= Int64(17), true); 223 | expect(Int32(17) >= Int64(16), true); 224 | expect(Int32.MIN_VALUE >= Int32.MAX_VALUE, false); 225 | expect(Int32.MAX_VALUE >= Int32.MIN_VALUE, true); 226 | }); 227 | 228 | test('>', () { 229 | expect(Int32(17) > Int32(18), false); 230 | expect(Int32(17) > Int32(17), false); 231 | expect(Int32(17) > Int32(16), true); 232 | expect(Int32(17) > Int64(18), false); 233 | expect(Int32(17) > Int64(17), false); 234 | expect(Int32(17) > Int64(16), true); 235 | expect(Int32.MIN_VALUE > Int32.MAX_VALUE, false); 236 | expect(Int32.MAX_VALUE > Int32.MIN_VALUE, true); 237 | }); 238 | }); 239 | 240 | group('bitwise operators', () { 241 | test('&', () { 242 | expect(Int32(0x12345678) & Int32(0x22222222), 243 | Int32(0x12345678 & 0x22222222)); 244 | expect(Int32(0x12345678) & Int64(0x22222222), 245 | Int64(0x12345678 & 0x22222222)); 246 | }); 247 | 248 | test('|', () { 249 | expect(Int32(0x12345678) | Int32(0x22222222), 250 | Int32(0x12345678 | 0x22222222)); 251 | expect(Int32(0x12345678) | Int64(0x22222222), 252 | Int64(0x12345678 | 0x22222222)); 253 | }); 254 | 255 | test('^', () { 256 | expect(Int32(0x12345678) ^ Int32(0x22222222), 257 | Int32(0x12345678 ^ 0x22222222)); 258 | expect(Int32(0x12345678) ^ Int64(0x22222222), 259 | Int64(0x12345678 ^ 0x22222222)); 260 | }); 261 | 262 | test('~', () { 263 | expect(~Int32(0x12345678), Int32(~0x12345678)); 264 | expect(-Int32(0x12345678), Int64(-0x12345678)); 265 | }); 266 | }); 267 | 268 | group('bitshift operators', () { 269 | test('<<', () { 270 | expect(Int32(0x12345678) << 7, Int32(0x12345678 << 7)); 271 | expect(Int32(0x12345678) << 32, Int32.ZERO); 272 | expect(Int32(0x12345678) << 33, Int32.ZERO); 273 | expect(() => Int32(17) << -1, throwsArgumentError); 274 | }); 275 | 276 | test('>>', () { 277 | expect(Int32(0x12345678) >> 7, Int32(0x12345678 >> 7)); 278 | expect(Int32(0x12345678) >> 32, Int32.ZERO); 279 | expect(Int32(0x12345678) >> 33, Int32.ZERO); 280 | expect(Int32(-42) >> 32, Int32(-1)); 281 | expect(Int32(-42) >> 33, Int32(-1)); 282 | expect(() => Int32(17) >> -1, throwsArgumentError); 283 | }); 284 | 285 | test('shiftRightUnsigned', () { 286 | expect(Int32(0x12345678).shiftRightUnsigned(7), Int32(0x12345678 >> 7)); 287 | expect(Int32(0x12345678).shiftRightUnsigned(32), Int32.ZERO); 288 | expect(Int32(0x12345678).shiftRightUnsigned(33), Int32.ZERO); 289 | expect(Int32(-42).shiftRightUnsigned(32), Int32.ZERO); 290 | expect(Int32(-42).shiftRightUnsigned(33), Int32.ZERO); 291 | expect(() => Int32(17).shiftRightUnsigned(-1), throwsArgumentError); 292 | }); 293 | }); 294 | 295 | group('conversions', () { 296 | test('toSigned', () { 297 | expect(Int32.ONE.toSigned(2), Int32.ONE); 298 | expect(Int32.ONE.toSigned(1), -Int32.ONE); 299 | expect(Int32.MAX_VALUE.toSigned(32), Int32.MAX_VALUE); 300 | expect(Int32.MIN_VALUE.toSigned(32), Int32.MIN_VALUE); 301 | expect(Int32.MAX_VALUE.toSigned(31), -Int32.ONE); 302 | expect(Int32.MIN_VALUE.toSigned(31), Int32.ZERO); 303 | expect(() => Int32.ONE.toSigned(0), throwsRangeError); 304 | expect(() => Int32.ONE.toSigned(33), throwsRangeError); 305 | }); 306 | test('toUnsigned', () { 307 | expect(Int32.ONE.toUnsigned(1), Int32.ONE); 308 | expect(Int32.ONE.toUnsigned(0), Int32.ZERO); 309 | expect(Int32.MAX_VALUE.toUnsigned(32), Int32.MAX_VALUE); 310 | expect(Int32.MIN_VALUE.toUnsigned(32), Int32.MIN_VALUE); 311 | expect(Int32.MAX_VALUE.toUnsigned(31), Int32.MAX_VALUE); 312 | expect(Int32.MIN_VALUE.toUnsigned(31), Int32.ZERO); 313 | expect(() => Int32.ONE.toUnsigned(-1), throwsRangeError); 314 | expect(() => Int32.ONE.toUnsigned(33), throwsRangeError); 315 | }); 316 | test('toDouble', () { 317 | expect(Int32(17).toDouble(), same(17.0)); 318 | expect(Int32(-17).toDouble(), same(-17.0)); 319 | }); 320 | test('toInt', () { 321 | expect(Int32(17).toInt(), 17); 322 | expect(Int32(-17).toInt(), -17); 323 | }); 324 | test('toInt32', () { 325 | expect(Int32(17).toInt32(), Int32(17)); 326 | expect(Int32(-17).toInt32(), Int32(-17)); 327 | }); 328 | test('toInt64', () { 329 | expect(Int32(17).toInt64(), Int64(17)); 330 | expect(Int32(-17).toInt64(), Int64(-17)); 331 | }); 332 | test('toBytes', () { 333 | expect(Int32(0).toBytes(), [0, 0, 0, 0]); 334 | expect(Int32(0x01020304).toBytes(), [4, 3, 2, 1]); 335 | expect(Int32(0x04030201).toBytes(), [1, 2, 3, 4]); 336 | expect(Int32(-1).toBytes(), [0xff, 0xff, 0xff, 0xff]); 337 | }); 338 | }); 339 | 340 | group('parse', () { 341 | test('base 10', () { 342 | void checkInt(int x) { 343 | expect(Int32.parseRadix('$x', 10), Int32(x)); 344 | } 345 | 346 | checkInt(0); 347 | checkInt(1); 348 | checkInt(1000); 349 | checkInt(12345678); 350 | checkInt(2147483647); 351 | checkInt(2147483648); 352 | checkInt(4294967295); 353 | checkInt(4294967296); 354 | expect(() => Int32.parseRadix('xyzzy', -1), throwsArgumentError); 355 | expect(() => Int32.parseRadix('plugh', 10), throwsFormatException); 356 | }); 357 | 358 | test('parseRadix', () { 359 | void check(String s, int r, String x) { 360 | expect(Int32.parseRadix(s, r).toString(), x); 361 | } 362 | 363 | check('deadbeef', 16, '-559038737'); 364 | check('95', 12, '113'); 365 | }); 366 | 367 | test('parseInt', () { 368 | expect(Int32.parseInt('0'), Int32(0)); 369 | expect(Int32.parseInt('1000'), Int32(1000)); 370 | expect(Int32.parseInt('4294967296'), Int32(4294967296)); 371 | }); 372 | 373 | test('parseHex', () { 374 | expect(Int32.parseHex('deadbeef'), Int32(0xdeadbeef)); 375 | expect(Int32.parseHex('cafebabe'), Int32(0xcafebabe)); 376 | expect(Int32.parseHex('8badf00d'), Int32(0x8badf00d)); 377 | }); 378 | }); 379 | 380 | group('string representation', () { 381 | test('toString', () { 382 | expect(Int32(0).toString(), '0'); 383 | expect(Int32(1).toString(), '1'); 384 | expect(Int32(-1).toString(), '-1'); 385 | expect(Int32(1000).toString(), '1000'); 386 | expect(Int32(-1000).toString(), '-1000'); 387 | expect(Int32(123456789).toString(), '123456789'); 388 | expect(Int32(2147483647).toString(), '2147483647'); 389 | expect(Int32(2147483648).toString(), '-2147483648'); 390 | expect(Int32(2147483649).toString(), '-2147483647'); 391 | expect(Int32(2147483650).toString(), '-2147483646'); 392 | expect(Int32(-2147483648).toString(), '-2147483648'); 393 | expect(Int32(-2147483649).toString(), '2147483647'); 394 | expect(Int32(-2147483650).toString(), '2147483646'); 395 | }); 396 | }); 397 | 398 | group('toHexString', () { 399 | test('returns hexadecimal string representation', () { 400 | expect(Int32(-1).toHexString(), '-1'); 401 | expect((Int32(-1) >> 8).toHexString(), '-1'); 402 | expect((Int32(-1) << 8).toHexString(), '-100'); 403 | expect(Int32(123456789).toHexString(), '75bcd15'); 404 | expect(Int32(-1).shiftRightUnsigned(8).toHexString(), 'ffffff'); 405 | }); 406 | }); 407 | 408 | group('toRadixString', () { 409 | test('returns base n string representation', () { 410 | expect(Int32(123456789).toRadixString(5), '223101104124'); 411 | }); 412 | }); 413 | } 414 | -------------------------------------------------------------------------------- /test/int64_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, 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 | // We permit local variable types in this test because they statically 'assert' 6 | // that the operations have an expected type. 7 | // 8 | // ignore_for_file: omit_local_variable_types 9 | 10 | import 'package:fixnum/fixnum.dart'; 11 | import 'package:test/test.dart'; 12 | 13 | void main() { 14 | group('fromBytes', () { 15 | test('fromBytes', () { 16 | void checkBytes(List bytes, int h, int l) { 17 | expect(Int64.fromBytes(bytes), Int64.fromInts(h, l)); 18 | } 19 | 20 | checkBytes([0, 0, 0, 0, 0, 0, 0, 0], 0, 0); 21 | checkBytes([1, 0, 0, 0, 0, 0, 0, 0], 0, 1); 22 | checkBytes([1, 2, 3, 4, 5, 6, 7, 8], 0x08070605, 0x04030201); 23 | checkBytes([0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], 0xffffffff, 24 | 0xfffffffe); 25 | checkBytes([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], 0xffffffff, 26 | 0xffffffff); 27 | }); 28 | test('fromBytesBigEndian', () { 29 | void checkBytes(List bytes, int h, int l) { 30 | expect(Int64.fromBytesBigEndian(bytes), Int64.fromInts(h, l)); 31 | } 32 | 33 | checkBytes([0, 0, 0, 0, 0, 0, 0, 0], 0, 0); 34 | checkBytes([0, 0, 0, 0, 0, 0, 0, 1], 0, 1); 35 | checkBytes([8, 7, 6, 5, 4, 3, 2, 1], 0x08070605, 0x04030201); 36 | checkBytes([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe], 0xffffffff, 37 | 0xfffffffe); 38 | checkBytes([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], 0xffffffff, 39 | 0xffffffff); 40 | }); 41 | }); 42 | 43 | void argumentErrorTest( 44 | Object Function(Int64, Object) op, [ 45 | Int64 receiver = Int64.ONE, 46 | ]) { 47 | expect( 48 | () => op(receiver, 'foo'), 49 | throwsA( 50 | isA() 51 | .having((p0) => p0.toString(), 'toString', contains('"foo"')), 52 | ), 53 | ); 54 | } 55 | 56 | group('is-tests', () { 57 | test('isEven', () { 58 | expect((-Int64.ONE).isEven, false); 59 | expect(Int64.ZERO.isEven, true); 60 | expect(Int64.ONE.isEven, false); 61 | expect(Int64.TWO.isEven, true); 62 | }); 63 | test('isMaxValue', () { 64 | expect(Int64.MIN_VALUE.isMaxValue, false); 65 | expect(Int64.ZERO.isMaxValue, false); 66 | expect(Int64.MAX_VALUE.isMaxValue, true); 67 | }); 68 | test('isMinValue', () { 69 | expect(Int64.MIN_VALUE.isMinValue, true); 70 | expect(Int64.ZERO.isMinValue, false); 71 | expect(Int64.MAX_VALUE.isMinValue, false); 72 | }); 73 | test('isNegative', () { 74 | expect(Int64.MIN_VALUE.isNegative, true); 75 | expect(Int64.ZERO.isNegative, false); 76 | expect(Int64.ONE.isNegative, false); 77 | }); 78 | test('isOdd', () { 79 | expect((-Int64.ONE).isOdd, true); 80 | expect(Int64.ZERO.isOdd, false); 81 | expect(Int64.ONE.isOdd, true); 82 | expect(Int64.TWO.isOdd, false); 83 | }); 84 | test('isZero', () { 85 | expect(Int64.MIN_VALUE.isZero, false); 86 | expect(Int64.ZERO.isZero, true); 87 | expect(Int64.MAX_VALUE.isZero, false); 88 | }); 89 | test('bitLength', () { 90 | expect(Int64(-2).bitLength, 1); 91 | expect((-Int64.ONE).bitLength, 0); 92 | expect(Int64.ZERO.bitLength, 0); 93 | expect((Int64.ONE << 21).bitLength, 22); 94 | expect((Int64.ONE << 22).bitLength, 23); 95 | expect((Int64.ONE << 43).bitLength, 44); 96 | expect((Int64.ONE << 44).bitLength, 45); 97 | expect(Int64(2).bitLength, 2); 98 | expect(Int64.MAX_VALUE.bitLength, 63); 99 | expect(Int64.MIN_VALUE.bitLength, 63); 100 | }); 101 | }); 102 | 103 | group('arithmetic operators', () { 104 | Int64 n1 = Int64(1234); 105 | Int64 n2 = Int64(9876); 106 | Int64 n3 = Int64(-1234); 107 | Int64 n4 = Int64(-9876); 108 | Int64 n5 = Int64.fromInts(0x12345678, 0xabcdabcd); 109 | Int64 n6 = Int64.fromInts(0x77773333, 0x22224444); 110 | 111 | test('+', () { 112 | expect(n1 + n2, Int64(11110)); 113 | expect(n3 + n2, Int64(8642)); 114 | expect(n3 + n4, Int64(-11110)); 115 | expect(n5 + n6, Int64.fromInts(0x89ab89ab, 0xcdeff011)); 116 | expect(Int64.MAX_VALUE + 1, Int64.MIN_VALUE); 117 | argumentErrorTest((a, b) => a + b); 118 | }); 119 | 120 | test('-', () { 121 | expect(n1 - n2, Int64(-8642)); 122 | expect(n3 - n2, Int64(-11110)); 123 | expect(n3 - n4, Int64(8642)); 124 | expect(n5 - n6, Int64.fromInts(0x9abd2345, 0x89ab6789)); 125 | expect(Int64.MIN_VALUE - 1, Int64.MAX_VALUE); 126 | argumentErrorTest((a, b) => a - b); 127 | }); 128 | 129 | test('unary -', () { 130 | expect(-n1, Int64(-1234)); 131 | expect(-Int64.ZERO, Int64.ZERO); 132 | }); 133 | 134 | test('*', () { 135 | expect(Int64(1111) * Int64(3), Int64(3333)); 136 | expect(Int64(1111) * Int64(-3), Int64(-3333)); 137 | expect(Int64(-1111) * Int64(3), Int64(-3333)); 138 | expect(Int64(-1111) * Int64(-3), Int64(3333)); 139 | expect(Int64(100) * Int64.ZERO, Int64.ZERO); 140 | 141 | expect( 142 | Int64.fromInts(0x12345678, 0x12345678) * 143 | Int64.fromInts(0x1234, 0x12345678), 144 | Int64.fromInts(0x7ff63f7c, 0x1df4d840)); 145 | expect( 146 | Int64.fromInts(0xf2345678, 0x12345678) * 147 | Int64.fromInts(0x1234, 0x12345678), 148 | Int64.fromInts(0x7ff63f7c, 0x1df4d840)); 149 | expect( 150 | Int64.fromInts(0xf2345678, 0x12345678) * 151 | Int64.fromInts(0xffff1234, 0x12345678), 152 | Int64.fromInts(0x297e3f7c, 0x1df4d840)); 153 | 154 | // RHS Int32 155 | expect(Int64(123456789) * Int32(987654321), 156 | Int64.fromInts(0x1b13114, 0xfbff5385)); 157 | expect(Int64(123456789) * Int32(987654321), 158 | Int64.fromInts(0x1b13114, 0xfbff5385)); 159 | 160 | // Wraparound 161 | expect(Int64(123456789) * Int64(987654321), 162 | Int64.fromInts(0x1b13114, 0xfbff5385)); 163 | 164 | expect(Int64.MIN_VALUE * Int64(2), Int64.ZERO); 165 | expect(Int64.MIN_VALUE * Int64(1), Int64.MIN_VALUE); 166 | expect(Int64.MIN_VALUE * Int64(-1), Int64.MIN_VALUE); 167 | argumentErrorTest((a, b) => a * b); 168 | }); 169 | 170 | test('~/', () { 171 | Int64 deadBeef = Int64.fromInts(0xDEADBEEF, 0xDEADBEEF); 172 | Int64 ten = Int64(10); 173 | 174 | expect(deadBeef ~/ ten, Int64.fromInts(0xfcaaf97e, 0x63115fe5)); 175 | expect(Int64.ONE ~/ Int64.TWO, Int64.ZERO); 176 | expect( 177 | Int64.MAX_VALUE ~/ Int64.TWO, Int64.fromInts(0x3fffffff, 0xffffffff)); 178 | expect(Int64.ZERO ~/ Int64(1000), Int64.ZERO); 179 | expect(Int64.MIN_VALUE ~/ Int64.MIN_VALUE, Int64.ONE); 180 | expect(Int64(1000) ~/ Int64.MIN_VALUE, Int64.ZERO); 181 | expect(Int64.MIN_VALUE ~/ Int64(8192), Int64(-1125899906842624)); 182 | expect(Int64.MIN_VALUE ~/ Int64(8193), Int64(-1125762484664320)); 183 | expect(Int64(-1000) ~/ Int64(8192), Int64.ZERO); 184 | expect(Int64(-1000) ~/ Int64(8193), Int64.ZERO); 185 | expect(Int64(-1000000000) ~/ Int64(8192), Int64(-122070)); 186 | expect(Int64(-1000000000) ~/ Int64(8193), Int64(-122055)); 187 | expect(Int64(1000000000) ~/ Int64(8192), Int64(122070)); 188 | expect(Int64(1000000000) ~/ Int64(8193), Int64(122055)); 189 | expect(Int64.MAX_VALUE ~/ Int64.fromInts(0x00000000, 0x00000400), 190 | Int64.fromInts(0x1fffff, 0xffffffff)); 191 | expect(Int64.MAX_VALUE ~/ Int64.fromInts(0x00000000, 0x00040000), 192 | Int64.fromInts(0x1fff, 0xffffffff)); 193 | expect(Int64.MAX_VALUE ~/ Int64.fromInts(0x00000000, 0x04000000), 194 | Int64.fromInts(0x1f, 0xffffffff)); 195 | expect(Int64.MAX_VALUE ~/ Int64.fromInts(0x00000004, 0x00000000), 196 | Int64(536870911)); 197 | expect(Int64.MAX_VALUE ~/ Int64.fromInts(0x00000400, 0x00000000), 198 | Int64(2097151)); 199 | expect(Int64.MAX_VALUE ~/ Int64.fromInts(0x00040000, 0x00000000), 200 | Int64(8191)); 201 | expect( 202 | Int64.MAX_VALUE ~/ Int64.fromInts(0x04000000, 0x00000000), Int64(31)); 203 | expect(Int64.MAX_VALUE ~/ Int64.fromInts(0x00000000, 0x00000300), 204 | Int64.fromInts(0x2AAAAA, 0xAAAAAAAA)); 205 | expect(Int64.MAX_VALUE ~/ Int64.fromInts(0x00000000, 0x30000000), 206 | Int64.fromInts(0x2, 0xAAAAAAAA)); 207 | expect(Int64.MAX_VALUE ~/ Int64.fromInts(0x00300000, 0x00000000), 208 | Int64(0x2AA)); 209 | expect(Int64.MAX_VALUE ~/ Int64(0x123456), 210 | Int64.fromInts(0x708, 0x002E9501)); 211 | expect(Int64.MAX_VALUE % Int64(0x123456), Int64(0x3BDA9)); 212 | expect(Int64(5) ~/ Int64(5), Int64.ONE); 213 | expect(Int64(1000) ~/ Int64(3), Int64(333)); 214 | expect(Int64(1000) ~/ Int64(-3), Int64(-333)); 215 | expect(Int64(-1000) ~/ Int64(3), Int64(-333)); 216 | expect(Int64(-1000) ~/ Int64(-3), Int64(333)); 217 | expect(Int64(3) ~/ Int64(1000), Int64.ZERO); 218 | expect( 219 | Int64.fromInts(0x12345678, 0x12345678) ~/ Int64.fromInts(0x0, 0x123), 220 | Int64.fromInts(0x1003d0, 0xe84f5ae8)); 221 | expect( 222 | Int64.fromInts(0x12345678, 0x12345678) ~/ 223 | Int64.fromInts(0x1234, 0x12345678), 224 | Int64.fromInts(0x0, 0x10003)); 225 | expect( 226 | Int64.fromInts(0xf2345678, 0x12345678) ~/ 227 | Int64.fromInts(0x1234, 0x12345678), 228 | Int64.fromInts(0xffffffff, 0xffff3dfe)); 229 | expect( 230 | Int64.fromInts(0xf2345678, 0x12345678) ~/ 231 | Int64.fromInts(0xffff1234, 0x12345678), 232 | Int64.fromInts(0x0, 0xeda)); 233 | expect(Int64(829893893) ~/ Int32(1919), Int32(432461)); 234 | expect(Int64(829893893) ~/ Int64(1919), Int32(432461)); 235 | expect(Int64(829893893) ~/ 1919, Int32(432461)); 236 | expect(() => Int64(1) ~/ Int64.ZERO, throwsA(isUnsupportedError)); 237 | expect( 238 | Int64.MIN_VALUE ~/ Int64(2), Int64.fromInts(0xc0000000, 0x00000000)); 239 | expect(Int64.MIN_VALUE ~/ Int64(1), Int64.MIN_VALUE); 240 | expect(Int64.MIN_VALUE ~/ Int64(-1), Int64.MIN_VALUE); 241 | expect(() => Int64(17) ~/ Int64.ZERO, throwsA(isUnsupportedError)); 242 | argumentErrorTest((a, b) => a ~/ b); 243 | }); 244 | 245 | test('%', () { 246 | // Define % as Euclidean mod, with positive result for all arguments 247 | expect(Int64.ZERO % Int64(1000), Int64.ZERO); 248 | expect(Int64.MIN_VALUE % Int64.MIN_VALUE, Int64.ZERO); 249 | expect(Int64(1000) % Int64.MIN_VALUE, Int64(1000)); 250 | expect(Int64.MIN_VALUE % Int64(8192), Int64.ZERO); 251 | expect(Int64.MIN_VALUE % Int64(8193), Int64(6145)); 252 | expect(Int64(-1000) % Int64(8192), Int64(7192)); 253 | expect(Int64(-1000) % Int64(8193), Int64(7193)); 254 | expect(Int64(-1000000000) % Int64(8192), Int64(5632)); 255 | expect(Int64(-1000000000) % Int64(8193), Int64(4808)); 256 | expect(Int64(1000000000) % Int64(8192), Int64(2560)); 257 | expect(Int64(1000000000) % Int64(8193), Int64(3385)); 258 | expect(Int64.MAX_VALUE % Int64.fromInts(0x00000000, 0x00000400), 259 | Int64.fromInts(0x0, 0x3ff)); 260 | expect(Int64.MAX_VALUE % Int64.fromInts(0x00000000, 0x00040000), 261 | Int64.fromInts(0x0, 0x3ffff)); 262 | expect(Int64.MAX_VALUE % Int64.fromInts(0x00000000, 0x04000000), 263 | Int64.fromInts(0x0, 0x3ffffff)); 264 | expect(Int64.MAX_VALUE % Int64.fromInts(0x00000004, 0x00000000), 265 | Int64.fromInts(0x3, 0xffffffff)); 266 | expect(Int64.MAX_VALUE % Int64.fromInts(0x00000400, 0x00000000), 267 | Int64.fromInts(0x3ff, 0xffffffff)); 268 | expect(Int64.MAX_VALUE % Int64.fromInts(0x00040000, 0x00000000), 269 | Int64.fromInts(0x3ffff, 0xffffffff)); 270 | expect(Int64.MAX_VALUE % Int64.fromInts(0x04000000, 0x00000000), 271 | Int64.fromInts(0x3ffffff, 0xffffffff)); 272 | expect(Int64(0x12345678).remainder(Int64(0x22)), 273 | Int64(0x12345678.remainder(0x22))); 274 | expect(Int64(0x12345678).remainder(Int64(-0x22)), 275 | Int64(0x12345678.remainder(-0x22))); 276 | expect(Int64(-0x12345678).remainder(Int64(-0x22)), 277 | Int64(-0x12345678.remainder(-0x22))); 278 | expect(Int64(-0x12345678).remainder(Int64(0x22)), 279 | Int64(-0x12345678.remainder(0x22))); 280 | expect(Int32(0x12345678).remainder(Int64(0x22)), 281 | Int64(0x12345678.remainder(0x22))); 282 | argumentErrorTest((a, b) => a % b); 283 | }); 284 | 285 | test('clamp', () { 286 | Int64 val = Int64(17); 287 | expect(val.clamp(20, 30), Int64(20)); 288 | expect(val.clamp(10, 20), Int64(17)); 289 | expect(val.clamp(10, 15), Int64(15)); 290 | 291 | expect(val.clamp(Int32(20), Int32(30)), Int64(20)); 292 | expect(val.clamp(Int32(10), Int32(20)), Int64(17)); 293 | expect(val.clamp(Int32(10), Int32(15)), Int64(15)); 294 | 295 | expect(val.clamp(Int64(20), Int64(30)), Int64(20)); 296 | expect(val.clamp(Int64(10), Int64(20)), Int64(17)); 297 | expect(val.clamp(Int64(10), Int64(15)), Int64(15)); 298 | expect(val.clamp(Int64.MIN_VALUE, Int64(30)), Int64(17)); 299 | expect(val.clamp(Int64(10), Int64.MAX_VALUE), Int64(17)); 300 | 301 | expect(() => val.clamp(1, 'b'), throwsA(isArgumentError)); 302 | expect(() => val.clamp('a', 1), throwsA(isArgumentError)); 303 | }); 304 | }); 305 | 306 | group('leading/trailing zeros', () { 307 | test('numberOfLeadingZeros', () { 308 | void checkZeros(Int64 value, int zeros) { 309 | expect(value.numberOfLeadingZeros(), zeros); 310 | } 311 | 312 | checkZeros(Int64(0), 64); 313 | checkZeros(Int64(1), 63); 314 | checkZeros(Int64.fromInts(0x00000000, 0x003fffff), 42); 315 | checkZeros(Int64.fromInts(0x00000000, 0x00400000), 41); 316 | checkZeros(Int64.fromInts(0x00000fff, 0xffffffff), 20); 317 | checkZeros(Int64.fromInts(0x00001000, 0x00000000), 19); 318 | checkZeros(Int64.fromInts(0x7fffffff, 0xffffffff), 1); 319 | checkZeros(Int64(-1), 0); 320 | }); 321 | 322 | test('numberOfTrailingZeros', () { 323 | void checkZeros(Int64 value, int zeros) { 324 | expect(value.numberOfTrailingZeros(), zeros); 325 | } 326 | 327 | checkZeros(Int64(-1), 0); 328 | checkZeros(Int64(1), 0); 329 | checkZeros(Int64(2), 1); 330 | checkZeros(Int64.fromInts(0x00000000, 0x00200000), 21); 331 | checkZeros(Int64.fromInts(0x00000000, 0x00400000), 22); 332 | checkZeros(Int64.fromInts(0x00000800, 0x00000000), 43); 333 | checkZeros(Int64.fromInts(0x00001000, 0x00000000), 44); 334 | checkZeros(Int64.fromInts(0x80000000, 0x00000000), 63); 335 | checkZeros(Int64(0), 64); 336 | }); 337 | }); 338 | 339 | group('comparison operators', () { 340 | Int64 largeNeg = Int64.fromInts(0x82341234, 0x0); 341 | Int64 largePos = Int64.fromInts(0x12341234, 0x0); 342 | Int64 largePosPlusOne = largePos + Int64(1); 343 | 344 | test('<', () { 345 | expect(Int64(10) < Int64(11), true); 346 | expect(Int64(10) < Int64(10), false); 347 | expect(Int64(10) < Int64(9), false); 348 | expect(Int64(10) < Int32(11), true); 349 | expect(Int64(10) < Int32(10), false); 350 | expect(Int64(10) < Int32(9), false); 351 | expect(Int64(-10) < Int64(-11), false); 352 | expect(Int64.MIN_VALUE < Int64.ZERO, true); 353 | expect(largeNeg < largePos, true); 354 | expect(largePos < largePosPlusOne, true); 355 | expect(largePos < largePos, false); 356 | expect(largePosPlusOne < largePos, false); 357 | expect(Int64.MIN_VALUE < Int64.MAX_VALUE, true); 358 | expect(Int64.MAX_VALUE < Int64.MIN_VALUE, false); 359 | argumentErrorTest((a, b) => a < b); 360 | }); 361 | 362 | test('<=', () { 363 | expect(Int64(10) <= Int64(11), true); 364 | expect(Int64(10) <= Int64(10), true); 365 | expect(Int64(10) <= Int64(9), false); 366 | expect(Int64(10) <= Int32(11), true); 367 | expect(Int64(10) <= Int32(10), true); 368 | expect(Int64(10) <= Int64(9), false); 369 | expect(Int64(-10) <= Int64(-11), false); 370 | expect(Int64(-10) <= Int64(-10), true); 371 | expect(largeNeg <= largePos, true); 372 | expect(largePos <= largeNeg, false); 373 | expect(largePos <= largePosPlusOne, true); 374 | expect(largePos <= largePos, true); 375 | expect(largePosPlusOne <= largePos, false); 376 | expect(Int64.MIN_VALUE <= Int64.MAX_VALUE, true); 377 | expect(Int64.MAX_VALUE <= Int64.MIN_VALUE, false); 378 | argumentErrorTest((a, b) => a <= b); 379 | }); 380 | 381 | test('==', () { 382 | expect(Int64(0), equals(Int64(0))); 383 | expect(Int64(0), isNot(equals(Int64(1)))); 384 | expect(Int64(0), equals(Int32(0))); 385 | expect(Int64(0), isNot(equals(Int32(1)))); 386 | expect(Int64(0) == 0, isTrue); // ignore: unrelated_type_equality_checks 387 | expect(Int64(0), isNot(equals(1))); 388 | expect(Int64(10), isNot(equals(Int64(11)))); 389 | expect(Int64(10), equals(Int64(10))); 390 | expect(Int64(10), isNot(equals(Int64(9)))); 391 | expect(Int64(10), isNot(equals(Int32(11)))); 392 | expect(Int64(10), equals(Int32(10))); 393 | expect(Int64(10), isNot(equals(Int32(9)))); 394 | expect(Int64(10), isNot(equals(11))); 395 | expect(Int64(10) == 10, isTrue); // ignore: unrelated_type_equality_checks 396 | expect(Int64(10), isNot(equals(9))); 397 | expect(Int64(-10), equals(Int64(-10))); 398 | expect(Int64(-10) != Int64(-10), false); 399 | expect( 400 | Int64(-10) == -10, isTrue); // ignore: unrelated_type_equality_checks 401 | expect(Int64(-10), isNot(equals(-9))); 402 | expect(largePos, equals(largePos)); 403 | expect(largePos, isNot(equals(largePosPlusOne))); 404 | expect(largePosPlusOne, isNot(equals(largePos))); 405 | expect(Int64.MIN_VALUE, isNot(equals(Int64.MAX_VALUE))); 406 | expect(Int64(17), isNot(equals(Object()))); 407 | expect(Int64(17), isNot(equals(null))); 408 | }); 409 | 410 | test('>=', () { 411 | expect(Int64(10) >= Int64(11), false); 412 | expect(Int64(10) >= Int64(10), true); 413 | expect(Int64(10) >= Int64(9), true); 414 | expect(Int64(10) >= Int32(11), false); 415 | expect(Int64(10) >= Int32(10), true); 416 | expect(Int64(10) >= Int32(9), true); 417 | expect(Int64(-10) >= Int64(-11), true); 418 | expect(Int64(-10) >= Int64(-10), true); 419 | expect(largePos >= largeNeg, true); 420 | expect(largeNeg >= largePos, false); 421 | expect(largePos >= largePosPlusOne, false); 422 | expect(largePos >= largePos, true); 423 | expect(largePosPlusOne >= largePos, true); 424 | expect(Int64.MIN_VALUE >= Int64.MAX_VALUE, false); 425 | expect(Int64.MAX_VALUE >= Int64.MIN_VALUE, true); 426 | argumentErrorTest((a, b) => a >= b); 427 | }); 428 | 429 | test('>', () { 430 | expect(Int64(10) > Int64(11), false); 431 | expect(Int64(10) > Int64(10), false); 432 | expect(Int64(10) > Int64(9), true); 433 | expect(Int64(10) > Int32(11), false); 434 | expect(Int64(10) > Int32(10), false); 435 | expect(Int64(10) > Int32(9), true); 436 | expect(Int64(-10) > Int64(-11), true); 437 | expect(Int64(10) > Int64(-11), true); 438 | expect(Int64(-10) > Int64(11), false); 439 | expect(largePos > largeNeg, true); 440 | expect(largeNeg > largePos, false); 441 | expect(largePos > largePosPlusOne, false); 442 | expect(largePos > largePos, false); 443 | expect(largePosPlusOne > largePos, true); 444 | expect(Int64.ZERO > Int64.MIN_VALUE, true); 445 | expect(Int64.MIN_VALUE > Int64.MAX_VALUE, false); 446 | expect(Int64.MAX_VALUE > Int64.MIN_VALUE, true); 447 | argumentErrorTest((a, b) => a > b); 448 | }); 449 | }); 450 | 451 | group('bitwise operators', () { 452 | Int64 n1 = Int64(1234); 453 | Int64 n2 = Int64(9876); 454 | Int64 n3 = Int64(-1234); 455 | Int64 n4 = Int64(0x1234) << 32; 456 | Int64 n5 = Int64(0x9876) << 32; 457 | 458 | test('&', () { 459 | expect(n1 & n2, Int64(1168)); 460 | expect(n3 & n2, Int64(8708)); 461 | expect(n4 & n5, Int64(0x1034) << 32); 462 | argumentErrorTest((a, b) => a & b); 463 | }); 464 | 465 | test('|', () { 466 | expect(n1 | n2, Int64(9942)); 467 | expect(n3 | n2, Int64(-66)); 468 | expect(n4 | n5, Int64(0x9a76) << 32); 469 | argumentErrorTest((a, b) => a | b); 470 | }); 471 | 472 | test('^', () { 473 | expect(n1 ^ n2, Int64(8774)); 474 | expect(n3 ^ n2, Int64(-8774)); 475 | expect(n4 ^ n5, Int64(0x8a42) << 32); 476 | argumentErrorTest((a, b) => a ^ b); 477 | }); 478 | 479 | test('~', () { 480 | expect(-Int64(1), Int64(-1)); 481 | expect(-Int64(-1), Int64(1)); 482 | expect(-Int64.MIN_VALUE, Int64.MIN_VALUE); 483 | 484 | expect(~n1, Int64(-1235)); 485 | expect(~n2, Int64(-9877)); 486 | expect(~n3, Int64(1233)); 487 | expect(~n4, Int64.fromInts(0xffffedcb, 0xffffffff)); 488 | expect(~n5, Int64.fromInts(0xffff6789, 0xffffffff)); 489 | }); 490 | }); 491 | 492 | group('bitshift operators', () { 493 | test('<<', () { 494 | expect(Int64.fromInts(0x12341234, 0x45674567) << 10, 495 | Int64.fromInts(0xd048d115, 0x9d159c00)); 496 | expect(Int64.fromInts(0x92341234, 0x45674567) << 10, 497 | Int64.fromInts(0xd048d115, 0x9d159c00)); 498 | expect(Int64(-1) << 5, Int64(-32)); 499 | expect(Int64(-1) << 0, Int64(-1)); 500 | expect(Int64(42) << 64, Int64.ZERO); 501 | expect(Int64(42) << 65, Int64.ZERO); 502 | expect(() => Int64(17) << -1, throwsArgumentError); 503 | }); 504 | 505 | test('>>', () { 506 | expect((Int64.MIN_VALUE >> 13).toString(), '-1125899906842624'); 507 | expect(Int64.fromInts(0x12341234, 0x45674567) >> 10, 508 | Int64.fromInts(0x48d04, 0x8d1159d1)); 509 | expect(Int64.fromInts(0x92341234, 0x45674567) >> 10, 510 | Int64.fromInts(0xffe48d04, 0x8d1159d1)); 511 | expect(Int64.fromInts(0xFFFFFFF, 0xFFFFFFFF) >> 34, Int64(67108863)); 512 | expect(Int64(42) >> 64, Int64.ZERO); 513 | expect(Int64(42) >> 65, Int64.ZERO); 514 | for (int n = 0; n <= 66; n++) { 515 | expect(Int64(-1) >> n, Int64(-1)); 516 | } 517 | expect(Int64.fromInts(0x72345678, 0x9abcdef0) >> 8, 518 | Int64.fromInts(0x00723456, 0x789abcde)); 519 | expect(Int64.fromInts(0x72345678, 0x9abcdef0) >> 16, 520 | Int64.fromInts(0x00007234, 0x56789abc)); 521 | expect(Int64.fromInts(0x72345678, 0x9abcdef0) >> 24, 522 | Int64.fromInts(0x00000072, 0x3456789a)); 523 | expect(Int64.fromInts(0x72345678, 0x9abcdef0) >> 28, 524 | Int64.fromInts(0x00000007, 0x23456789)); 525 | expect(Int64.fromInts(0x72345678, 0x9abcdef0) >> 32, 526 | Int64.fromInts(0x00000000, 0x72345678)); 527 | expect(Int64.fromInts(0x72345678, 0x9abcdef0) >> 36, 528 | Int64.fromInts(0x00000000, 0x07234567)); 529 | expect(Int64.fromInts(0x72345678, 0x9abcdef0) >> 40, 530 | Int64.fromInts(0x00000000, 0x00723456)); 531 | expect(Int64.fromInts(0x72345678, 0x9abcde00) >> 44, 532 | Int64.fromInts(0x00000000, 0x00072345)); 533 | expect(Int64.fromInts(0x72345678, 0x9abcdef0) >> 48, 534 | Int64.fromInts(0x00000000, 0x00007234)); 535 | expect(Int64.fromInts(0x92345678, 0x9abcdef0) >> 8, 536 | Int64.fromInts(0xff923456, 0x789abcde)); 537 | expect(Int64.fromInts(0x92345678, 0x9abcdef0) >> 16, 538 | Int64.fromInts(0xffff9234, 0x56789abc)); 539 | expect(Int64.fromInts(0x92345678, 0x9abcdef0) >> 24, 540 | Int64.fromInts(0xffffff92, 0x3456789a)); 541 | expect(Int64.fromInts(0x92345678, 0x9abcdef0) >> 28, 542 | Int64.fromInts(0xfffffff9, 0x23456789)); 543 | expect(Int64.fromInts(0x92345678, 0x9abcdef0) >> 32, 544 | Int64.fromInts(0xffffffff, 0x92345678)); 545 | expect(Int64.fromInts(0x92345678, 0x9abcdef0) >> 36, 546 | Int64.fromInts(0xffffffff, 0xf9234567)); 547 | expect(Int64.fromInts(0x92345678, 0x9abcdef0) >> 40, 548 | Int64.fromInts(0xffffffff, 0xff923456)); 549 | expect(Int64.fromInts(0x92345678, 0x9abcdef0) >> 44, 550 | Int64.fromInts(0xffffffff, 0xfff92345)); 551 | expect(Int64.fromInts(0x92345678, 0x9abcdef0) >> 48, 552 | Int64.fromInts(0xffffffff, 0xffff9234)); 553 | expect(() => Int64(17) >> -1, throwsArgumentError); 554 | }); 555 | 556 | test('shiftRightUnsigned', () { 557 | expect(Int64.fromInts(0x12341234, 0x45674567).shiftRightUnsigned(10), 558 | Int64.fromInts(0x48d04, 0x8d1159d1)); 559 | expect(Int64.fromInts(0x92341234, 0x45674567).shiftRightUnsigned(10), 560 | Int64.fromInts(0x248d04, 0x8d1159d1)); 561 | expect(Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(8), 562 | Int64.fromInts(0x00723456, 0x789abcde)); 563 | expect(Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(16), 564 | Int64.fromInts(0x00007234, 0x56789abc)); 565 | expect(Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(24), 566 | Int64.fromInts(0x00000072, 0x3456789a)); 567 | expect(Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(28), 568 | Int64.fromInts(0x00000007, 0x23456789)); 569 | expect(Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(32), 570 | Int64.fromInts(0x00000000, 0x72345678)); 571 | expect(Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(36), 572 | Int64.fromInts(0x00000000, 0x07234567)); 573 | expect(Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(40), 574 | Int64.fromInts(0x00000000, 0x00723456)); 575 | expect(Int64.fromInts(0x72345678, 0x9abcde00).shiftRightUnsigned(44), 576 | Int64.fromInts(0x00000000, 0x00072345)); 577 | expect(Int64.fromInts(0x72345678, 0x9abcdef0).shiftRightUnsigned(48), 578 | Int64.fromInts(0x00000000, 0x00007234)); 579 | expect(Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(8), 580 | Int64.fromInts(0x00923456, 0x789abcde)); 581 | expect(Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(16), 582 | Int64.fromInts(0x00009234, 0x56789abc)); 583 | expect(Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(24), 584 | Int64.fromInts(0x00000092, 0x3456789a)); 585 | expect(Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(28), 586 | Int64.fromInts(0x00000009, 0x23456789)); 587 | expect(Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(32), 588 | Int64.fromInts(0x00000000, 0x92345678)); 589 | expect(Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(36), 590 | Int64.fromInts(0x00000000, 0x09234567)); 591 | expect(Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(40), 592 | Int64.fromInts(0x00000000, 0x00923456)); 593 | expect(Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(44), 594 | Int64.fromInts(0x00000000, 0x00092345)); 595 | expect(Int64.fromInts(0x00000000, 0x00009234), 596 | Int64.fromInts(0x92345678, 0x9abcdef0).shiftRightUnsigned(48)); 597 | expect(Int64(-1).shiftRightUnsigned(64), Int64.ZERO); 598 | expect(Int64(1).shiftRightUnsigned(64), Int64.ZERO); 599 | expect(() => Int64(17).shiftRightUnsigned(-1), throwsArgumentError); 600 | }); 601 | 602 | test('overflow', () { 603 | expect((Int64(1) << 63) >> 1, -Int64.fromInts(0x40000000, 0x00000000)); 604 | expect((Int64(-1) << 32) << 32, Int64(0)); 605 | expect(Int64.MIN_VALUE << 0, Int64.MIN_VALUE); 606 | expect(Int64.MIN_VALUE << 1, Int64(0)); 607 | expect( 608 | (-Int64.fromInts(8, 0)) >> 1, Int64.fromInts(0xfffffffc, 0x00000000)); 609 | expect((-Int64.fromInts(8, 0)).shiftRightUnsigned(1), 610 | Int64.fromInts(0x7ffffffc, 0x0)); 611 | }); 612 | }); 613 | 614 | group('conversions', () { 615 | test('toSigned', () { 616 | expect((Int64.ONE << 44).toSigned(46), Int64.ONE << 44); 617 | expect((Int64.ONE << 44).toSigned(45), -(Int64.ONE << 44)); 618 | expect((Int64.ONE << 22).toSigned(24), Int64.ONE << 22); 619 | expect((Int64.ONE << 22).toSigned(23), -(Int64.ONE << 22)); 620 | expect(Int64.ONE.toSigned(2), Int64.ONE); 621 | expect(Int64.ONE.toSigned(1), -Int64.ONE); 622 | expect(Int64.MAX_VALUE.toSigned(64), Int64.MAX_VALUE); 623 | expect(Int64.MIN_VALUE.toSigned(64), Int64.MIN_VALUE); 624 | expect(Int64.MAX_VALUE.toSigned(63), -Int64.ONE); 625 | expect(Int64.MIN_VALUE.toSigned(63), Int64.ZERO); 626 | expect(() => Int64.ONE.toSigned(0), throwsRangeError); 627 | expect(() => Int64.ONE.toSigned(65), throwsRangeError); 628 | }); 629 | test('toUnsigned', () { 630 | expect((Int64.ONE << 44).toUnsigned(45), Int64.ONE << 44); 631 | expect((Int64.ONE << 44).toUnsigned(44), Int64.ZERO); 632 | expect((Int64.ONE << 22).toUnsigned(23), Int64.ONE << 22); 633 | expect((Int64.ONE << 22).toUnsigned(22), Int64.ZERO); 634 | expect(Int64.ONE.toUnsigned(1), Int64.ONE); 635 | expect(Int64.ONE.toUnsigned(0), Int64.ZERO); 636 | expect(Int64.MAX_VALUE.toUnsigned(64), Int64.MAX_VALUE); 637 | expect(Int64.MIN_VALUE.toUnsigned(64), Int64.MIN_VALUE); 638 | expect(Int64.MAX_VALUE.toUnsigned(63), Int64.MAX_VALUE); 639 | expect(Int64.MIN_VALUE.toUnsigned(63), Int64.ZERO); 640 | expect(() => Int64.ONE.toUnsigned(-1), throwsRangeError); 641 | expect(() => Int64.ONE.toUnsigned(65), throwsRangeError); 642 | }); 643 | test('toDouble', () { 644 | expect(Int64(0).toDouble(), same(0.0)); 645 | expect(Int64(100).toDouble(), same(100.0)); 646 | expect(Int64(-100).toDouble(), same(-100.0)); 647 | expect(Int64(2147483647).toDouble(), same(2147483647.0)); 648 | expect(Int64(2147483648).toDouble(), same(2147483648.0)); 649 | expect(Int64(-2147483647).toDouble(), same(-2147483647.0)); 650 | expect(Int64(-2147483648).toDouble(), same(-2147483648.0)); 651 | expect(Int64(4503599627370495).toDouble(), same(4503599627370495.0)); 652 | expect(Int64(4503599627370496).toDouble(), same(4503599627370496.0)); 653 | expect(Int64(-4503599627370495).toDouble(), same(-4503599627370495.0)); 654 | expect(Int64(-4503599627370496).toDouble(), same(-4503599627370496.0)); 655 | expect(Int64.parseInt('-10000000000000000').toDouble().toStringAsFixed(1), 656 | '-10000000000000000.0'); 657 | expect(Int64.parseInt('-10000000000000001').toDouble().toStringAsFixed(1), 658 | '-10000000000000000.0'); 659 | expect(Int64.parseInt('-10000000000000002').toDouble().toStringAsFixed(1), 660 | '-10000000000000002.0'); 661 | expect(Int64.parseInt('-10000000000000003').toDouble().toStringAsFixed(1), 662 | '-10000000000000004.0'); 663 | expect(Int64.parseInt('-10000000000000004').toDouble().toStringAsFixed(1), 664 | '-10000000000000004.0'); 665 | expect(Int64.parseInt('-10000000000000005').toDouble().toStringAsFixed(1), 666 | '-10000000000000004.0'); 667 | expect(Int64.parseInt('-10000000000000006').toDouble().toStringAsFixed(1), 668 | '-10000000000000006.0'); 669 | expect(Int64.parseInt('-10000000000000007').toDouble().toStringAsFixed(1), 670 | '-10000000000000008.0'); 671 | expect(Int64.parseInt('-10000000000000008').toDouble().toStringAsFixed(1), 672 | '-10000000000000008.0'); 673 | }); 674 | 675 | test('toInt', () { 676 | expect(Int64(0).toInt(), 0); 677 | expect(Int64(100).toInt(), 100); 678 | expect(Int64(-100).toInt(), -100); 679 | expect(Int64(2147483647).toInt(), 2147483647); 680 | expect(Int64(2147483648).toInt(), 2147483648); 681 | expect(Int64(-2147483647).toInt(), -2147483647); 682 | expect(Int64(-2147483648).toInt(), -2147483648); 683 | expect(Int64(4503599627370495).toInt(), 4503599627370495); 684 | expect(Int64(4503599627370496).toInt(), 4503599627370496); 685 | expect(Int64(-4503599627370495).toInt(), -4503599627370495); 686 | expect(Int64(-4503599627370496).toInt(), -4503599627370496); 687 | }); 688 | 689 | test('toInt32', () { 690 | expect(Int64(0).toInt32(), Int32(0)); 691 | expect(Int64(1).toInt32(), Int32(1)); 692 | expect(Int64(-1).toInt32(), Int32(-1)); 693 | expect(Int64(2147483647).toInt32(), Int32(2147483647)); 694 | expect(Int64(2147483648).toInt32(), Int32(-2147483648)); 695 | expect(Int64(2147483649).toInt32(), Int32(-2147483647)); 696 | expect(Int64(2147483650).toInt32(), Int32(-2147483646)); 697 | expect(Int64(-2147483648).toInt32(), Int32(-2147483648)); 698 | expect(Int64(-2147483649).toInt32(), Int32(2147483647)); 699 | expect(Int64(-2147483650).toInt32(), Int32(2147483646)); 700 | expect(Int64(-2147483651).toInt32(), Int32(2147483645)); 701 | }); 702 | 703 | test('toBytes', () { 704 | expect(Int64(0).toBytes(), [0, 0, 0, 0, 0, 0, 0, 0]); 705 | expect(Int64.fromInts(0x08070605, 0x04030201).toBytes(), 706 | [1, 2, 3, 4, 5, 6, 7, 8]); 707 | expect(Int64.fromInts(0x01020304, 0x05060708).toBytes(), 708 | [8, 7, 6, 5, 4, 3, 2, 1]); 709 | expect(Int64(-1).toBytes(), 710 | [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); 711 | }); 712 | }); 713 | 714 | test('JavaScript 53-bit integer boundary', () { 715 | Int64 factorial(Int64 n) { 716 | if (n.isZero) { 717 | return Int64(1); 718 | } else { 719 | return n * factorial(n - Int64(1)); 720 | } 721 | } 722 | 723 | Int64 fact18 = factorial(Int64(18)); 724 | Int64 fact17 = factorial(Int64(17)); 725 | expect(fact18 ~/ fact17, Int64(18)); 726 | }); 727 | 728 | test('min, max values', () { 729 | expect(Int64(1) << 63, Int64.MIN_VALUE); 730 | expect(-(Int64.MIN_VALUE + Int64(1)), Int64.MAX_VALUE); 731 | }); 732 | 733 | test('negation', () { 734 | void check(int n) { 735 | // Sign change should commute with conversion. 736 | expect(-Int64(-n), Int64(n)); 737 | expect(Int64(-n), -Int64(n)); 738 | } 739 | 740 | check(10); 741 | check(1000000000000000000); 742 | check(9223372036854774784); // Near Int64.MAX_VALUE with exact double value. 743 | check(-9223372036854775808); // Int64.MIN_VALUE. Is exact double. 744 | }); 745 | 746 | group('parse', () { 747 | test('parseRadix10', () { 748 | void checkInt(int x) { 749 | expect(Int64.parseRadix('$x', 10), Int64(x)); 750 | expect(Int64.tryParseRadix('$x', 10), Int64(x)); 751 | } 752 | 753 | checkInt(0); 754 | checkInt(1); 755 | checkInt(-1); 756 | checkInt(1000); 757 | checkInt(12345678); 758 | checkInt(-12345678); 759 | checkInt(2147483647); 760 | checkInt(2147483648); 761 | checkInt(-2147483647); 762 | checkInt(-2147483648); 763 | checkInt(4294967295); 764 | checkInt(4294967296); 765 | checkInt(-4294967295); 766 | checkInt(-4294967296); 767 | 768 | expect(() => Int64.parseRadix('xyzzy', -1), throwsArgumentError); 769 | expect(() => Int64.parseRadix('plugh', 10), throwsFormatException); 770 | expect(() => Int64.parseRadix('', 10), throwsFormatException); 771 | expect(() => Int64.parseRadix('-', 10), throwsFormatException); 772 | 773 | expect(() => Int64.tryParseRadix('xyzzy', -1), throwsArgumentError); 774 | expect(Int64.tryParseRadix('plugh', 10), null); 775 | expect(Int64.tryParseRadix('', 10), null); 776 | expect(Int64.tryParseRadix('-', 10), null); 777 | }); 778 | 779 | test('parseHex', () { 780 | void checkHex(String hexStr, int h, int l) { 781 | expect(Int64.parseHex(hexStr), Int64.fromInts(h, l)); 782 | expect(Int64.tryParseHex(hexStr), Int64.fromInts(h, l)); 783 | } 784 | 785 | checkHex('0', 0, 0); 786 | checkHex('-0', 0, 0); 787 | checkHex('00', 0, 0); 788 | checkHex('01', 0, 1); 789 | checkHex('-01', 0xffffffff, 0xffffffff); 790 | checkHex('0a', 0, 10); 791 | checkHex('0A', 0, 10); 792 | checkHex('10', 0, 16); 793 | checkHex('3FFFFF', 0, 0x3fffff); 794 | checkHex('400000', 0, 0x400000); 795 | checkHex('FFFFFFFFFFF', 0xfff, 0xffffffff); 796 | checkHex('FFFFFFFFFFFFFFFE', 0xffffffff, 0xfffffffe); 797 | checkHex('FFFFFFFFFFFFFFFF', 0xffffffff, 0xffffffff); 798 | 799 | expect(() => Int64.parseHex(''), throwsFormatException); 800 | expect(() => Int64.parseHex('-'), throwsFormatException); 801 | 802 | expect(Int64.tryParseHex(''), null); 803 | expect(Int64.tryParseHex('-'), null); 804 | }); 805 | 806 | test('parseRadix', () { 807 | void check(String s, int r, String x) { 808 | expect(Int64.parseRadix(s, r).toString(), x); 809 | expect(Int64.tryParseRadix(s, r).toString(), x); 810 | } 811 | 812 | check('ghoul', 36, '27699213'); 813 | check('ghoul', 35, '24769346'); 814 | // Min and max value. 815 | check('-9223372036854775808', 10, '-9223372036854775808'); 816 | check('9223372036854775807', 10, '9223372036854775807'); 817 | // Overflow during parsing. 818 | check('9223372036854775808', 10, '-9223372036854775808'); 819 | 820 | expect(() => Int64.parseRadix('0', 1), throwsRangeError); 821 | expect(() => Int64.parseRadix('0', 37), throwsRangeError); 822 | expect(() => Int64.parseRadix('xyzzy', -1), throwsRangeError); 823 | expect(() => Int64.parseRadix('xyzzy', 10), throwsFormatException); 824 | 825 | expect(() => Int64.tryParseRadix('0', 1), throwsRangeError); 826 | expect(() => Int64.tryParseRadix('0', 37), throwsRangeError); 827 | expect(() => Int64.tryParseRadix('xyzzy', -1), throwsRangeError); 828 | expect(Int64.tryParseRadix('xyzzy', 10), null); 829 | }); 830 | 831 | test('parseRadixN', () { 832 | void check(String s, int r) { 833 | expect(Int64.parseRadix(s, r).toRadixString(r), s); 834 | expect(Int64.tryParseRadix(s, r)!.toRadixString(r), s); 835 | } 836 | 837 | check('2ppp111222333', 33); // This value & radix requires three chunks. 838 | }); 839 | }); 840 | 841 | group('string representation', () { 842 | test('toString', () { 843 | expect(Int64(0).toString(), '0'); 844 | expect(Int64(1).toString(), '1'); 845 | expect(Int64(-1).toString(), '-1'); 846 | expect(Int64(-10).toString(), '-10'); 847 | expect(Int64.MIN_VALUE.toString(), '-9223372036854775808'); 848 | expect(Int64.MAX_VALUE.toString(), '9223372036854775807'); 849 | 850 | int top = 922337201; 851 | int bottom = 967490662; 852 | Int64 fullnum = (Int64(1000000000) * Int64(top)) + Int64(bottom); 853 | expect(fullnum.toString(), '922337201967490662'); 854 | expect((-fullnum).toString(), '-922337201967490662'); 855 | expect(Int64(123456789).toString(), '123456789'); 856 | }); 857 | 858 | test('toHexString', () { 859 | Int64 deadbeef12341234 = Int64.fromInts(0xDEADBEEF, 0x12341234); 860 | expect(Int64.ZERO.toHexString(), '0'); 861 | expect(deadbeef12341234.toHexString(), 'DEADBEEF12341234'); 862 | expect(Int64.fromInts(0x17678A7, 0xDEF01234).toHexString(), 863 | '17678A7DEF01234'); 864 | expect(Int64(123456789).toHexString(), '75BCD15'); 865 | }); 866 | 867 | test('toRadixString', () { 868 | expect(Int64(123456789).toRadixString(5), '223101104124'); 869 | expect(Int64.MIN_VALUE.toRadixString(2), 870 | '-1000000000000000000000000000000000000000000000000000000000000000'); 871 | expect(Int64.MIN_VALUE.toRadixString(3), 872 | '-2021110011022210012102010021220101220222'); 873 | expect(Int64.MIN_VALUE.toRadixString(4), 874 | '-20000000000000000000000000000000'); 875 | expect(Int64.MIN_VALUE.toRadixString(5), '-1104332401304422434310311213'); 876 | expect(Int64.MIN_VALUE.toRadixString(6), '-1540241003031030222122212'); 877 | expect(Int64.MIN_VALUE.toRadixString(7), '-22341010611245052052301'); 878 | expect(Int64.MIN_VALUE.toRadixString(8), '-1000000000000000000000'); 879 | expect(Int64.MIN_VALUE.toRadixString(9), '-67404283172107811828'); 880 | expect(Int64.MIN_VALUE.toRadixString(10), '-9223372036854775808'); 881 | expect(Int64.MIN_VALUE.toRadixString(11), '-1728002635214590698'); 882 | expect(Int64.MIN_VALUE.toRadixString(12), '-41a792678515120368'); 883 | expect(Int64.MIN_VALUE.toRadixString(13), '-10b269549075433c38'); 884 | expect(Int64.MIN_VALUE.toRadixString(14), '-4340724c6c71dc7a8'); 885 | expect(Int64.MIN_VALUE.toRadixString(15), '-160e2ad3246366808'); 886 | expect(Int64.MIN_VALUE.toRadixString(16), '-8000000000000000'); 887 | expect(Int64.MAX_VALUE.toRadixString(2), 888 | '111111111111111111111111111111111111111111111111111111111111111'); 889 | expect(Int64.MAX_VALUE.toRadixString(3), 890 | '2021110011022210012102010021220101220221'); 891 | expect( 892 | Int64.MAX_VALUE.toRadixString(4), '13333333333333333333333333333333'); 893 | expect(Int64.MAX_VALUE.toRadixString(5), '1104332401304422434310311212'); 894 | expect(Int64.MAX_VALUE.toRadixString(6), '1540241003031030222122211'); 895 | expect(Int64.MAX_VALUE.toRadixString(7), '22341010611245052052300'); 896 | expect(Int64.MAX_VALUE.toRadixString(8), '777777777777777777777'); 897 | expect(Int64.MAX_VALUE.toRadixString(9), '67404283172107811827'); 898 | expect(Int64.MAX_VALUE.toRadixString(10), '9223372036854775807'); 899 | expect(Int64.MAX_VALUE.toRadixString(11), '1728002635214590697'); 900 | expect(Int64.MAX_VALUE.toRadixString(12), '41a792678515120367'); 901 | expect(Int64.MAX_VALUE.toRadixString(13), '10b269549075433c37'); 902 | expect(Int64.MAX_VALUE.toRadixString(14), '4340724c6c71dc7a7'); 903 | expect(Int64.MAX_VALUE.toRadixString(15), '160e2ad3246366807'); 904 | expect(Int64.MAX_VALUE.toRadixString(16), '7fffffffffffffff'); 905 | expect(() => Int64(42).toRadixString(-1), throwsArgumentError); 906 | expect(() => Int64(42).toRadixString(0), throwsArgumentError); 907 | expect(() => Int64(42).toRadixString(37), throwsArgumentError); 908 | }); 909 | 910 | test('toStringUnsigned', () { 911 | List values = []; 912 | for (int high = 0; high < 16; high++) { 913 | for (int low = -2; low <= 2; low++) { 914 | values.add((Int64(high) << (64 - 4)) + Int64(low)); 915 | } 916 | } 917 | 918 | for (Int64 value in values) { 919 | for (int radix = 2; radix <= 36; radix++) { 920 | String s1 = value.toRadixStringUnsigned(radix); 921 | Int64 v2 = Int64.parseRadix(s1, radix); 922 | expect(v2, value); 923 | String s2 = v2.toRadixStringUnsigned(radix); 924 | expect(s2, s1); 925 | } 926 | String s3 = value.toStringUnsigned(); 927 | Int64 v4 = Int64.parseInt(s3); 928 | expect(v4, value); 929 | String s4 = v4.toStringUnsigned(); 930 | expect(s4, s3); 931 | } 932 | }); 933 | }); 934 | } 935 | -------------------------------------------------------------------------------- /test/int_64_vm_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, 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 | @TestOn('vm') 6 | library; 7 | 8 | import 'package:fixnum/fixnum.dart'; 9 | import 'package:test/test.dart'; 10 | 11 | void main() { 12 | group('conversions', () { 13 | test('toInt', () { 14 | expect(Int64.parseInt('-10000000000000000').toInt(), 15 | same(-10000000000000000)); 16 | expect(Int64.parseInt('-10000000000000001').toInt(), 17 | same(-10000000000000001)); 18 | expect(Int64.parseInt('-10000000000000002').toInt(), 19 | same(-10000000000000002)); 20 | expect(Int64.parseInt('-10000000000000003').toInt(), 21 | same(-10000000000000003)); 22 | expect(Int64.parseInt('-10000000000000004').toInt(), 23 | same(-10000000000000004)); 24 | expect(Int64.parseInt('-10000000000000005').toInt(), 25 | same(-10000000000000005)); 26 | expect(Int64.parseInt('-10000000000000006').toInt(), 27 | same(-10000000000000006)); 28 | expect(Int64.parseInt('-10000000000000007').toInt(), 29 | same(-10000000000000007)); 30 | expect(Int64.parseInt('-10000000000000008').toInt(), 31 | same(-10000000000000008)); 32 | }); 33 | }); 34 | 35 | test('', () { 36 | void check(int n) { 37 | // Sign change should commute with conversion. 38 | expect(-Int64(-n), Int64(n)); 39 | expect(Int64(-n), -Int64(n)); 40 | } 41 | 42 | check(10); 43 | check(1000000000000000000); 44 | check(9223372000000000000); // near Int64.MAX_VALUE, has exact double value 45 | check(9223372036854775807); // Int64.MAX_VALUE, rounds up to -MIN_VALUE 46 | check(-9223372036854775808); // Int64.MIN_VALUE 47 | }); 48 | } 49 | --------------------------------------------------------------------------------