|
8 | 8 | package kotlinx.io |
9 | 9 |
|
10 | 10 | import kotlinx.cinterop.* |
| 11 | +import kotlinx.io.unsafe.UnsafeBufferOperations |
| 12 | +import kotlinx.io.unsafe.withData |
11 | 13 | import platform.Foundation.NSData |
12 | 14 | import platform.Foundation.create |
13 | 15 | import platform.Foundation.data |
14 | 16 | import platform.darwin.NSUIntegerMax |
15 | 17 | import platform.posix.* |
16 | 18 |
|
17 | | -@OptIn(ExperimentalForeignApi::class) |
| 19 | +@OptIn(ExperimentalForeignApi::class, UnsafeIoApi::class) |
18 | 20 | internal fun Buffer.write(source: CPointer<uint8_tVar>, maxLength: Int) { |
19 | 21 | require(maxLength >= 0) { "maxLength ($maxLength) must not be negative" } |
20 | 22 |
|
21 | 23 | var currentOffset = 0 |
22 | 24 | while (currentOffset < maxLength) { |
23 | | - val tail = writableSegment(1) |
24 | | - |
25 | | - val toCopy = minOf(maxLength - currentOffset, Segment.SIZE - tail.limit) |
26 | | - tail.data.usePinned { |
27 | | - memcpy(it.addressOf(tail.limit), source + currentOffset, toCopy.convert()) |
| 25 | + UnsafeBufferOperations.writeToTail(this, 1) { data, pos, limit -> |
| 26 | + val toCopy = minOf(maxLength - currentOffset, limit - pos) |
| 27 | + data.usePinned { |
| 28 | + memcpy(it.addressOf(pos), source + currentOffset, toCopy.convert()) |
| 29 | + } |
| 30 | + currentOffset += toCopy |
| 31 | + toCopy |
28 | 32 | } |
29 | | - |
30 | | - currentOffset += toCopy |
31 | | - tail.limit += toCopy |
32 | 33 | } |
33 | | - this.sizeMut += maxLength |
34 | 34 | } |
35 | 35 |
|
| 36 | +@OptIn(UnsafeIoApi::class) |
36 | 37 | internal fun Buffer.readAtMostTo(sink: CPointer<uint8_tVar>, maxLength: Int): Int { |
37 | 38 | require(maxLength >= 0) { "maxLength ($maxLength) must not be negative" } |
38 | 39 |
|
39 | | - val s = head ?: return 0 |
40 | | - val toCopy = minOf(maxLength, s.limit - s.pos) |
41 | | - s.data.usePinned { |
42 | | - memcpy(sink, it.addressOf(s.pos), toCopy.convert()) |
43 | | - } |
44 | | - |
45 | | - s.pos += toCopy |
46 | | - this.sizeMut -= toCopy.toLong() |
47 | | - |
48 | | - if (s.pos == s.limit) { |
49 | | - recycleHead() |
| 40 | + var toCopy = 0 |
| 41 | + UnsafeBufferOperations.readFromHead(this) { data, pos, limit -> |
| 42 | + toCopy = minOf(maxLength, limit - pos) |
| 43 | + data.usePinned { |
| 44 | + memcpy(sink, it.addressOf(pos), toCopy.convert()) |
| 45 | + } |
| 46 | + toCopy |
50 | 47 | } |
51 | 48 |
|
52 | 49 | return toCopy |
53 | 50 | } |
54 | 51 |
|
55 | | -@OptIn(BetaInteropApi::class) |
| 52 | +@OptIn(BetaInteropApi::class, UnsafeIoApi::class) |
56 | 53 | internal fun Buffer.snapshotAsNSData(): NSData { |
57 | 54 | if (size == 0L) return NSData.data() |
58 | 55 |
|
59 | 56 | check(size.toULong() <= NSUIntegerMax) { "Buffer is too long ($size) to be converted into NSData." } |
60 | 57 |
|
61 | 58 | val bytes = malloc(size.convert())?.reinterpret<uint8_tVar>() |
62 | 59 | ?: throw Error("malloc failed: ${strerror(errno)?.toKString()}") |
63 | | - var curr = head |
64 | | - var index = 0 |
65 | | - do { |
66 | | - check(curr != null) { "Current segment is null" } |
67 | | - val pos = curr.pos |
68 | | - val length = curr.limit - pos |
69 | | - curr.data.usePinned { |
70 | | - memcpy(bytes + index, it.addressOf(pos), length.convert()) |
| 60 | + |
| 61 | + UnsafeBufferOperations.iterate(this) { ctx, head -> |
| 62 | + var curr: Segment? = head |
| 63 | + var index = 0 |
| 64 | + while (curr != null) { |
| 65 | + val segment: Segment = curr |
| 66 | + ctx.withData(segment) { data, pos, limit -> |
| 67 | + val length = limit - pos |
| 68 | + data.usePinned { |
| 69 | + memcpy(bytes + index, it.addressOf(pos), length.convert()) |
| 70 | + } |
| 71 | + index += length |
| 72 | + } |
| 73 | + curr = ctx.next(segment) |
71 | 74 | } |
72 | | - curr = curr.next |
73 | | - index += length |
74 | | - } while (curr != null) |
| 75 | + } |
75 | 76 | return NSData.create(bytesNoCopy = bytes, length = size.convert()) |
76 | 77 | } |
0 commit comments