or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-channels.mdbyte-order.mdcharacter-encoding.mdindex.mdmemory-management.mdobject-pooling.mdpacket-io.md

memory-management.mddocs/

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

```