1 /***********************************************************************
2  * Copyright (c) 2013-2024 Commonwealth Computer Research, Inc.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Apache License, Version 2.0
5  * which accompanies this distribution and is available at
6  * http://www.opensource.org/licenses/apache2.0.php.
7  ***********************************************************************/
8 
9 package org.locationtech.geomesa.utils.io
10 
11 import java.io.InputStream
12 import java.nio.ByteBuffer
13 import java.nio.charset.StandardCharsets
14 
15 object ByteBuffers {
16 
17   class ExpandingByteBuffer(capacity: Int) {
18 
19     private var bb = ByteBuffer.allocate(capacity)
20 
21     private def ensureRemaining(count: Int): Unit = {
22       if (bb.remaining < count) {
23         val expanded = ByteBuffer.allocate(bb.capacity() * 2)
24         bb.flip()
25         expanded.put(bb)
26         bb = expanded
27       }
28     }
29 
30     def putString(string: String): Unit = {
31       if (string == null) { putInt(-1) } else {
32         putBytes(string.getBytes(StandardCharsets.UTF_8))
33       }
34     }
35     def getString: String = {
36       val length = getInt
37       if (length == -1) { null } else {
38         val bytes = Array.ofDim[Byte](length)
39         bb.get(bytes)
40         new String(bytes, StandardCharsets.UTF_8)
41       }
42     }
43 
44     def putBytes(bytes: Array[Byte]): Unit = { ensureRemaining(bytes.length + 4); bb.putBytes(bytes) }
45     def getBytes: Array[Byte] = bb.getBytes
46 
47     def putBool(bool: Boolean): Unit = { ensureRemaining(1); bb.putBool(bool) }
48     def getBool: Boolean = bb.getBool
49 
50     def toArray: Array[Byte] = bb.toArray
51 
52     def put(b: Byte): ByteBuffer = { ensureRemaining(1); bb.put(b) }
53     def get(): Byte = bb.get()
54 
55     def put(src: Array[Byte]): ByteBuffer = { ensureRemaining(src.length); bb.put(src) }
56     def get(dst: Array[Byte]): ByteBuffer = bb.get(dst)
57 
58     def putChar(value: Char): ByteBuffer = { ensureRemaining(2); bb.putChar(value) }
59     def getChar: Char = bb.getChar
60 
61     def putShort(value: Short): ByteBuffer = { ensureRemaining(2); bb.putShort(value) }
62     def getShort: Short = bb.getShort
63 
64     def putInt(value: Int): ByteBuffer = { ensureRemaining(4); bb.putInt(value) }
65     def getInt: Int = bb.getInt
66 
67     def putLong(value: Long): ByteBuffer = { ensureRemaining(8); bb.putLong(value) }
68     def getLong: Long = bb.getLong
69 
70     def putFloat(value: Float): ByteBuffer = { ensureRemaining(4); bb.putFloat(value) }
71     def getFloat: Float = bb.getFloat
72 
73     def putDouble(value: Double): ByteBuffer = { ensureRemaining(8); bb.putDouble(value) }
74     def getDouble: Double = bb.getDouble
75   }
76 
77   implicit class RichByteBuffer(val bb: ByteBuffer) extends AnyVal {
78 
79     def toInputStream: InputStream = new ByteBufferInputStream(bb)
80 
81     def putBytes(bytes: Array[Byte]): Unit = {
82       bb.putInt(bytes.length)
83       bb.put(bytes)
84     }
85     def getBytes: Array[Byte] = {
86       val bytes = Array.ofDim[Byte](bb.getInt())
87       bb.get(bytes)
88       bytes
89     }
90 
91     def putString(string: String): Unit = {
92       if (string == null) { bb.putInt(-1) } else {
93         putBytes(string.getBytes(StandardCharsets.UTF_8))
94       }
95     }
96     def getString: String = {
97       val length = bb.getInt
98       if (length == -1) { null } else {
99         val bytes = Array.ofDim[Byte](length)
100         bb.get(bytes)
101         new String(bytes, StandardCharsets.UTF_8)
102       }
103     }
104 
105     def putBool(bool: Boolean): Unit = bb.put(if (bool) { 1.toByte } else { 0.toByte })
106     def getBool: Boolean = bb.get == 1
107 
108     def toArray: Array[Byte] = {
109       bb.flip()
110       val bytes = Array.ofDim[Byte](bb.remaining)
111       bb.get(bytes)
112       bytes
113     }
114   }
115 
116   class ByteBufferInputStream(buffer: ByteBuffer) extends InputStream {
117 
118     override def read(): Int = {
119       if (!buffer.hasRemaining) { -1 } else {
120         buffer.get() & 0xFF
121       }
122     }
123 
124     override def read(bytes: Array[Byte], offset: Int, length: Int): Int = {
125       if (!buffer.hasRemaining) { -1 } else {
126         val read = math.min(length, buffer.remaining)
127         buffer.get(bytes, offset, read)
128         read
129       }
130     }
131   }
132 
133 }
Line Stmt Id Pos Tree Symbol Tests Code
19 10531 713 - 721 Select org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.capacity ExpandingByteBuffer.this.capacity
19 10532 693 - 722 Apply java.nio.ByteBuffer.allocate java.nio.ByteBuffer.allocate(ExpandingByteBuffer.this.capacity)
22 10533 788 - 808 Apply scala.Int.< ExpandingByteBuffer.this.bb.remaining().<(count)
22 10540 810 - 946 Block <nosymbol> { val expanded: java.nio.ByteBuffer = java.nio.ByteBuffer.allocate(ExpandingByteBuffer.this.bb.capacity().*(2)); ExpandingByteBuffer.this.bb.flip(); expanded.put(ExpandingByteBuffer.this.bb); ExpandingByteBuffer.this.bb_=(expanded) }
22 10541 784 - 784 Literal <nosymbol> ()
22 10542 784 - 784 Block <nosymbol> ()
23 10534 855 - 872 Apply scala.Int.* ExpandingByteBuffer.this.bb.capacity().*(2)
23 10535 835 - 873 Apply java.nio.ByteBuffer.allocate java.nio.ByteBuffer.allocate(ExpandingByteBuffer.this.bb.capacity().*(2))
24 10536 882 - 891 Apply java.nio.ByteBuffer.flip ExpandingByteBuffer.this.bb.flip()
25 10537 913 - 915 Select org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.bb ExpandingByteBuffer.this.bb
25 10538 900 - 916 Apply java.nio.ByteBuffer.put expanded.put(ExpandingByteBuffer.this.bb)
26 10539 925 - 938 Apply org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.bb_= ExpandingByteBuffer.this.bb_=(expanded)
31 10543 1008 - 1022 Apply java.lang.Object.== string.==(null)
31 10544 1026 - 1036 Apply org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.putInt ExpandingByteBuffer.this.putInt(-1)
31 10545 1032 - 1032 Literal <nosymbol> ()
31 10546 1026 - 1036 Block <nosymbol> { ExpandingByteBuffer.this.putInt(-1); () }
32 10547 1079 - 1101 Select java.nio.charset.StandardCharsets.UTF_8 java.nio.charset.StandardCharsets.UTF_8
32 10548 1063 - 1102 Apply java.lang.String.getBytes string.getBytes(java.nio.charset.StandardCharsets.UTF_8)
32 10549 1054 - 1103 Apply org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.putBytes ExpandingByteBuffer.this.putBytes(string.getBytes(java.nio.charset.StandardCharsets.UTF_8))
32 10550 1054 - 1103 Block org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.putBytes ExpandingByteBuffer.this.putBytes(string.getBytes(java.nio.charset.StandardCharsets.UTF_8))
36 10551 1167 - 1173 Select org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.getInt ExpandingByteBuffer.this.getInt
37 10552 1184 - 1196 Apply scala.Int.== length.==(-1)
37 10553 1200 - 1204 Literal <nosymbol> null
37 10554 1200 - 1204 Block <nosymbol> null
37 10559 1212 - 1339 Block <nosymbol> { val bytes: Array[Byte] = scala.Array.ofDim[Byte](length)((ClassTag.Byte: scala.reflect.ClassTag[Byte])); ExpandingByteBuffer.this.bb.get(bytes); new scala.Predef.String(bytes, java.nio.charset.StandardCharsets.UTF_8) }
38 10555 1234 - 1259 ApplyToImplicitArgs scala.Array.ofDim scala.Array.ofDim[Byte](length)((ClassTag.Byte: scala.reflect.ClassTag[Byte]))
39 10556 1268 - 1281 Apply java.nio.ByteBuffer.get ExpandingByteBuffer.this.bb.get(bytes)
40 10557 1308 - 1330 Select java.nio.charset.StandardCharsets.UTF_8 java.nio.charset.StandardCharsets.UTF_8
40 10558 1290 - 1331 Apply java.lang.String.<init> new scala.Predef.String(bytes, java.nio.charset.StandardCharsets.UTF_8)
44 10560 1410 - 1426 Apply scala.Int.+ bytes.length.+(4)
44 10561 1394 - 1427 Apply org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.ensureRemaining ExpandingByteBuffer.this.ensureRemaining(bytes.length.+(4))
44 10562 1429 - 1447 Apply org.locationtech.geomesa.utils.io.ByteBuffers.RichByteBuffer.putBytes ByteBuffers.this.RichByteBuffer(ExpandingByteBuffer.this.bb).putBytes(bytes)
45 10563 1482 - 1484 Select org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.bb ExpandingByteBuffer.this.bb
45 10564 1482 - 1493 Select org.locationtech.geomesa.utils.io.ByteBuffers.RichByteBuffer.getBytes ByteBuffers.this.RichByteBuffer(ExpandingByteBuffer.this.bb).getBytes
47 10565 1536 - 1554 Apply org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.ensureRemaining ExpandingByteBuffer.this.ensureRemaining(1)
47 10566 1556 - 1572 Apply org.locationtech.geomesa.utils.io.ByteBuffers.RichByteBuffer.putBool ByteBuffers.this.RichByteBuffer(ExpandingByteBuffer.this.bb).putBool(bool)
48 10567 1602 - 1604 Select org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.bb ExpandingByteBuffer.this.bb
48 10568 1602 - 1612 Select org.locationtech.geomesa.utils.io.ByteBuffers.RichByteBuffer.getBool ByteBuffers.this.RichByteBuffer(ExpandingByteBuffer.this.bb).getBool
50 10569 1645 - 1647 Select org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.bb ExpandingByteBuffer.this.bb
50 10570 1645 - 1655 Select org.locationtech.geomesa.utils.io.ByteBuffers.RichByteBuffer.toArray ByteBuffers.this.RichByteBuffer(ExpandingByteBuffer.this.bb).toArray
52 10571 1694 - 1712 Apply org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.ensureRemaining ExpandingByteBuffer.this.ensureRemaining(1)
52 10572 1714 - 1723 Apply java.nio.ByteBuffer.put ExpandingByteBuffer.this.bb.put(b)
53 10573 1748 - 1756 Apply java.nio.ByteBuffer.get ExpandingByteBuffer.this.bb.get()
55 10574 1820 - 1830 Select scala.Array.length src.length
55 10575 1804 - 1831 Apply org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.ensureRemaining ExpandingByteBuffer.this.ensureRemaining(src.length)
55 10576 1833 - 1844 Apply java.nio.ByteBuffer.put ExpandingByteBuffer.this.bb.put(src)
56 10577 1891 - 1902 Apply java.nio.ByteBuffer.get ExpandingByteBuffer.this.bb.get(dst)
58 10578 1949 - 1967 Apply org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.ensureRemaining ExpandingByteBuffer.this.ensureRemaining(2)
58 10579 1969 - 1986 Apply java.nio.ByteBuffer.putChar ExpandingByteBuffer.this.bb.putChar(value)
59 10580 2013 - 2023 Apply java.nio.ByteBuffer.getChar ExpandingByteBuffer.this.bb.getChar()
61 10581 2072 - 2090 Apply org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.ensureRemaining ExpandingByteBuffer.this.ensureRemaining(2)
61 10582 2092 - 2110 Apply java.nio.ByteBuffer.putShort ExpandingByteBuffer.this.bb.putShort(value)
62 10583 2139 - 2150 Apply java.nio.ByteBuffer.getShort ExpandingByteBuffer.this.bb.getShort()
64 10584 2195 - 2213 Apply org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.ensureRemaining ExpandingByteBuffer.this.ensureRemaining(4)
64 10585 2215 - 2231 Apply java.nio.ByteBuffer.putInt ExpandingByteBuffer.this.bb.putInt(value)
65 10586 2256 - 2265 Apply java.nio.ByteBuffer.getInt ExpandingByteBuffer.this.bb.getInt()
67 10587 2312 - 2330 Apply org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.ensureRemaining ExpandingByteBuffer.this.ensureRemaining(8)
67 10588 2332 - 2349 Apply java.nio.ByteBuffer.putLong ExpandingByteBuffer.this.bb.putLong(value)
68 10589 2376 - 2386 Apply java.nio.ByteBuffer.getLong ExpandingByteBuffer.this.bb.getLong()
70 10590 2435 - 2453 Apply org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.ensureRemaining ExpandingByteBuffer.this.ensureRemaining(4)
70 10591 2455 - 2473 Apply java.nio.ByteBuffer.putFloat ExpandingByteBuffer.this.bb.putFloat(value)
71 10592 2502 - 2513 Apply java.nio.ByteBuffer.getFloat ExpandingByteBuffer.this.bb.getFloat()
73 10593 2564 - 2582 Apply org.locationtech.geomesa.utils.io.ByteBuffers.ExpandingByteBuffer.ensureRemaining ExpandingByteBuffer.this.ensureRemaining(8)
73 10594 2584 - 2603 Apply java.nio.ByteBuffer.putDouble ExpandingByteBuffer.this.bb.putDouble(value)
74 10595 2634 - 2646 Apply java.nio.ByteBuffer.getDouble ExpandingByteBuffer.this.bb.getDouble()
79 10596 2785 - 2787 Select org.locationtech.geomesa.utils.io.ByteBuffers.RichByteBuffer.bb RichByteBuffer.this.bb
79 10597 2759 - 2788 Apply org.locationtech.geomesa.utils.io.ByteBuffers.ByteBufferInputStream.<init> new ByteBuffers.this.ByteBufferInputStream(RichByteBuffer.this.bb)
82 10598 2853 - 2865 Select scala.Array.length bytes.length
82 10599 2843 - 2866 Apply java.nio.ByteBuffer.putInt RichByteBuffer.this.bb.putInt(bytes.length)
83 10600 2873 - 2886 Apply java.nio.ByteBuffer.put RichByteBuffer.this.bb.put(bytes)
83 10601 2879 - 2879 Literal <nosymbol> ()
86 10602 2963 - 2974 Apply java.nio.ByteBuffer.getInt RichByteBuffer.this.bb.getInt()
86 10603 2945 - 2975 ApplyToImplicitArgs scala.Array.ofDim scala.Array.ofDim[Byte](RichByteBuffer.this.bb.getInt())((ClassTag.Byte: scala.reflect.ClassTag[Byte]))
87 10604 2982 - 2995 Apply java.nio.ByteBuffer.get RichByteBuffer.this.bb.get(bytes)
92 10605 3069 - 3083 Apply java.lang.Object.== string.==(null)
92 10606 3087 - 3100 Apply java.nio.ByteBuffer.putInt RichByteBuffer.this.bb.putInt(-1)
92 10607 3096 - 3096 Literal <nosymbol> ()
92 10608 3087 - 3100 Block <nosymbol> { RichByteBuffer.this.bb.putInt(-1); () }
93 10609 3143 - 3165 Select java.nio.charset.StandardCharsets.UTF_8 java.nio.charset.StandardCharsets.UTF_8
93 10610 3127 - 3166 Apply java.lang.String.getBytes string.getBytes(java.nio.charset.StandardCharsets.UTF_8)
93 10611 3118 - 3167 Apply org.locationtech.geomesa.utils.io.ByteBuffers.RichByteBuffer.putBytes RichByteBuffer.this.putBytes(string.getBytes(java.nio.charset.StandardCharsets.UTF_8))
93 10612 3118 - 3167 Block org.locationtech.geomesa.utils.io.ByteBuffers.RichByteBuffer.putBytes RichByteBuffer.this.putBytes(string.getBytes(java.nio.charset.StandardCharsets.UTF_8))
97 10613 3231 - 3240 Apply java.nio.ByteBuffer.getInt RichByteBuffer.this.bb.getInt()
98 10614 3251 - 3263 Apply scala.Int.== length.==(-1)
98 10615 3267 - 3271 Literal <nosymbol> null
98 10616 3267 - 3271 Block <nosymbol> null
98 10621 3279 - 3406 Block <nosymbol> { val bytes: Array[Byte] = scala.Array.ofDim[Byte](length)((ClassTag.Byte: scala.reflect.ClassTag[Byte])); RichByteBuffer.this.bb.get(bytes); new scala.Predef.String(bytes, java.nio.charset.StandardCharsets.UTF_8) }
99 10617 3301 - 3326 ApplyToImplicitArgs scala.Array.ofDim scala.Array.ofDim[Byte](length)((ClassTag.Byte: scala.reflect.ClassTag[Byte]))
100 10618 3335 - 3348 Apply java.nio.ByteBuffer.get RichByteBuffer.this.bb.get(bytes)
101 10619 3375 - 3397 Select java.nio.charset.StandardCharsets.UTF_8 java.nio.charset.StandardCharsets.UTF_8
101 10620 3357 - 3398 Apply java.lang.String.<init> new scala.Predef.String(bytes, java.nio.charset.StandardCharsets.UTF_8)
105 10622 3472 - 3473 Literal <nosymbol> 1
105 10623 3472 - 3480 Select scala.Int.toByte 1.toByte
105 10624 3472 - 3480 Block scala.Int.toByte 1.toByte
105 10625 3490 - 3491 Literal <nosymbol> 0
105 10626 3490 - 3498 Select scala.Int.toByte 0.toByte
105 10627 3490 - 3498 Block scala.Int.toByte 0.toByte
105 10628 3453 - 3501 Apply java.nio.ByteBuffer.put RichByteBuffer.this.bb.put(if (bool) 1.toByte else 0.toByte)
105 10629 3459 - 3459 Literal <nosymbol> ()
106 10630 3529 - 3540 Apply scala.Byte.== RichByteBuffer.this.bb.get().==(1)
109 10631 3581 - 3590 Apply java.nio.ByteBuffer.flip RichByteBuffer.this.bb.flip()
110 10632 3627 - 3639 Apply java.nio.Buffer.remaining RichByteBuffer.this.bb.remaining()
110 10633 3609 - 3640 ApplyToImplicitArgs scala.Array.ofDim scala.Array.ofDim[Byte](RichByteBuffer.this.bb.remaining())((ClassTag.Byte: scala.reflect.ClassTag[Byte]))
111 10634 3647 - 3660 Apply java.nio.ByteBuffer.get RichByteBuffer.this.bb.get(bytes)
119 10635 3800 - 3820 Select scala.Boolean.unary_! ByteBufferInputStream.this.buffer.hasRemaining().unary_!
119 10636 3824 - 3826 Literal <nosymbol> -1
119 10637 3824 - 3826 Block <nosymbol> -1
120 10638 3844 - 3863 Apply scala.Byte.& ByteBufferInputStream.this.buffer.get().&(255)
120 10639 3844 - 3863 Block scala.Byte.& ByteBufferInputStream.this.buffer.get().&(255)
125 10640 3966 - 3986 Select scala.Boolean.unary_! ByteBufferInputStream.this.buffer.hasRemaining().unary_!
125 10641 3990 - 3992 Literal <nosymbol> -1
125 10642 3990 - 3992 Block <nosymbol> -1
125 10646 4000 - 4116 Block <nosymbol> { val read: Int = scala.math.`package`.min(length, ByteBufferInputStream.this.buffer.remaining()); ByteBufferInputStream.this.buffer.get(bytes, offset, read); read }
126 10643 4038 - 4054 Apply java.nio.Buffer.remaining ByteBufferInputStream.this.buffer.remaining()
126 10644 4021 - 4055 Apply scala.math.min scala.math.`package`.min(length, ByteBufferInputStream.this.buffer.remaining())
127 10645 4064 - 4095 Apply java.nio.ByteBuffer.get ByteBufferInputStream.this.buffer.get(bytes, offset, read)