OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2013, 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 // Tests typed-data buffer classes. |
| 6 |
| 7 import "package:collection_helpers/all.dart"; |
| 8 import "package:unittest/unittest.dart"; |
| 9 import "dart:typed_data"; |
| 10 |
| 11 main() { |
| 12 testUint(8, (l) => new Uint8Buffer(l)); |
| 13 testInt(8, (l) => new Int8Buffer(l)); |
| 14 test("Uint8ClampedBuffer", () { |
| 15 testIntBuffer(8, 0, 255, (l) => new Uint8ClampedBuffer(l), clampUint8); |
| 16 }); |
| 17 testUint(16, (l) => new Uint16Buffer(l)); |
| 18 testInt(16, (l) => new Int16Buffer(l)); |
| 19 testUint(32, (l) => new Uint32Buffer(l)); /// 01: ok |
| 20 testInt(32, (l) => new Int32Buffer(l)); |
| 21 testUint(64, (l) => new Uint64Buffer(l)); /// 01: continued |
| 22 testInt(64, (l) => new Int64Buffer(l)); /// 01: continued |
| 23 |
| 24 testInt32x4Buffer(intSamples); |
| 25 |
| 26 List roundedFloatSamples = floatSamples.map(roundToFloat).toList(); |
| 27 testFloatBuffer(32, roundedFloatSamples, |
| 28 () => new Float32Buffer(), |
| 29 roundToFloat); |
| 30 testFloatBuffer(64, doubleSamples, () => new Float64Buffer(), (x) => x); |
| 31 |
| 32 testFloat32x4Buffer(roundedFloatSamples); |
| 33 } |
| 34 |
| 35 double roundToFloat(double value) { |
| 36 return (new Float32List(1)..[0] = value)[0]; |
| 37 } |
| 38 |
| 39 typedef int Rounder(int value); |
| 40 |
| 41 Rounder roundUint(bits) { |
| 42 int halfbits = (1 << (bits ~/ 2)) - 1; |
| 43 int mask = halfbits | (halfbits << (bits ~/ 2)); |
| 44 return (int x) => x & mask; |
| 45 } |
| 46 |
| 47 Rounder roundInt(bits) { |
| 48 int highBit = 1 << (bits - 1); |
| 49 int mask = highBit - 1; |
| 50 return (int x) => (x & mask) - (x & highBit); |
| 51 } |
| 52 |
| 53 int clampUint8(x) => x < 0 ? 0 : x > 255 ? 255 : x; |
| 54 |
| 55 void testUint(int bits, var buffer) { |
| 56 int min = 0; |
| 57 Function round = roundUint(bits); |
| 58 int max = round(-1); |
| 59 test("Uint${bits}Buffer", () { |
| 60 testIntBuffer(bits, min, max, buffer, round); |
| 61 }); |
| 62 } |
| 63 |
| 64 void testInt(int bits, var buffer) { |
| 65 int min = -(1 << (bits - 1)); |
| 66 int max = -(min + 1); |
| 67 test("Int${bits}Buffer", () { |
| 68 testIntBuffer(bits, min, max, buffer, roundInt(bits)); |
| 69 }); |
| 70 } |
| 71 |
| 72 const List<int> intSamples = const [ |
| 73 0x10000000000000001, |
| 74 0x10000000000000000, // 2^64 |
| 75 0x0ffffffffffffffff, |
| 76 0xaaaaaaaaaaaaaaaa, |
| 77 0x8000000000000001, |
| 78 0x8000000000000000, // 2^63 |
| 79 0x7fffffffffffffff, |
| 80 0x5555555555555555, |
| 81 0x100000001, |
| 82 0x100000000, // 2^32 |
| 83 0x0ffffffff, |
| 84 0xaaaaaaaa, |
| 85 0x80000001, |
| 86 0x80000000, // 2^31 |
| 87 0x7fffffff, |
| 88 0x55555555, |
| 89 0x10001, |
| 90 0x10000, // 2^16 |
| 91 0x0ffff, |
| 92 0xaaaa, |
| 93 0x8001, |
| 94 0x8000, // 2^15 |
| 95 0x7fff, |
| 96 0x5555, |
| 97 0x101, |
| 98 0x100, // 2^8 |
| 99 0x0ff, |
| 100 0xaa, |
| 101 0x81, |
| 102 0x80, // 2^7 |
| 103 0x7f, |
| 104 0x55, |
| 105 0x02, |
| 106 0x01, |
| 107 0x00 |
| 108 ]; |
| 109 |
| 110 // Takes bit-size, min value, max value, function to create a buffer, and |
| 111 // the rounding that is applied when storing values outside the valid range |
| 112 // into the buffer. |
| 113 void testIntBuffer(int bits, int min, int max, |
| 114 create(int length), |
| 115 int round(int)) { |
| 116 assert(round(min) == min); |
| 117 assert(round(max) == max); |
| 118 // All int buffers default to the value 0. |
| 119 var buffer = create(0); |
| 120 List<int> list = buffer; // Check the type. |
| 121 expect(buffer.length, equals(0)); |
| 122 var bytes = bits ~/ 8; |
| 123 |
| 124 expect(buffer.elementSizeInBytes, equals(bytes)); |
| 125 expect(buffer.lengthInBytes, equals(0)); |
| 126 expect(buffer.offsetInBytes, equals(0)); |
| 127 |
| 128 buffer.add(min); |
| 129 expect(buffer.length, equals(1)); |
| 130 expect(buffer[0], equals(min)); |
| 131 |
| 132 expect(buffer.elementSizeInBytes, equals(bytes)); |
| 133 expect(buffer.lengthInBytes, equals(bytes)); |
| 134 expect(buffer.offsetInBytes, equals(0)); |
| 135 |
| 136 buffer.length = 0; |
| 137 expect(buffer.length, equals(0)); |
| 138 |
| 139 List samples = intSamples.toList()..addAll(intSamples.map((x) => -x)); |
| 140 for (int value in samples) { |
| 141 int length = buffer.length; |
| 142 buffer.add(value); |
| 143 expect(buffer.length, equals(length + 1)); |
| 144 expect(buffer[length], equals(round(value))); |
| 145 } |
| 146 buffer.addAll(samples); // Add all the values at once. |
| 147 for (int i = 0; i < samples.length; i++) { |
| 148 expect(buffer[samples.length + i], equals(buffer[i])); |
| 149 } |
| 150 |
| 151 // Remove range works and changes length. |
| 152 buffer.removeRange(samples.length, buffer.length); |
| 153 expect(buffer.length, equals(samples.length)); |
| 154 |
| 155 // Both values are in `samples`, but equality is performed without rounding. |
| 156 expect(buffer.contains(min - 1), isFalse); |
| 157 expect(buffer.contains(max + 1), isFalse); |
| 158 expect(buffer.contains(round(min - 1)), isTrue); |
| 159 expect(buffer.contains(round(max + 1)), isTrue); |
| 160 |
| 161 // Accessing the underlying buffer works. |
| 162 buffer.length = 2; |
| 163 buffer[0] = min; |
| 164 buffer[1] = max; |
| 165 var byteBuffer = new Uint8List.view(buffer.buffer); |
| 166 int byteSize = buffer.elementSizeInBytes; |
| 167 for (int i = 0; i < byteSize; i++) { |
| 168 int tmp = byteBuffer[i]; |
| 169 byteBuffer[i] = byteBuffer[byteSize + i]; |
| 170 byteBuffer[byteSize + i] = tmp; |
| 171 } |
| 172 expect(buffer[0], equals(max)); |
| 173 expect(buffer[1], equals(min)); |
| 174 } |
| 175 |
| 176 const List doubleSamples = const [ |
| 177 0.0, |
| 178 5e-324, // Minimal denormal value. |
| 179 2.225073858507201e-308, // Maximal denormal value. |
| 180 2.2250738585072014e-308, // Minimal normal value. |
| 181 0.9999999999999999, // Maximum value < 1. |
| 182 1.0, |
| 183 1.0000000000000002, // Minimum value > 1. |
| 184 4294967295.0, // 2^32 -1. |
| 185 4294967296.0, // 2^32. |
| 186 4503599627370495.5, // Maximal fractional value. |
| 187 9007199254740992.0, // Maximal exact value (adding one gets lost). |
| 188 1.7976931348623157e+308, // Maximal value. |
| 189 1.0/0.0, // Infinity. |
| 190 0.0/0.0, // NaN. |
| 191 0.49999999999999994, // Round-traps 1-3 (adding 0.5 and rounding towards |
| 192 4503599627370497.0, // minus infinity will not be the same as rounding |
| 193 9007199254740991.0 // to nearest with 0.5 rounding up). |
| 194 ]; |
| 195 |
| 196 const List floatSamples = const [ |
| 197 0.0, |
| 198 1.4e-45, // Minimal denormal value. |
| 199 1.1754942E-38, // Maximal denormal value. |
| 200 1.17549435E-38, // Minimal normal value. |
| 201 0.99999994, // Maximal value < 1. |
| 202 1.0, |
| 203 1.0000001, // Minimal value > 1. |
| 204 8388607.5, // Maximal fractional value. |
| 205 16777216.0, // Maximal exact value. |
| 206 3.4028235e+38, // Maximal value. |
| 207 1.0/0.0, // Infinity. |
| 208 0.0/0.0, // NaN. |
| 209 0.99999994, // Round traps 1-3. |
| 210 8388609.0, |
| 211 16777215.0 |
| 212 ]; |
| 213 |
| 214 void doubleEqual(x, y) { |
| 215 if (y.isNaN) { |
| 216 expect(x.isNaN, isTrue); |
| 217 } else { |
| 218 if (x != y) { |
| 219 } |
| 220 expect(x, equals(y)); |
| 221 } |
| 222 } |
| 223 |
| 224 testFloatBuffer(int bitSize, List samples, create(), double round(double v)) { |
| 225 test("Float${bitSize}Buffer", () { |
| 226 var buffer = create(); |
| 227 List<double> list = buffer; // Test type. |
| 228 int byteSize = bitSize ~/ 8; |
| 229 |
| 230 expect(buffer.length, equals(0)); |
| 231 buffer.add(0.0); |
| 232 expect(buffer.length, equals(1)); |
| 233 expect(buffer.removeLast(), equals(0.0)); |
| 234 expect(buffer.length, equals(0)); |
| 235 |
| 236 for (double value in samples) { |
| 237 buffer.add(value); |
| 238 doubleEqual(buffer[buffer.length - 1], round(value)); |
| 239 } |
| 240 expect(buffer.length, equals(samples.length)); |
| 241 |
| 242 buffer.addAll(samples); |
| 243 expect(buffer.length, equals(samples.length * 2)); |
| 244 for (int i = 0; i < samples.length; i++) { |
| 245 doubleEqual(buffer[i], buffer[samples.length + i]); |
| 246 } |
| 247 |
| 248 buffer.removeRange(samples.length, buffer.length); |
| 249 expect(buffer.length, equals(samples.length)); |
| 250 |
| 251 buffer.insertAll(0, samples); |
| 252 expect(buffer.length, equals(samples.length * 2)); |
| 253 for (int i = 0; i < samples.length; i++) { |
| 254 doubleEqual(buffer[i], buffer[samples.length + i]); |
| 255 } |
| 256 |
| 257 buffer.length = samples.length; |
| 258 expect(buffer.length, equals(samples.length)); |
| 259 |
| 260 // TypedData. |
| 261 expect(buffer.elementSizeInBytes, equals(byteSize)); |
| 262 expect(buffer.lengthInBytes, equals(byteSize * buffer.length)); |
| 263 expect(buffer.offsetInBytes, equals(0)); |
| 264 |
| 265 // Accessing the buffer works. |
| 266 // Accessing the underlying buffer works. |
| 267 buffer.length = 2; |
| 268 buffer[0] = samples[0]; |
| 269 buffer[1] = samples[1]; |
| 270 var bytes = new Uint8List.view(buffer.buffer); |
| 271 for (int i = 0; i < byteSize; i++) { |
| 272 int tmp = bytes[i]; |
| 273 bytes[i] = bytes[byteSize + i]; |
| 274 bytes[byteSize + i] = tmp; |
| 275 } |
| 276 doubleEqual(buffer[0], round(samples[1])); |
| 277 doubleEqual(buffer[1], round(samples[0])); |
| 278 }); |
| 279 } |
| 280 |
| 281 testFloat32x4Buffer(List floatSamples) { |
| 282 List float4Samples = []; |
| 283 for (int i = 0; i < floatSamples.length - 3; i++) { |
| 284 float4Samples.add(new Float32x4(floatSamples[i], |
| 285 floatSamples[i + 1], |
| 286 floatSamples[i + 2], |
| 287 floatSamples[i + 3])); |
| 288 } |
| 289 |
| 290 void floatEquals(x, y) { |
| 291 if (y.isNaN) { |
| 292 expect(x.isNaN, isTrue); |
| 293 } else { |
| 294 expect(x, equals(y)); |
| 295 } |
| 296 } |
| 297 |
| 298 void x4Equals(Float32x4 x, Float32x4 y) { |
| 299 floatEquals(x.x, y.x); |
| 300 floatEquals(x.y, y.y); |
| 301 floatEquals(x.z, y.z); |
| 302 floatEquals(x.w, y.w); |
| 303 } |
| 304 |
| 305 test("Float32x4Buffer", () { |
| 306 var buffer = new Float32x4Buffer(5); |
| 307 List<Float32x4> list = buffer; |
| 308 |
| 309 expect(buffer.length, equals(5)); |
| 310 expect(buffer.elementSizeInBytes, equals(128 ~/ 8)); |
| 311 expect(buffer.lengthInBytes, equals(5 * 128 ~/ 8)); |
| 312 expect(buffer.offsetInBytes, equals(0)); |
| 313 |
| 314 x4Equals(buffer[0], new Float32x4.zero()); |
| 315 buffer.length = 0; |
| 316 expect(buffer.length, equals(0)); |
| 317 |
| 318 for (var sample in float4Samples) { |
| 319 buffer.add(sample); |
| 320 x4Equals(buffer[buffer.length - 1], sample); |
| 321 } |
| 322 expect(buffer.length, equals(float4Samples.length)); |
| 323 |
| 324 buffer.addAll(float4Samples); |
| 325 expect(buffer.length, equals(float4Samples.length * 2)); |
| 326 for (int i = 0; i < float4Samples.length; i++) { |
| 327 x4Equals(buffer[i], buffer[float4Samples.length + i]); |
| 328 } |
| 329 |
| 330 buffer.removeRange(4, 4 + float4Samples.length); |
| 331 for (int i = 0; i < float4Samples.length; i++) { |
| 332 x4Equals(buffer[i], float4Samples[i]); |
| 333 } |
| 334 |
| 335 // Test underlying buffer. |
| 336 buffer.length = 1; |
| 337 buffer[0] = float4Samples[0]; // Does not contain NaN. |
| 338 |
| 339 Float32List floats = new Float32List.view(buffer.buffer); |
| 340 expect(floats[0], equals(buffer[0].x)); |
| 341 expect(floats[1], equals(buffer[0].y)); |
| 342 expect(floats[2], equals(buffer[0].z)); |
| 343 expect(floats[3], equals(buffer[0].w)); |
| 344 }); |
| 345 } |
| 346 |
| 347 void testInt32x4Buffer(intSamples) { |
| 348 test("Int32x4Buffer", () { |
| 349 Function round = roundInt(32); |
| 350 int bits = 128; |
| 351 int bytes = 128 ~/ 8; |
| 352 Matcher equals32x4(Int32x4 expected) => new MatchesInt32x4(expected); |
| 353 |
| 354 var buffer = new Int32x4Buffer(0); |
| 355 List<Int32x4> list = buffer; // It's a List. |
| 356 expect(buffer.length, equals(0)); |
| 357 |
| 358 expect(buffer.elementSizeInBytes, equals(bytes)); |
| 359 expect(buffer.lengthInBytes, equals(0)); |
| 360 expect(buffer.offsetInBytes, equals(0)); |
| 361 |
| 362 Int32x4 sample = new Int32x4(-0x80000000, -1, 0, 0x7fffffff); |
| 363 buffer.add(sample); |
| 364 expect(buffer.length, equals(1)); |
| 365 expect(buffer[0], equals32x4(sample)); |
| 366 |
| 367 expect(buffer.elementSizeInBytes, equals(bytes)); |
| 368 expect(buffer.lengthInBytes, equals(bytes)); |
| 369 expect(buffer.offsetInBytes, equals(0)); |
| 370 |
| 371 buffer.length = 0; |
| 372 expect(buffer.length, equals(0)); |
| 373 |
| 374 var samples = intSamples |
| 375 .where((value) => value == round(value)) // Issue 15130 |
| 376 .map((value) => new Int32x4(value, -value, ~value, ~-value)) |
| 377 .toList(); |
| 378 for (Int32x4 value in samples) { |
| 379 int length = buffer.length; |
| 380 buffer.add(value); |
| 381 expect(buffer.length, equals(length + 1)); |
| 382 expect(buffer[length], equals32x4(value)); |
| 383 } |
| 384 |
| 385 buffer.addAll(samples); // Add all the values at once. |
| 386 for (int i = 0; i < samples.length; i++) { |
| 387 expect(buffer[samples.length + i], equals32x4(buffer[i])); |
| 388 } |
| 389 |
| 390 // Remove range works and changes length. |
| 391 buffer.removeRange(samples.length, buffer.length); |
| 392 expect(buffer.length, equals(samples.length)); |
| 393 |
| 394 // Accessing the underlying buffer works. |
| 395 buffer.length = 2; |
| 396 buffer[0] = new Int32x4(-80000000, 0x7fffffff, 0, -1); |
| 397 var byteBuffer = new Uint8List.view(buffer.buffer); |
| 398 int halfBytes = bytes ~/ 2; |
| 399 for (int i = 0; i < halfBytes; i++) { |
| 400 int tmp = byteBuffer[i]; |
| 401 byteBuffer[i] = byteBuffer[halfBytes + i]; |
| 402 byteBuffer[halfBytes + i] = tmp; |
| 403 } |
| 404 var result = new Int32x4(0, -1, -80000000, 0x7fffffff); |
| 405 expect(buffer[0], equals32x4(result)); |
| 406 }); |
| 407 } |
| 408 |
| 409 class MatchesInt32x4 extends Matcher { |
| 410 Int32x4 result; |
| 411 MatchesInt32x4(this.result); |
| 412 bool matches(item, Map matchState) { |
| 413 if (item is! Int32x4) return false; |
| 414 Int32x4 value = item; |
| 415 return result.x == value.x && result.y == value.y && |
| 416 result.z == value.z && result.w == value.w; |
| 417 } |
| 418 |
| 419 Description describe(Description description) => |
| 420 description.add('Int32x4.=='); |
| 421 } |
OLD | NEW |