| // Copyright (c) 2019, 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. | 
 |  | 
 | import 'dart:ffi'; | 
 | import 'package:ffi/ffi.dart'; | 
 |  | 
 | main() { | 
 |   print('start main'); | 
 |  | 
 |   { | 
 |     // Basic operation: allocate, get, set, and free. | 
 |     Pointer<Int64> p = calloc(); | 
 |     p.value = 42; | 
 |     int pValue = p.value; | 
 |     print('${p.runtimeType} value: ${pValue}'); | 
 |     calloc.free(p); | 
 |   } | 
 |  | 
 |   { | 
 |     // Undefined behavior before set. | 
 |     Pointer<Int64> p = calloc(); | 
 |     int pValue = p.value; | 
 |     print('If not set, returns garbage: ${pValue}'); | 
 |     calloc.free(p); | 
 |   } | 
 |  | 
 |   { | 
 |     // Pointers can be created from an address. | 
 |     Pointer<Int64> pHelper = calloc(); | 
 |     pHelper.value = 1337; | 
 |  | 
 |     int address = pHelper.address; | 
 |     print('Address: ${address}'); | 
 |  | 
 |     Pointer<Int64> p = Pointer.fromAddress(address); | 
 |     print('${p.runtimeType} value: ${p.value}'); | 
 |  | 
 |     calloc.free(pHelper); | 
 |   } | 
 |  | 
 |   { | 
 |     // Address is zeroed out after free. | 
 |     Pointer<Int64> p = calloc(); | 
 |     calloc.free(p); | 
 |     print('After free, address is zero: ${p.address}'); | 
 |   } | 
 |  | 
 |   { | 
 |     // Allocating too much throws an exception. | 
 |     try { | 
 |       int maxMint = 9223372036854775807; // 2^63 - 1 | 
 |       calloc<Int64>(maxMint); | 
 |     } on Error { | 
 |       print('Expected exception on allocating too much'); | 
 |     } | 
 |     try { | 
 |       int maxInt1_8 = 1152921504606846975; // 2^60 -1 | 
 |       calloc<Int64>(maxInt1_8); | 
 |     } on Error { | 
 |       print('Expected exception on allocating too much'); | 
 |     } | 
 |   } | 
 |  | 
 |   { | 
 |     // Pointers can be cast into another type, | 
 |     // resulting in the corresponding bits read. | 
 |     Pointer<Int64> p1 = calloc(); | 
 |     p1.value = 9223372036854775807; // 2^63 - 1 | 
 |  | 
 |     Pointer<Int32> p2 = p1.cast(); | 
 |     print('${p2.runtimeType} value: ${p2.value}'); // -1 | 
 |  | 
 |     Pointer<Int32> p3 = p2 + 1; | 
 |     print('${p3.runtimeType} value: ${p3.value}'); // 2^31 - 1 | 
 |  | 
 |     calloc.free(p1); | 
 |   } | 
 |  | 
 |   { | 
 |     // Data can be tightly packed in memory. | 
 |     Pointer<Int8> p = calloc(8); | 
 |     for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) { | 
 |       (p + i).value = i * 3; | 
 |     } | 
 |     for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) { | 
 |       print('p.elementAt($i) value: ${(p + i).value}'); | 
 |     } | 
 |     calloc.free(p); | 
 |   } | 
 |  | 
 |   { | 
 |     // Values that don't fit are truncated. | 
 |     Pointer<Int32> p11 = calloc(); | 
 |  | 
 |     p11.value = 9223372036854775807; | 
 |  | 
 |     print(p11); | 
 |  | 
 |     calloc.free(p11); | 
 |   } | 
 |  | 
 |   { | 
 |     // Doubles. | 
 |     Pointer<Double> p = calloc(); | 
 |     p.value = 3.14159265359; | 
 |     print('${p.runtimeType} value: ${p.value}'); | 
 |     p.value = 3.14; | 
 |     print('${p.runtimeType} value: ${p.value}'); | 
 |     calloc.free(p); | 
 |   } | 
 |  | 
 |   { | 
 |     // Floats. | 
 |     Pointer<Float> p = calloc(); | 
 |     p.value = 3.14159265359; | 
 |     print('${p.runtimeType} value: ${p.value}'); | 
 |     p.value = 3.14; | 
 |     print('${p.runtimeType} value: ${p.value}'); | 
 |     calloc.free(p); | 
 |   } | 
 |  | 
 |   { | 
 |     // IntPtr varies in size based on whether the platform is 32 or 64 bit. | 
 |     // Addresses of pointers fit in this size. | 
 |     Pointer<IntPtr> p = calloc(); | 
 |     int p14addr = p.address; | 
 |     p.value = p14addr; | 
 |     int pValue = p.value; | 
 |     print('${p.runtimeType} value: ${pValue}'); | 
 |     calloc.free(p); | 
 |   } | 
 |  | 
 |   { | 
 |     // Void pointers are unsized. | 
 |     // The size of the element it is pointing to is undefined, | 
 |     // they cannot be allocated, read, or written. | 
 |  | 
 |     Pointer<IntPtr> p1 = calloc(); | 
 |     Pointer<Void> p2 = p1.cast(); | 
 |     print('${p2.runtimeType} address: ${p2.address}'); | 
 |  | 
 |     calloc.free(p1); | 
 |   } | 
 |  | 
 |   { | 
 |     // Pointer to a pointer to something. | 
 |     Pointer<Int16> pHelper = calloc(); | 
 |     pHelper.value = 17; | 
 |  | 
 |     Pointer<Pointer<Int16>> p = calloc(); | 
 |  | 
 |     // Storing into a pointer pointer automatically unboxes. | 
 |     p.value = pHelper; | 
 |  | 
 |     // Reading from a pointer pointer automatically boxes. | 
 |     Pointer<Int16> pHelper2 = p.value; | 
 |     print('${pHelper2.runtimeType} value: ${pHelper2.value}'); | 
 |  | 
 |     int pValue = p.value.value; | 
 |     print('${p.runtimeType} value\'s value: ${pValue}'); | 
 |  | 
 |     calloc.free(p); | 
 |     calloc.free(pHelper); | 
 |   } | 
 |  | 
 |   { | 
 |     // The pointer to pointer types must match up. | 
 |     Pointer<Int8> pHelper = calloc(); | 
 |     pHelper.value = 123; | 
 |  | 
 |     Pointer<Pointer<Int16>> p = calloc(); | 
 |  | 
 |     // Trying to store `pHelper` into `p.val` would result in a type mismatch. | 
 |  | 
 |     calloc.free(pHelper); | 
 |     calloc.free(p); | 
 |   } | 
 |  | 
 |   { | 
 |     // `nullptr` points to address 0 in c++. | 
 |     Pointer<Pointer<Int8>> pointerToPointer = calloc(); | 
 |     Pointer<Int8> value = nullptr; | 
 |     pointerToPointer.value = value; | 
 |     value = pointerToPointer.value; | 
 |     print("Loading a pointer to the 0 address is null: ${value}"); | 
 |     calloc.free(pointerToPointer); | 
 |   } | 
 |  | 
 |   { | 
 |     // The toplevel function sizeOf returns element size in bytes. | 
 |     print('sizeOf<Double>(): ${sizeOf<Double>()}'); | 
 |     print('sizeOf<Int16>(): ${sizeOf<Int16>()}'); | 
 |     print('sizeOf<IntPtr>(): ${sizeOf<IntPtr>()}'); | 
 |   } | 
 |  | 
 |   { | 
 |     // With IntPtr pointers, one could manually setup arbitrary data | 
 |     // structures in C memory. | 
 |     // | 
 |     // However, it is advised to use Pointer<Pointer<...>> for that. | 
 |  | 
 |     void createChain(Pointer<IntPtr> head, int length, int value) { | 
 |       if (length == 0) { | 
 |         head.value = value; | 
 |         return; | 
 |       } | 
 |       Pointer<IntPtr> next = calloc<IntPtr>(); | 
 |       head.value = next.address; | 
 |       createChain(next, length - 1, value); | 
 |     } | 
 |  | 
 |     int getChainValue(Pointer<IntPtr> head, int length) { | 
 |       if (length == 0) { | 
 |         return head.value; | 
 |       } | 
 |       Pointer<IntPtr> next = Pointer.fromAddress(head.value); | 
 |       return getChainValue(next, length - 1); | 
 |     } | 
 |  | 
 |     void freeChain(Pointer<IntPtr> head, int length) { | 
 |       Pointer<IntPtr> next = Pointer.fromAddress(head.value); | 
 |       calloc.free(head); | 
 |       if (length == 0) { | 
 |         return; | 
 |       } | 
 |       freeChain(next, length - 1); | 
 |     } | 
 |  | 
 |     int length = 10; | 
 |     Pointer<IntPtr> head = calloc(); | 
 |     createChain(head, length, 512); | 
 |     int tailValue = getChainValue(head, length); | 
 |     print('tailValue: ${tailValue}'); | 
 |     freeChain(head, length); | 
 |   } | 
 |  | 
 |   print("end main"); | 
 | } |