@zio.dev/zio-blocks 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,576 @@
1
+ ---
2
+ id: chunk
3
+ title: "Chunk"
4
+ ---
5
+
6
+ `Chunk[A]` is an immutable, indexed sequence optimized for high-performance operations. Unlike Scala's built-in collections, Chunk is designed for zero-allocation access patterns, efficient concatenation, and unboxed primitive storage.
7
+
8
+ ## Why Chunk?
9
+
10
+ Chunk addresses several limitations of standard Scala collections:
11
+
12
+ | Feature | Chunk | Vector | Array |
13
+ |---------|-------|--------|-------|
14
+ | Immutable | ✓ | ✓ | ✗ |
15
+ | O(1) indexed access | ✓ | ~O(1) | ✓ |
16
+ | Unboxed primitives | ✓ | ✗ | ✓ |
17
+ | Efficient concatenation | ✓ | ✓ | ✗ |
18
+ | Safe functional interface | ✓ | ✓ | ✗ |
19
+ | Lazy slicing | ✓ | ✗ | ✗ |
20
+
21
+ Key advantages:
22
+
23
+ - **Zero-boxing for primitives**: `Chunk[Int]`, `Chunk[Double]`, etc. store values unboxed in specialized arrays
24
+ - **Lazy concatenation**: Uses balanced tree structures (based on Conc-Trees) for O(log n) concatenation
25
+ - **Efficient slicing**: `drop`, `take`, and `slice` create views without copying
26
+ - **Automatic materialization**: Deep operation chains are materialized when depth exceeds thresholds
27
+ - **Scala collections integration**: Implements `IndexedSeq` for seamless interoperability
28
+
29
+ ## Installation
30
+
31
+ Add the following to your `build.sbt`:
32
+
33
+ ```scala
34
+ libraryDependencies += "dev.zio" %% "zio-blocks-chunk" % "<version>"
35
+ ```
36
+
37
+ For cross-platform projects (Scala.js):
38
+
39
+ ```scala
40
+ libraryDependencies += "dev.zio" %%% "zio-blocks-chunk" % "<version>"
41
+ ```
42
+
43
+ Supported Scala versions: 2.13.x and 3.x
44
+
45
+ ## Creating Chunks
46
+
47
+ ### From Varargs
48
+
49
+ ```scala mdoc:compile-only
50
+ import zio.blocks.chunk.Chunk
51
+
52
+ val numbers = Chunk(1, 2, 3, 4, 5)
53
+ val strings = Chunk("hello", "world")
54
+ val empty = Chunk.empty[Int]
55
+ ```
56
+
57
+ ### From a Single Element
58
+
59
+ ```scala mdoc:compile-only
60
+ import zio.blocks.chunk.Chunk
61
+
62
+ val single = Chunk.single(42)
63
+ val unit = Chunk.unit // Chunk(())
64
+ ```
65
+
66
+ ### From Arrays
67
+
68
+ When you have an existing array, use `fromArray`. Note that the array should not be mutated after wrapping:
69
+
70
+ ```scala mdoc:compile-only
71
+ import zio.blocks.chunk.Chunk
72
+
73
+ val arr = Array(1, 2, 3)
74
+ val chunk = Chunk.fromArray(arr)
75
+ ```
76
+
77
+ ### From Iterables and Iterators
78
+
79
+ ```scala mdoc:compile-only
80
+ import zio.blocks.chunk.Chunk
81
+
82
+ val fromList = Chunk.fromIterable(List(1, 2, 3))
83
+ val fromVector = Chunk.fromIterable(Vector("a", "b"))
84
+ val fromIter = Chunk.fromIterator(Iterator.range(0, 10))
85
+ ```
86
+
87
+ ### From Java Collections
88
+
89
+ ```scala mdoc:compile-only
90
+ import zio.blocks.chunk.Chunk
91
+ import java.util
92
+
93
+ val javaList = new util.ArrayList[String]()
94
+ javaList.add("one")
95
+ javaList.add("two")
96
+
97
+ val chunk = Chunk.fromJavaIterable(javaList)
98
+ ```
99
+
100
+ ### From NIO Buffers
101
+
102
+ Chunk provides direct integration with Java NIO buffers:
103
+
104
+ ```scala mdoc:compile-only
105
+ import zio.blocks.chunk.Chunk
106
+ import java.nio.ByteBuffer
107
+
108
+ val buffer = ByteBuffer.wrap(Array[Byte](1, 2, 3, 4))
109
+ val bytes = Chunk.fromByteBuffer(buffer)
110
+ ```
111
+
112
+ Available buffer constructors:
113
+ - `Chunk.fromByteBuffer(ByteBuffer): Chunk[Byte]`
114
+ - `Chunk.fromCharBuffer(CharBuffer): Chunk[Char]`
115
+ - `Chunk.fromIntBuffer(IntBuffer): Chunk[Int]`
116
+ - `Chunk.fromLongBuffer(LongBuffer): Chunk[Long]`
117
+ - `Chunk.fromShortBuffer(ShortBuffer): Chunk[Short]`
118
+ - `Chunk.fromFloatBuffer(FloatBuffer): Chunk[Float]`
119
+ - `Chunk.fromDoubleBuffer(DoubleBuffer): Chunk[Double]`
120
+
121
+ ### Generator Functions
122
+
123
+ ```scala mdoc:compile-only
124
+ import zio.blocks.chunk.Chunk
125
+
126
+ val filled = Chunk.fill(5)("x") // Chunk("x", "x", "x", "x", "x")
127
+ val iterated = Chunk.iterate(1, 5)(_ * 2) // Chunk(1, 2, 4, 8, 16)
128
+ val unfolded = Chunk.unfold(0)(n => if (n < 5) Some((n, n + 1)) else None)
129
+ ```
130
+
131
+ ## Core Operations
132
+
133
+ ### Element Access
134
+
135
+ ```scala mdoc:compile-only
136
+ import zio.blocks.chunk.Chunk
137
+
138
+ val chunk = Chunk(10, 20, 30, 40, 50)
139
+
140
+ val first = chunk(0) // 10
141
+ val second = chunk(1) // 20
142
+ val head = chunk.head // 10
143
+ val last = chunk.last // 50
144
+ val len = chunk.length // 5
145
+
146
+ val maybeHead = chunk.headOption // Some(10)
147
+ val maybeLast = chunk.lastOption // Some(50)
148
+ ```
149
+
150
+ For primitive chunks, specialized accessors avoid boxing:
151
+
152
+ ```scala mdoc:compile-only
153
+ import zio.blocks.chunk.Chunk
154
+
155
+ val ints = Chunk(1, 2, 3)
156
+ val i: Int = ints.int(0) // unboxed access
157
+
158
+ val bytes = Chunk[Byte](1, 2, 3)
159
+ val b: Byte = bytes.byte(0) // unboxed access
160
+
161
+ val doubles = Chunk(1.0, 2.0, 3.0)
162
+ val d: Double = doubles.double(0) // unboxed access
163
+ ```
164
+
165
+ ### Transformations
166
+
167
+ ```scala mdoc:compile-only
168
+ import zio.blocks.chunk.Chunk
169
+
170
+ val chunk = Chunk(1, 2, 3, 4, 5)
171
+
172
+ val doubled = chunk.map(_ * 2) // Chunk(2, 4, 6, 8, 10)
173
+ val filtered = chunk.filter(_ > 2) // Chunk(3, 4, 5)
174
+ val flatted = chunk.flatMap(n => Chunk(n, n)) // Chunk(1, 1, 2, 2, ...)
175
+ val collected = chunk.collect { case n if n % 2 == 0 => n * 10 } // Chunk(20, 40)
176
+ ```
177
+
178
+ ### Concatenation
179
+
180
+ Concatenation is efficient—Chunk uses balanced tree structures to avoid copying:
181
+
182
+ ```scala mdoc:compile-only
183
+ import zio.blocks.chunk.Chunk
184
+
185
+ val a = Chunk(1, 2, 3)
186
+ val b = Chunk(4, 5, 6)
187
+
188
+ val combined = a ++ b // Chunk(1, 2, 3, 4, 5, 6)
189
+ val appended = a :+ 4 // Chunk(1, 2, 3, 4)
190
+ val prepended = 0 +: a // Chunk(0, 1, 2, 3)
191
+ ```
192
+
193
+ ### Slicing
194
+
195
+ Slicing operations create views and don't copy data:
196
+
197
+ ```scala mdoc:compile-only
198
+ import zio.blocks.chunk.Chunk
199
+
200
+ val chunk = Chunk(1, 2, 3, 4, 5, 6, 7, 8)
201
+
202
+ val firstThree = chunk.take(3) // Chunk(1, 2, 3)
203
+ val lastThree = chunk.takeRight(3) // Chunk(6, 7, 8)
204
+ val dropped = chunk.drop(2) // Chunk(3, 4, 5, 6, 7, 8)
205
+ val sliced = chunk.slice(2, 5) // Chunk(3, 4, 5)
206
+
207
+ val (left, right) = chunk.splitAt(4) // (Chunk(1,2,3,4), Chunk(5,6,7,8))
208
+ ```
209
+
210
+ ### Conditional Operations
211
+
212
+ ```scala mdoc:compile-only
213
+ import zio.blocks.chunk.Chunk
214
+
215
+ val chunk = Chunk(1, 2, 3, 4, 5, 6)
216
+
217
+ val takeWhileSmall = chunk.takeWhile(_ < 4) // Chunk(1, 2, 3)
218
+ val dropWhileSmall = chunk.dropWhile(_ < 4) // Chunk(4, 5, 6)
219
+ val takeUntilBig = chunk.takeWhile(_ <= 3) // Chunk(1, 2, 3)
220
+ val dropUntilBig = chunk.dropUntil(_ > 3) // Chunk(5, 6)
221
+ ```
222
+
223
+ ### Folding and Reduction
224
+
225
+ ```scala mdoc:compile-only
226
+ import zio.blocks.chunk.Chunk
227
+
228
+ val chunk = Chunk(1, 2, 3, 4, 5)
229
+
230
+ val sum = chunk.foldLeft(0)(_ + _) // 15
231
+ val product = chunk.foldRight(1)(_ * _) // 120
232
+ val summed = chunk.reduce(_ + _) // 15
233
+
234
+ val runningSum = chunk.foldWhile(0)(_ < 10)(_ + _) // 10 (1+2+3+4)
235
+ ```
236
+
237
+ ### Searching and Predicates
238
+
239
+ ```scala mdoc:compile-only
240
+ import zio.blocks.chunk.Chunk
241
+
242
+ val chunk = Chunk(1, 2, 3, 4, 5)
243
+
244
+ val hasEven = chunk.exists(_ % 2 == 0) // true
245
+ val allSmall = chunk.forall(_ < 10) // true
246
+ val found = chunk.find(_ > 3) // Some(4)
247
+ val index = chunk.indexWhere(_ > 3) // 3
248
+ ```
249
+
250
+ ### Zipping
251
+
252
+ ```scala mdoc:compile-only
253
+ import zio.blocks.chunk.Chunk
254
+
255
+ val as = Chunk("a", "b", "c")
256
+ val bs = Chunk(1, 2, 3)
257
+
258
+ val zipped = as.zip(bs) // Chunk(("a",1), ("b",2), ("c",3))
259
+ val withIndex = as.zipWithIndex // Chunk(("a",0), ("b",1), ("c",2))
260
+ val zipWith = as.zipWith(bs)(_ + _) // Chunk("a1", "b2", "c3")
261
+ val zipAll = as.zipAll(Chunk(1, 2)) // handles different lengths
262
+ ```
263
+
264
+ ### Updating Elements
265
+
266
+ Updates are immutable and use efficient buffering:
267
+
268
+ ```scala mdoc:compile-only
269
+ import zio.blocks.chunk.Chunk
270
+
271
+ val chunk = Chunk(1, 2, 3, 4, 5)
272
+ val updated = chunk.updated(2, 100) // Chunk(1, 2, 100, 4, 5)
273
+ ```
274
+
275
+ ### Deduplication and Sorting
276
+
277
+ ```scala mdoc:compile-only
278
+ import zio.blocks.chunk.Chunk
279
+
280
+ val withDupes = Chunk(1, 1, 2, 2, 2, 3, 3)
281
+ val deduped = withDupes.dedupe // Chunk(1, 2, 3) - removes adjacent duplicates
282
+
283
+ val unsorted = Chunk(3, 1, 4, 1, 5)
284
+ val sorted = unsorted.sorted // Chunk(1, 1, 3, 4, 5)
285
+ ```
286
+
287
+ ### Splitting
288
+
289
+ ```scala mdoc:compile-only
290
+ import zio.blocks.chunk.Chunk
291
+
292
+ val chunk = Chunk(1, 2, 3, 4, 5, 6)
293
+
294
+ val parts = chunk.split(3) // Chunk(Chunk(1,2), Chunk(3,4), Chunk(5,6))
295
+ val (before, after) = chunk.splitWhere(_ > 3) // splits at first element > 3
296
+ ```
297
+
298
+ ### String Conversion
299
+
300
+ ```scala mdoc:compile-only
301
+ import zio.blocks.chunk.Chunk
302
+ import java.nio.charset.StandardCharsets
303
+
304
+ val bytes = Chunk[Byte](72, 101, 108, 108, 111)
305
+ val str = bytes.asString // "Hello"
306
+
307
+ val chars = Chunk('H', 'e', 'l', 'l', 'o')
308
+ val str2 = chars.asString // "Hello"
309
+
310
+ val withCharset = bytes.asString(StandardCharsets.UTF_8) // "Hello"
311
+ val base64 = bytes.asBase64String // base64-encoded string
312
+ ```
313
+
314
+ ### Materialization
315
+
316
+ For complex operation chains, you can force materialization to an array-backed chunk:
317
+
318
+ ```scala mdoc:compile-only
319
+ import zio.blocks.chunk.Chunk
320
+
321
+ val complex = Chunk(1, 2, 3) ++ Chunk(4, 5) ++ Chunk(6, 7)
322
+ val materialized = complex.materialize // backed by a single array
323
+ ```
324
+
325
+ ## NonEmptyChunk
326
+
327
+ `NonEmptyChunk[A]` is a chunk guaranteed to contain at least one element. This enables safe use of operations like `head` and `reduce`:
328
+
329
+ ```scala mdoc:compile-only
330
+ import zio.blocks.chunk.{Chunk, NonEmptyChunk}
331
+
332
+ val nec = NonEmptyChunk(1, 2, 3)
333
+
334
+ val first: Int = nec.head // always safe
335
+ val sum: Int = nec.reduce(_ + _) // always safe
336
+
337
+ val mapped: NonEmptyChunk[Int] = nec.map(_ * 2)
338
+ val flatMapped: NonEmptyChunk[Int] = nec.flatMap(n => NonEmptyChunk(n, n + 1))
339
+ ```
340
+
341
+ ### Creating NonEmptyChunk
342
+
343
+ ```scala mdoc:compile-only
344
+ import zio.blocks.chunk.{Chunk, NonEmptyChunk}
345
+
346
+ val fromValues = NonEmptyChunk(1, 2, 3)
347
+ val single = NonEmptyChunk.single(42)
348
+ val fromCons = NonEmptyChunk.fromCons(::(1, List(2, 3)))
349
+ val fromIterable = NonEmptyChunk.fromIterable(1, List(2, 3))
350
+
351
+ val maybeNec: Option[NonEmptyChunk[Int]] = NonEmptyChunk.fromChunk(Chunk(1, 2))
352
+ val empty: Option[NonEmptyChunk[Int]] = NonEmptyChunk.fromChunk(Chunk.empty) // None
353
+ ```
354
+
355
+ ### Converting Between Chunk and NonEmptyChunk
356
+
357
+ ```scala mdoc:compile-only
358
+ import zio.blocks.chunk.{Chunk, NonEmptyChunk}
359
+
360
+ val nec = NonEmptyChunk(1, 2, 3)
361
+ val chunk: Chunk[Int] = nec.toChunk
362
+
363
+ val chunk2 = Chunk(1, 2, 3)
364
+ chunk2.nonEmptyOrElse(0)(_.reduce(_ + _)) // 6 if non-empty, 0 if empty
365
+ ```
366
+
367
+ ### Operations That Preserve NonEmptiness
368
+
369
+ These operations return `NonEmptyChunk`:
370
+ - `map`, `flatMap`, `flatten`
371
+ - `append`, `prepend`, `++`
372
+ - `zip`, `zipWith`, `zipWithIndex`
373
+ - `sorted`, `sortBy`, `reverse`
374
+ - `distinct`, `materialize`
375
+
376
+ Operations that might produce empty results return `Chunk`:
377
+ - `filter`, `filterNot`
378
+ - `collect`
379
+ - `tail`, `init`
380
+
381
+ ## ChunkBuilder
382
+
383
+ `ChunkBuilder` is a mutable builder for creating chunks efficiently. It's specialized for primitives to avoid boxing:
384
+
385
+ ```scala mdoc:compile-only
386
+ import zio.blocks.chunk.{Chunk, ChunkBuilder}
387
+
388
+ val builder = ChunkBuilder.make[Int]()
389
+ builder.addOne(1)
390
+ builder.addOne(2)
391
+ builder.addAll(List(3, 4, 5))
392
+ val result: Chunk[Int] = builder.result() // Chunk(1, 2, 3, 4, 5)
393
+ ```
394
+
395
+ ### Specialized Builders
396
+
397
+ For primitives, use specialized builders for best performance:
398
+
399
+ ```scala mdoc:compile-only
400
+ import zio.blocks.chunk.{Chunk, ChunkBuilder}
401
+
402
+ val intBuilder = new ChunkBuilder.Int
403
+ intBuilder.addOne(1)
404
+ intBuilder.addOne(2)
405
+ val ints: Chunk[Int] = intBuilder.result()
406
+
407
+ val byteBuilder = new ChunkBuilder.Byte
408
+ val longBuilder = new ChunkBuilder.Long
409
+ val doubleBuilder = new ChunkBuilder.Double
410
+ val boolBuilder = new ChunkBuilder.Boolean
411
+ ```
412
+
413
+ Available specialized builders: `Boolean`, `Byte`, `Char`, `Short`, `Int`, `Long`, `Float`, `Double`
414
+
415
+ ## Bit Operations
416
+
417
+ Chunk provides efficient bit-level operations for working with binary data:
418
+
419
+ ### Converting to Bits
420
+
421
+ ```scala mdoc:compile-only
422
+ import zio.blocks.chunk.Chunk
423
+
424
+ val bytes = Chunk[Byte](0x0F, 0xF0.toByte)
425
+ val bits = bytes.asBitsByte // Chunk of 16 booleans
426
+
427
+ val ints = Chunk(0x12345678)
428
+ val intBits = ints.asBitsInt(Chunk.BitChunk.Endianness.BigEndian)
429
+
430
+ val longs = Chunk(0x123456789ABCDEF0L)
431
+ val longBits = longs.asBitsLong(Chunk.BitChunk.Endianness.BigEndian)
432
+ ```
433
+
434
+ ### Bitwise Operations
435
+
436
+ ```scala mdoc:compile-only
437
+ import zio.blocks.chunk.Chunk
438
+
439
+ val a = Chunk(true, false, true, false)
440
+ val b = Chunk(true, true, false, false)
441
+
442
+ val andResult = a & b // Chunk(true, false, false, false)
443
+ val orResult = a | b // Chunk(true, true, true, false)
444
+ val xorResult = a ^ b // Chunk(false, true, true, false)
445
+ val negated = a.negate // Chunk(false, true, false, true)
446
+ ```
447
+
448
+ ### Packing Booleans
449
+
450
+ ```scala mdoc:compile-only
451
+ import zio.blocks.chunk.Chunk
452
+
453
+ val bits = Chunk(true, false, true, false, true, true, true, true)
454
+ val packedBytes: Chunk[Byte] = bits.toPackedByte // Efficient byte representation
455
+
456
+ val packedInts: Chunk[Int] = bits.toPackedInt(Chunk.BitChunk.Endianness.BigEndian)
457
+ val packedLongs: Chunk[Long] = bits.toPackedLong(Chunk.BitChunk.Endianness.BigEndian)
458
+ ```
459
+
460
+ ### Binary String
461
+
462
+ ```scala mdoc:compile-only
463
+ import zio.blocks.chunk.Chunk
464
+
465
+ val bits = Chunk(true, false, true, true)
466
+ val binary: String = bits.toBinaryString // "1011"
467
+ ```
468
+
469
+ ## ChunkMap
470
+
471
+ `ChunkMap[K, V]` is an order-preserving immutable map backed by parallel chunks. It maintains insertion order during iteration:
472
+
473
+ ```scala mdoc:compile-only
474
+ import zio.blocks.chunk.{Chunk, ChunkMap}
475
+
476
+ val map = ChunkMap("a" -> 1, "b" -> 2, "c" -> 3)
477
+
478
+ val value = map.get("b") // Some(2)
479
+ val updated = map.updated("d", 4)
480
+ val removed = map.removed("b")
481
+ ```
482
+
483
+ ### Creating ChunkMap
484
+
485
+ ```scala mdoc:compile-only
486
+ import zio.blocks.chunk.{Chunk, ChunkMap}
487
+
488
+ val empty = ChunkMap.empty[String, Int]
489
+ val fromPairs = ChunkMap("x" -> 1, "y" -> 2)
490
+ val fromChunk = ChunkMap.fromChunk(Chunk(("a", 1), ("b", 2)))
491
+ val fromChunks = ChunkMap.fromChunks(Chunk("a", "b"), Chunk(1, 2))
492
+ ```
493
+
494
+ ### Indexed Access
495
+
496
+ ChunkMap provides O(1) positional access:
497
+
498
+ ```scala mdoc:compile-only
499
+ import zio.blocks.chunk.{Chunk, ChunkMap}
500
+
501
+ val map = ChunkMap("z" -> 1, "a" -> 2, "m" -> 3)
502
+
503
+ val first = map.atIndex(0) // ("z", 1)
504
+ val key = map.keyAtIndex(1) // "a"
505
+ val value = map.valueAtIndex(2) // 3
506
+
507
+ val keys: Chunk[String] = map.keysChunk
508
+ val values: Chunk[Int] = map.valuesChunk
509
+ ```
510
+
511
+ ### Optimized Lookup
512
+
513
+ For frequent lookups, create an indexed version with O(1) key access:
514
+
515
+ ```scala mdoc:compile-only
516
+ import zio.blocks.chunk.ChunkMap
517
+
518
+ val map = ChunkMap("a" -> 1, "b" -> 2, "c" -> 3)
519
+ val indexed = map.indexed // O(1) lookups, extra memory for index
520
+
521
+ val value = indexed.get("b") // O(1) instead of O(n)
522
+ ```
523
+
524
+ ## Scala Collections Integration
525
+
526
+ Chunk implements `IndexedSeq` and integrates seamlessly with Scala collections:
527
+
528
+ ```scala mdoc:compile-only
529
+ import zio.blocks.chunk.Chunk
530
+
531
+ val chunk = Chunk(1, 2, 3, 4, 5)
532
+
533
+ val list: List[Int] = chunk.toList
534
+ val vector: Vector[Int] = chunk.toVector
535
+ val array: Array[Int] = chunk.toArray
536
+
537
+ val fromSeq: Chunk[Int] = Chunk.from(Vector(1, 2, 3))
538
+ ```
539
+
540
+ Standard collection operations work as expected:
541
+
542
+ ```scala mdoc:compile-only
543
+ import zio.blocks.chunk.Chunk
544
+
545
+ val chunk = Chunk(1, 2, 3)
546
+ val result = chunk
547
+ .filter(_ > 1)
548
+ .map(_ * 2)
549
+ .flatMap(n => Chunk(n, n + 1))
550
+ ```
551
+
552
+ ## Performance Characteristics
553
+
554
+ | Operation | Time Complexity | Notes |
555
+ |-----------|-----------------|-------|
556
+ | `apply(i)` | O(1) | Direct array access for materialized chunks |
557
+ | `length` | O(1) | Cached |
558
+ | `head`, `last` | O(1) | |
559
+ | `++` | O(log n) | Balanced tree concatenation |
560
+ | `:+`, `+:` | O(1) amortized | Buffered appends |
561
+ | `take`, `drop`, `slice` | O(1) | Creates view |
562
+ | `map`, `filter`, `flatMap` | O(n) | |
563
+ | `updated` | O(1) amortized | Buffered updates |
564
+ | `materialize` | O(n) | Copies to array |
565
+
566
+ ### When to Materialize
567
+
568
+ Chunk automatically materializes when:
569
+ - Tree depth exceeds internal thresholds
570
+ - You call `materialize` explicitly
571
+ - Converting to array with `toArray`
572
+
573
+ Consider explicit materialization when:
574
+ - Performing many random accesses on a deeply nested chunk
575
+ - Passing data to APIs that need arrays
576
+ - Optimizing a hot loop