|
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