0
# Memory Management
1
2
Low-level memory operations providing direct byte access, primitive type loading/storing, and platform-optimized memory utilities.
3
4
## Capabilities
5
6
### Memory Class
7
8
Platform-specific linear range of bytes providing direct memory access with bounds checking and platform optimizations.
9
10
```kotlin { .api }
11
/**
12
* Represents a linear range of bytes in memory.
13
* Platform-specific implementation optimized for the target architecture.
14
*/
15
expect class Memory {
16
/** Total size of this memory region in bytes */
17
val size: Long
18
19
/** Size as 32-bit integer (throws if size > Int.MAX_VALUE) */
20
val size32: Int
21
22
/**
23
* Load a byte value from the specified index.
24
* @param index byte offset from start of memory region
25
* @return byte value at the index
26
* @throws IndexOutOfBoundsException if index is out of bounds
27
*/
28
fun loadAt(index: Int): Byte
29
fun loadAt(index: Long): Byte
30
31
/**
32
* Store a byte value at the specified index.
33
* @param index byte offset from start of memory region
34
* @param value byte value to store
35
* @throws IndexOutOfBoundsException if index is out of bounds
36
*/
37
fun storeAt(index: Int, value: Byte)
38
fun storeAt(index: Long, value: Byte)
39
40
/**
41
* Create a subrange view of this memory region.
42
* Changes to the slice affect the original memory.
43
* @param offset starting byte offset
44
* @param length size of the slice in bytes
45
* @return Memory view of the specified range
46
*/
47
fun slice(offset: Int, length: Int): Memory
48
fun slice(offset: Long, length: Long): Memory
49
50
/**
51
* Copy bytes from this memory to another memory region.
52
* @param destination target memory region
53
* @param offset source offset in this memory
54
* @param length number of bytes to copy
55
* @param destinationOffset target offset in destination memory
56
*/
57
fun copyTo(destination: Memory, offset: Int, length: Int, destinationOffset: Int)
58
fun copyTo(destination: Memory, offset: Long, length: Long, destinationOffset: Long)
59
60
/**
61
* Copy bytes from this memory to a byte array.
62
* @param destination target byte array
63
* @param offset source offset in this memory
64
* @param length number of bytes to copy
65
* @param destinationOffset target offset in destination array
66
*/
67
fun copyTo(destination: ByteArray, offset: Int, length: Int, destinationOffset: Int)
68
69
/**
70
* Array-like access operator for reading bytes.
71
* @param index byte offset from start
72
* @return byte value at index
73
*/
74
operator fun get(index: Int): Byte
75
operator fun get(index: Long): Byte
76
77
/**
78
* Array-like assignment operator for storing bytes.
79
* @param index byte offset from start
80
* @param value byte value to store
81
*/
82
operator fun set(index: Int, value: Byte)
83
operator fun set(index: Long, value: Byte)
84
85
/**
86
* Fill a range of memory with a specific byte value.
87
* @param offset starting offset to fill
88
* @param count number of bytes to fill
89
* @param value byte value to fill with
90
*/
91
fun fill(offset: Int, count: Int, value: Byte)
92
fun fill(offset: Long, count: Long, value: Byte)
93
94
companion object {
95
/** Empty memory region with zero size */
96
val Empty: Memory
97
}
98
}
99
```
100
101
**Usage Examples:**
102
103
```kotlin
104
import io.ktor.utils.io.bits.*
105
106
// Use temporary memory allocation
107
withMemory(1024) { memory ->
108
// Basic byte operations
109
memory[0] = 0xFF.toByte()
110
memory[1] = 0x42.toByte()
111
val firstByte = memory[0]
112
val secondByte = memory.loadAt(1)
113
114
// Fill memory with pattern
115
memory.fill(0, 100, 0xAA.toByte())
116
117
// Create slices
118
val slice = memory.slice(10, 50) // 50 bytes starting at offset 10
119
slice[0] = 0x99.toByte() // Modifies original memory at offset 10
120
121
// Copy to byte array
122
val array = ByteArray(20)
123
memory.copyTo(array, offset = 0, length = 20, destinationOffset = 0)
124
}
125
126
// Copy operations between temporary memory regions
127
withMemory(100) { source ->
128
withMemory(100) { dest ->
129
source.copyTo(dest, offset = 0, length = 50, destinationOffset = 25)
130
}
131
}
132
```
133
134
### Memory Primitive Operations
135
136
Extension functions for loading and storing primitive types from Memory with big-endian byte order.
137
138
```kotlin { .api }
139
/**
140
* Load a 16-bit signed short value in big-endian byte order.
141
* @param offset byte offset in memory
142
* @return short value
143
*/
144
fun Memory.loadShortAt(offset: Int): Short
145
fun Memory.loadShortAt(offset: Long): Short
146
147
/**
148
* Store a 16-bit signed short value in big-endian byte order.
149
* @param offset byte offset in memory
150
* @param value short value to store
151
*/
152
fun Memory.storeShortAt(offset: Int, value: Short)
153
fun Memory.storeShortAt(offset: Long, value: Short)
154
155
/**
156
* Load a 32-bit signed int value in big-endian byte order.
157
* @param offset byte offset in memory
158
* @return int value
159
*/
160
fun Memory.loadIntAt(offset: Int): Int
161
fun Memory.loadIntAt(offset: Long): Int
162
163
/**
164
* Store a 32-bit signed int value in big-endian byte order.
165
* @param offset byte offset in memory
166
* @param value int value to store
167
*/
168
fun Memory.storeIntAt(offset: Int, value: Int)
169
fun Memory.storeIntAt(offset: Long, value: Int)
170
171
/**
172
* Load a 64-bit signed long value in big-endian byte order.
173
* @param offset byte offset in memory
174
* @return long value
175
*/
176
fun Memory.loadLongAt(offset: Int): Long
177
fun Memory.loadLongAt(offset: Long): Long
178
179
/**
180
* Store a 64-bit signed long value in big-endian byte order.
181
* @param offset byte offset in memory
182
* @param value long value to store
183
*/
184
fun Memory.storeLongAt(offset: Int, value: Long)
185
fun Memory.storeLongAt(offset: Long, value: Long)
186
187
/**
188
* Load an unsigned 16-bit short value.
189
* @param offset byte offset in memory
190
* @return unsigned short value
191
*/
192
fun Memory.loadUShortAt(offset: Int): UShort
193
fun Memory.loadUShortAt(offset: Long): UShort
194
195
/**
196
* Store an unsigned 16-bit short value.
197
* @param offset byte offset in memory
198
* @param value unsigned short value to store
199
*/
200
fun Memory.storeUShortAt(offset: Int, value: UShort)
201
fun Memory.storeUShortAt(offset: Long, value: UShort)
202
203
/**
204
* Load an unsigned 32-bit int value.
205
* @param offset byte offset in memory
206
* @return unsigned int value
207
*/
208
fun Memory.loadUIntAt(offset: Int): UInt
209
fun Memory.loadUIntAt(offset: Long): UInt
210
211
/**
212
* Store an unsigned 32-bit int value.
213
* @param offset byte offset in memory
214
* @param value unsigned int value to store
215
*/
216
fun Memory.storeUIntAt(offset: Int, value: UInt)
217
fun Memory.storeUIntAt(offset: Long, value: UInt)
218
219
/**
220
* Load an unsigned 64-bit long value.
221
* @param offset byte offset in memory
222
* @return unsigned long value
223
*/
224
fun Memory.loadULongAt(offset: Int): ULong
225
fun Memory.loadULongAt(offset: Long): ULong
226
227
/**
228
* Store an unsigned 64-bit long value.
229
* @param offset byte offset in memory
230
* @param value unsigned long value to store
231
*/
232
fun Memory.storeULongAt(offset: Int, value: ULong)
233
fun Memory.storeULongAt(offset: Long, value: ULong)
234
235
/**
236
* Load a 32-bit float value in big-endian byte order.
237
* @param offset byte offset in memory
238
* @return float value
239
*/
240
fun Memory.loadFloatAt(offset: Int): Float
241
fun Memory.loadFloatAt(offset: Long): Float
242
243
/**
244
* Store a 32-bit float value in big-endian byte order.
245
* @param offset byte offset in memory
246
* @param value float value to store
247
*/
248
fun Memory.storeFloatAt(offset: Int, value: Float)
249
fun Memory.storeFloatAt(offset: Long, value: Float)
250
251
/**
252
* Load a 64-bit double value in big-endian byte order.
253
* @param offset byte offset in memory
254
* @return double value
255
*/
256
fun Memory.loadDoubleAt(offset: Int): Double
257
fun Memory.loadDoubleAt(offset: Long): Double
258
259
/**
260
* Store a 64-bit double value in big-endian byte order.
261
* @param offset byte offset in memory
262
* @param value double value to store
263
*/
264
fun Memory.storeDoubleAt(offset: Int, value: Double)
265
fun Memory.storeDoubleAt(offset: Long, value: Double)
266
```
267
268
**Usage Examples:**
269
270
```kotlin
271
import io.ktor.utils.io.bits.*
272
273
withMemory(64) { memory ->
274
// Store different primitive types
275
memory.storeIntAt(0, 0x12345678)
276
memory.storeFloatAt(4, 3.14159f)
277
memory.storeDoubleAt(8, 2.718281828)
278
memory.storeLongAt(16, 0x123456789ABCDEF0L)
279
280
// Load values back
281
val intValue = memory.loadIntAt(0) // 0x12345678
282
val floatValue = memory.loadFloatAt(4) // 3.14159f
283
val doubleValue = memory.loadDoubleAt(8) // 2.718281828
284
val longValue = memory.loadLongAt(16) // 0x123456789ABCDEF0L
285
286
// Work with unsigned types
287
memory.storeUIntAt(24, 0xFFFFFFFFu)
288
val unsignedValue = memory.loadUIntAt(24) // 0xFFFFFFFFu
289
}
290
291
// Store data structure
292
data class Point(val x: Float, val y: Float, val z: Float)
293
294
fun storePoint(memory: Memory, offset: Int, point: Point) {
295
memory.storeFloatAt(offset, point.x)
296
memory.storeFloatAt(offset + 4, point.y)
297
memory.storeFloatAt(offset + 8, point.z)
298
}
299
300
fun loadPoint(memory: Memory, offset: Int): Point {
301
return Point(
302
x = memory.loadFloatAt(offset),
303
y = memory.loadFloatAt(offset + 4),
304
z = memory.loadFloatAt(offset + 8)
305
)
306
}
307
308
val point = Point(1.0f, 2.0f, 3.0f)
309
storePoint(memory, 32, point)
310
val loadedPoint = loadPoint(memory, 32)
311
```
312
313
### Buffer Class (Deprecated)
314
315
Buffer with read/write positions backed by Memory for stream-like operations.
316
317
```kotlin { .api }
318
/**
319
* Buffer with read/write positions backed by Memory.
320
* Provides stream-like reading and writing with position tracking.
321
* @deprecated Use Memory and BytePacketBuilder/ByteReadPacket instead
322
*/
323
@Deprecated("Use Memory and packet APIs instead")
324
class Buffer {
325
/** Underlying memory region backing this buffer */
326
val memory: Memory
327
328
/** Current read position in the buffer */
329
var readPosition: Int
330
331
/** Current write position in the buffer */
332
var writePosition: Int
333
334
/** Reserved space at the beginning of the buffer */
335
val startGap: Int
336
337
/** Maximum write position allowed */
338
val limit: Int
339
340
/** Reserved space at the end of the buffer */
341
val endGap: Int
342
343
/** Total capacity of the buffer */
344
val capacity: Int
345
346
/** Number of bytes available for reading */
347
val readRemaining: Int
348
349
/** Number of bytes available for writing */
350
val writeRemaining: Int
351
352
/**
353
* Discard exactly count bytes from the read position.
354
* @param count number of bytes to discard
355
*/
356
fun discardExact(count: Int)
357
358
/**
359
* Commit count bytes that were written directly to memory.
360
* @param count number of bytes to commit
361
*/
362
fun commitWritten(count: Int)
363
364
/**
365
* Rewind the read position by count bytes.
366
* @param count number of bytes to rewind
367
*/
368
fun rewind(count: Int)
369
370
/**
371
* Reserve space at the beginning of the buffer.
372
* @param startGap number of bytes to reserve
373
*/
374
fun reserveStartGap(startGap: Int)
375
376
/**
377
* Reserve space at the end of the buffer.
378
* @param endGap number of bytes to reserve
379
*/
380
fun reserveEndGap(endGap: Int)
381
382
/** Reset buffer for reading from the beginning */
383
fun resetForRead()
384
385
/** Reset buffer for writing from the beginning */
386
fun resetForWrite()
387
388
/**
389
* Create a duplicate buffer sharing the same memory.
390
* @return new Buffer instance
391
*/
392
fun duplicate(): Buffer
393
394
/**
395
* Try to peek at the next byte without consuming it.
396
* @return next byte value or -1 if no more bytes
397
*/
398
fun tryPeekByte(): Int
399
400
/**
401
* Try to read a byte, returning -1 if none available.
402
* @return byte value or -1 if no more bytes
403
*/
404
fun tryReadByte(): Int
405
406
/**
407
* Read a byte, throwing exception if none available.
408
* @return byte value
409
* @throws EOFException if no more bytes
410
*/
411
fun readByte(): Byte
412
413
/**
414
* Write a byte to the buffer.
415
* @param value byte value to write
416
*/
417
fun writeByte(value: Byte)
418
419
companion object {
420
/** Default reserved size for gaps */
421
const val ReservedSize: Int = 8
422
423
/** Empty buffer singleton */
424
val Empty: Buffer
425
}
426
}
427
```
428
429
### Memory Allocation Functions
430
431
Functions for temporary memory allocation with automatic cleanup.
432
433
```kotlin { .api }
434
/**
435
* Invoke block function with a temporary Memory instance of the specified size.
436
* The provided instance shouldn't be captured and used outside of the block.
437
* @param size number of bytes to allocate
438
* @param block operation to perform with the memory
439
* @return result of the block operation
440
*/
441
inline fun <R> withMemory(size: Int, block: (Memory) -> R): R
442
443
/**
444
* Invoke block function with a temporary Memory instance of the specified size.
445
* @param size number of bytes to allocate (as Long)
446
* @param block operation to perform with the memory
447
* @return result of the block operation
448
*/
449
inline fun <R> withMemory(size: Long, block: (Memory) -> R): R
450
451
/**
452
* Execute block of code providing a temporary Memory view of this byte array range.
453
* @param offset starting position in array
454
* @param length number of bytes to use
455
* @param block operation to perform with the memory view
456
* @return result of the block operation
457
*/
458
fun <R> ByteArray.useMemory(offset: Int = 0, length: Int, block: (Memory) -> R): R
459
```
460
461
**Advanced Usage Examples:**
462
463
```kotlin
464
import io.ktor.utils.io.bits.*
465
466
// Memory allocation strategies
467
withMemory(1024) { smallMemory ->
468
// Use small memory allocation
469
}
470
471
withMemory(1024 * 1024) { largeMemory ->
472
// Use large memory allocation
473
}
474
475
// Use existing byte arrays as memory
476
val existingArray = ByteArray(100) { it.toByte() }
477
existingArray.useMemory { wrappedMemory ->
478
// Use entire array as memory
479
}
480
481
existingArray.useMemory(offset = 10, length = 50) { partialMemory ->
482
// Use part of array as memory
483
}
484
485
// Complex data serialization
486
class Header(val magic: Int, val version: Short, val flags: Byte)
487
class Payload(val data: ByteArray)
488
489
fun serializeMessage(memory: Memory, header: Header, payload: Payload): Int {
490
var offset = 0
491
492
// Write header
493
memory.storeIntAt(offset, header.magic)
494
offset += 4
495
memory.storeShortAt(offset, header.version)
496
offset += 2
497
memory.storeAt(offset, header.flags)
498
offset += 1
499
500
// Write payload size
501
memory.storeIntAt(offset, payload.data.size)
502
offset += 4
503
504
// Write payload data
505
payload.data.forEachIndexed { index, byte ->
506
memory.storeAt(offset + index, byte)
507
}
508
offset += payload.data.size
509
510
return offset // Total bytes written
511
}
512
513
fun deserializeMessage(memory: Memory): Pair<Header, Payload> {
514
var offset = 0
515
516
// Read header
517
val magic = memory.loadIntAt(offset)
518
offset += 4
519
val version = memory.loadShortAt(offset)
520
offset += 2
521
val flags = memory.loadAt(offset)
522
offset += 1
523
524
val header = Header(magic, version, flags)
525
526
// Read payload
527
val payloadSize = memory.loadIntAt(offset)
528
offset += 4
529
530
val payloadData = ByteArray(payloadSize) { index ->
531
memory.loadAt(offset + index)
532
}
533
534
val payload = Payload(payloadData)
535
536
return header to payload
537
}
538
539
// Usage
540
withMemory(1024) { memory ->
541
val header = Header(0x12345678, 1, 0xFF.toByte())
542
val payload = Payload("Hello World".toByteArray())
543
544
val bytesWritten = serializeMessage(memory, header, payload)
545
val (deserializedHeader, deserializedPayload) = deserializeMessage(memory)
546
}
547
```