I am having difficulties in indexing the flexible array field of a C struct
imported into Swift
:
struct Packet {
unsigned long size;
char bytes [];
};
Packet Details
// Packet.h
#ifndef Packet_h
#define Packet_h
struct Packet {
unsigned long size;
char bytes []; // flexible array member
};
typedef struct Packet Packet;
Packet * Packet_allocate (unsigned long size);
void Packet_print (Packet *);
#endif
// Packet.c
Packet * Packet_allocate (unsigned long size) {
Packet w;
Packet * ptr = malloc (sizeof (Packet) + size * sizeof (w.bytes [0]));
assert (ptr);
ptr->size = size;
ptr->bytes [0] = 2;
ptr->bytes [size - 1] = 3;
return ptr;
}
void Packet_print (Packet * ptr) {
printf ("Packet: size: %lu\n", ptr->size);
for (int x = 0; x < ptr->size; ++x) {
printf ("\tbytes [%d]: %d\n", x, ((int) (ptr->bytes [x])));
}
}
This code provides the indexing functionality. (Originally provided by @scanon, with a warning.)
Packet+Index.swift
// Packet+Index.swift
extension Packet: RandomAccessCollection, MutableCollection {
public var startIndex: Int { 0 }
public var endIndex : Int { Int (self.size) }
public subscript (index: Int) -> UInt8 {
@_transparent
get {
precondition (indices.contains (index))
return withUnsafeBytes (of: self) {
$0 [MemoryLayout <Self>.size + index]
}
}
@_transparent
set {
precondition (indices.contains (index))
withUnsafeMutableBytes (of: &self) {
$0 [MemoryLayout <Self>.size + index] = newValue
}
}
}
}
I get a Thread 1: Fatal error
when I run the following code.
static func indexPacket () {
let u : UnsafeMutablePointer <Packet> = Packet_allocate (UInt (16))
Packet_print (u);
var packet = u.pointee
print (packet [0]) // <-- Thread 1: Fatal error
print (packet [Int (packet.size) - 1]) // <-- Thread 1: Fatal error
packet [0] = 32 // <-- Thread 1: Fatal error
packet [Int(packet.size) - 1] = 64 // <-- Thread 1: Fatal error
print ()
Packet_print (u);
}
The crash occurs in this code:
extension Packet: RandomAccessCollection, MutableCollection {
public var startIndex: Int { 0 }
public var endIndex : Int { Int (self.size) }
public subscript (index: Int) -> UInt8 {
@_transparent
get {
precondition (indices.contains (index))
return withUnsafeBytes (of: self) {
$0 [MemoryLayout <Self>.size + index] // <-- Thread 1: Fatal error
}
}
@_transparent
set {
precondition (indices.contains (index))
withUnsafeMutableBytes (of: &self) {
$0 [MemoryLayout <Self>.size + index] = newValue // <-- Thread 1: Fatal error
}
}
}
}
Although, thinking in C mode, I understand the above code, I am not sure whether it is correct or not.
Can anyone help please?
Thank you.