| // 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 + $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"); | |
| } |