| // Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| // |
| // VMOptions=--deterministic --optimization-counter-threshold=50 |
| |
| import 'dart:ffi'; |
| import 'dart:typed_data'; |
| |
| import 'package:expect/expect.dart'; |
| |
| void main() { |
| for (int i = 0; i < 100; i++) { |
| testStructAllocateDart(); |
| testUseCreateDirectly(); |
| testOffsets(); |
| testOutOfBounds(); |
| testUnion(); |
| } |
| print('done'); |
| } |
| |
| final class Coordinate extends Struct { |
| factory Coordinate({double? x, double? y}) { |
| final result = Struct.create<Coordinate>(); |
| if (x != null) result.x = x; |
| if (y != null) result.y = y; |
| return result; |
| } |
| |
| factory Coordinate.fromTypedList(TypedData typedList, [int offset = 0]) { |
| return Struct.create<Coordinate>(typedList, offset); |
| } |
| |
| @Double() |
| external double x; |
| |
| @Double() |
| external double y; |
| } |
| |
| void testStructAllocateDart() { |
| final c1 = Coordinate() |
| ..x = 10.0 |
| ..y = 20.0; |
| Expect.equals(10.0, c1.x); |
| Expect.equals(20.0, c1.y); |
| |
| final typedList = Float64List(2); |
| typedList[0] = 30.0; |
| typedList[1] = 40.0; |
| final c2 = Coordinate.fromTypedList(typedList); |
| Expect.equals(30.0, c2.x); |
| Expect.equals(40.0, c2.y); |
| |
| final c3 = Coordinate(x: 50.0, y: 60); |
| Expect.equals(50.0, c3.x); |
| Expect.equals(60.0, c3.y); |
| } |
| |
| final class SomeStruct extends Struct { |
| @Double() |
| external double x; |
| |
| @Double() |
| external double y; |
| } |
| |
| void testUseCreateDirectly() { |
| final c1 = Struct.create<SomeStruct>() |
| ..x = 10.0 |
| ..y = 20.0; |
| Expect.equals(10.0, c1.x); |
| Expect.equals(20.0, c1.y); |
| } |
| |
| void testOffsets() { |
| const length = 100; |
| final typedList = Float64List(length * 2); |
| for (int i = 0; i < length * 2; i++) { |
| typedList[i] = i.toDouble(); |
| } |
| final size = sizeOf<Coordinate>(); |
| var structs = [ |
| for (var i = 0; i < length; i++) |
| Coordinate.fromTypedList( |
| typedList, |
| i * size ~/ typedList.elementSizeInBytes, |
| ) |
| ]; |
| for (int i = 0; i < length; i++) { |
| Expect.approxEquals(structs[i].x, 2 * i); |
| Expect.approxEquals(structs[i].y, 2 * i + 1); |
| } |
| } |
| |
| void testOutOfBounds() { |
| final typedList = Uint8List(3 * sizeOf<Double>()); |
| final c1 = Coordinate.fromTypedList(typedList) |
| ..x = 4 |
| ..y = 6; |
| final view = Uint8List.view(typedList.buffer, 16); |
| Expect.equals(8, view.lengthInBytes); |
| Expect.throws<RangeError>(() { |
| Coordinate.fromTypedList(view) |
| ..x = 6 |
| ..y = 8; |
| }); |
| Expect.throws<RangeError>(() { |
| Coordinate.fromTypedList(typedList, 16) |
| ..x = 6 |
| ..y = 8; |
| }); |
| Expect.throws<RangeError>(() { |
| // Negative offsets are not allowed. One should access the ByteBuffer to |
| // apply a negative offset if this is wanted. |
| Coordinate.fromTypedList(view, -1) |
| ..x = 6 |
| ..y = 8; |
| }); |
| Expect.approxEquals(c1.x, 4); |
| Expect.approxEquals(c1.y, 6); |
| } |
| |
| final class MyUnion extends Union { |
| @Int32() |
| external int a; |
| |
| @Float() |
| external double b; |
| |
| /// Allocates a new [TypedData] of size `sizeOf<MyUnion>()` and wraps it in |
| /// [MyUnion]. |
| factory MyUnion.a(int a) { |
| return Union.create<MyUnion>()..a = a; |
| } |
| |
| /// Allocates a new [TypedData] of size `sizeOf<MyUnion>()` and wraps it in |
| /// [MyUnion]. |
| factory MyUnion.b(double b) { |
| return Union.create<MyUnion>()..b = b; |
| } |
| |
| /// Constructs a [MyUnion] view on [typedList]. |
| factory MyUnion.fromTypedData(TypedData typedList) { |
| return Union.create<MyUnion>(typedList); |
| } |
| } |
| |
| final class MyUnion2 extends Union { |
| @Int32() |
| external int a; |
| |
| @Float() |
| external double b; |
| } |
| |
| void testUnion() { |
| final myUnion = MyUnion.a(123); |
| Expect.equals(123, myUnion.a); |
| Expect.approxEquals(1.723597111119525e-43, myUnion.b); |
| |
| final myUnion2 = Union.create<MyUnion2>()..a = 123; |
| Expect.equals(123, myUnion2.a); |
| Expect.approxEquals(1.723597111119525e-43, myUnion2.b); |
| } |