Skip to content

Commit b0b3c97

Browse files
Yu-zhclaude
authored andcommitted
feat(builtin): add byte-aligned fastpath extract methods for ArrayView[Byte] and BytesView
Adds 14 fixed-size `unsafe_extract_*_aligned(bs, byte_offset)` methods on each of ArrayView[Byte] and BytesView (28 total): one per combination of {byte, uint16, uint32, uint64} × {unsigned, signed} × {LE, BE}, with the trivial 8-bit pair. BytesView forwards to pre-existing BytesView::unsafe_read_* in bytes_unsafe.mbt. ArrayView[Byte] goes via a %identity reinterpret of the view's backing UninitializedArray[Byte] into FixedArray[Byte], then calls private intrinsic-annotated fixedarray_read_* helpers (%bytes.unsafe_read_*) — all kept inside bitstring.mbt. Signed variants build on the unsigned ones via extend_sign/reinterpret_as_int. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f7aa6da commit b0b3c97

2 files changed

Lines changed: 546 additions & 0 deletions

File tree

builtin/bitstring.mbt

Lines changed: 381 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,3 +1034,384 @@ pub fn Bytes::unsafe_extract_bytesview(
10341034
) -> BytesView {
10351035
bs[:].unsafe_extract_bytesview(offset, len)
10361036
}
1037+
1038+
//--------------------------------
1039+
// Byte-aligned fastpaths
1040+
//
1041+
// Fixed-size reads at a byte offset, used when the bit offset is statically
1042+
// known to be a multiple of 8. These take `byte_offset` (in bytes), not bits.
1043+
//
1044+
// Provided for `ArrayView[Byte]` and `BytesView`.
1045+
//--------------------------------
1046+
1047+
///|
1048+
/// Zero-cost reinterpretation of the backing buffer as `FixedArray[Byte]`, so
1049+
/// the intrinsic-backed `fixedarray_read_*` helpers below can run against the
1050+
/// underlying storage of an `ArrayView[Byte]`.
1051+
fn buffer_to_fixedarray(buf : UninitializedArray[Byte]) -> FixedArray[Byte] = "%identity"
1052+
1053+
///|
1054+
#intrinsic("%bytes.unsafe_read_uint16_le")
1055+
fn fixedarray_read_uint16_le(bytes : FixedArray[Byte], index : Int) -> UInt16 {
1056+
for i in 0..<=1; result = (0 : UInt16) {
1057+
continue result | (bytes.unsafe_get(i + index).to_uint16() << (8 * i))
1058+
} nobreak {
1059+
result
1060+
}
1061+
}
1062+
1063+
///|
1064+
#intrinsic("%bytes.unsafe_read_uint16_be")
1065+
fn fixedarray_read_uint16_be(bytes : FixedArray[Byte], index : Int) -> UInt16 {
1066+
for i in 0..<=1; result = (0 : UInt16) {
1067+
continue result | (bytes.unsafe_get(i + index).to_uint16() << (8 * (1 - i)))
1068+
} nobreak {
1069+
result
1070+
}
1071+
}
1072+
1073+
///|
1074+
#intrinsic("%bytes.unsafe_read_uint32_le")
1075+
fn fixedarray_read_uint32_le(bytes : FixedArray[Byte], index : Int) -> UInt {
1076+
for i in 0..<=3; result = (0 : UInt) {
1077+
continue result | (bytes.unsafe_get(i + index).to_uint() << (8 * i))
1078+
} nobreak {
1079+
result
1080+
}
1081+
}
1082+
1083+
///|
1084+
#intrinsic("%bytes.unsafe_read_uint32_be")
1085+
fn fixedarray_read_uint32_be(bytes : FixedArray[Byte], index : Int) -> UInt {
1086+
for i in 0..<=3; result = (0 : UInt) {
1087+
continue result | (bytes.unsafe_get(i + index).to_uint() << (8 * (3 - i)))
1088+
} nobreak {
1089+
result
1090+
}
1091+
}
1092+
1093+
///|
1094+
#intrinsic("%bytes.unsafe_read_uint64_le")
1095+
fn fixedarray_read_uint64_le(bytes : FixedArray[Byte], index : Int) -> UInt64 {
1096+
for i in 0..<=7; result = (0 : UInt64) {
1097+
continue result | (bytes.unsafe_get(i + index).to_uint64() << (8 * i))
1098+
} nobreak {
1099+
result
1100+
}
1101+
}
1102+
1103+
///|
1104+
#intrinsic("%bytes.unsafe_read_uint64_be")
1105+
fn fixedarray_read_uint64_be(bytes : FixedArray[Byte], index : Int) -> UInt64 {
1106+
for i in 0..<=7; result = (0 : UInt64) {
1107+
continue result | (bytes.unsafe_get(i + index).to_uint64() << (8 * (7 - i)))
1108+
} nobreak {
1109+
result
1110+
}
1111+
}
1112+
1113+
//--------------------------------
1114+
// ArrayView[Byte] fastpaths
1115+
//--------------------------------
1116+
1117+
///|
1118+
#internal(experimental, "subject to breaking change without notice")
1119+
#doc(hidden)
1120+
pub fn ArrayView::unsafe_extract_byte_aligned(
1121+
bs : ArrayView[Byte],
1122+
byte_offset : Int,
1123+
) -> UInt {
1124+
bs.unsafe_get(byte_offset).to_uint()
1125+
}
1126+
1127+
///|
1128+
#internal(experimental, "subject to breaking change without notice")
1129+
#doc(hidden)
1130+
pub fn ArrayView::unsafe_extract_byte_signed_aligned(
1131+
bs : ArrayView[Byte],
1132+
byte_offset : Int,
1133+
) -> Int {
1134+
bs.unsafe_get(byte_offset).to_uint().extend_sign(8)
1135+
}
1136+
1137+
///|
1138+
#internal(experimental, "subject to breaking change without notice")
1139+
#doc(hidden)
1140+
pub fn ArrayView::unsafe_extract_uint16_le_aligned(
1141+
bs : ArrayView[Byte],
1142+
byte_offset : Int,
1143+
) -> UInt16 {
1144+
fixedarray_read_uint16_le(
1145+
buffer_to_fixedarray(bs.buf()),
1146+
bs.start() + byte_offset,
1147+
)
1148+
}
1149+
1150+
///|
1151+
#internal(experimental, "subject to breaking change without notice")
1152+
#doc(hidden)
1153+
pub fn ArrayView::unsafe_extract_uint16_be_aligned(
1154+
bs : ArrayView[Byte],
1155+
byte_offset : Int,
1156+
) -> UInt16 {
1157+
fixedarray_read_uint16_be(
1158+
buffer_to_fixedarray(bs.buf()),
1159+
bs.start() + byte_offset,
1160+
)
1161+
}
1162+
1163+
///|
1164+
#internal(experimental, "subject to breaking change without notice")
1165+
#doc(hidden)
1166+
pub fn ArrayView::unsafe_extract_int16_le_aligned(
1167+
bs : ArrayView[Byte],
1168+
byte_offset : Int,
1169+
) -> Int {
1170+
bs.unsafe_extract_uint16_le_aligned(byte_offset).to_uint().extend_sign(16)
1171+
}
1172+
1173+
///|
1174+
#internal(experimental, "subject to breaking change without notice")
1175+
#doc(hidden)
1176+
pub fn ArrayView::unsafe_extract_int16_be_aligned(
1177+
bs : ArrayView[Byte],
1178+
byte_offset : Int,
1179+
) -> Int {
1180+
bs.unsafe_extract_uint16_be_aligned(byte_offset).to_uint().extend_sign(16)
1181+
}
1182+
1183+
///|
1184+
#internal(experimental, "subject to breaking change without notice")
1185+
#doc(hidden)
1186+
pub fn ArrayView::unsafe_extract_uint_le_aligned(
1187+
bs : ArrayView[Byte],
1188+
byte_offset : Int,
1189+
) -> UInt {
1190+
fixedarray_read_uint32_le(
1191+
buffer_to_fixedarray(bs.buf()),
1192+
bs.start() + byte_offset,
1193+
)
1194+
}
1195+
1196+
///|
1197+
#internal(experimental, "subject to breaking change without notice")
1198+
#doc(hidden)
1199+
pub fn ArrayView::unsafe_extract_uint_be_aligned(
1200+
bs : ArrayView[Byte],
1201+
byte_offset : Int,
1202+
) -> UInt {
1203+
fixedarray_read_uint32_be(
1204+
buffer_to_fixedarray(bs.buf()),
1205+
bs.start() + byte_offset,
1206+
)
1207+
}
1208+
1209+
///|
1210+
#internal(experimental, "subject to breaking change without notice")
1211+
#doc(hidden)
1212+
pub fn ArrayView::unsafe_extract_int_le_aligned(
1213+
bs : ArrayView[Byte],
1214+
byte_offset : Int,
1215+
) -> Int {
1216+
bs.unsafe_extract_uint_le_aligned(byte_offset).reinterpret_as_int()
1217+
}
1218+
1219+
///|
1220+
#internal(experimental, "subject to breaking change without notice")
1221+
#doc(hidden)
1222+
pub fn ArrayView::unsafe_extract_int_be_aligned(
1223+
bs : ArrayView[Byte],
1224+
byte_offset : Int,
1225+
) -> Int {
1226+
bs.unsafe_extract_uint_be_aligned(byte_offset).reinterpret_as_int()
1227+
}
1228+
1229+
///|
1230+
#internal(experimental, "subject to breaking change without notice")
1231+
#doc(hidden)
1232+
pub fn ArrayView::unsafe_extract_uint64_le_aligned(
1233+
bs : ArrayView[Byte],
1234+
byte_offset : Int,
1235+
) -> UInt64 {
1236+
fixedarray_read_uint64_le(
1237+
buffer_to_fixedarray(bs.buf()),
1238+
bs.start() + byte_offset,
1239+
)
1240+
}
1241+
1242+
///|
1243+
#internal(experimental, "subject to breaking change without notice")
1244+
#doc(hidden)
1245+
pub fn ArrayView::unsafe_extract_uint64_be_aligned(
1246+
bs : ArrayView[Byte],
1247+
byte_offset : Int,
1248+
) -> UInt64 {
1249+
fixedarray_read_uint64_be(
1250+
buffer_to_fixedarray(bs.buf()),
1251+
bs.start() + byte_offset,
1252+
)
1253+
}
1254+
1255+
///|
1256+
#internal(experimental, "subject to breaking change without notice")
1257+
#doc(hidden)
1258+
pub fn ArrayView::unsafe_extract_int64_le_aligned(
1259+
bs : ArrayView[Byte],
1260+
byte_offset : Int,
1261+
) -> Int64 {
1262+
bs.unsafe_extract_uint64_le_aligned(byte_offset).reinterpret_as_int64()
1263+
}
1264+
1265+
///|
1266+
#internal(experimental, "subject to breaking change without notice")
1267+
#doc(hidden)
1268+
pub fn ArrayView::unsafe_extract_int64_be_aligned(
1269+
bs : ArrayView[Byte],
1270+
byte_offset : Int,
1271+
) -> Int64 {
1272+
bs.unsafe_extract_uint64_be_aligned(byte_offset).reinterpret_as_int64()
1273+
}
1274+
1275+
//--------------------------------
1276+
// BytesView fastpaths
1277+
//--------------------------------
1278+
1279+
///|
1280+
#internal(experimental, "subject to breaking change without notice")
1281+
#doc(hidden)
1282+
pub fn BytesView::unsafe_extract_byte_aligned(
1283+
bs : BytesView,
1284+
byte_offset : Int,
1285+
) -> UInt {
1286+
bs.unsafe_get(byte_offset).to_uint()
1287+
}
1288+
1289+
///|
1290+
#internal(experimental, "subject to breaking change without notice")
1291+
#doc(hidden)
1292+
pub fn BytesView::unsafe_extract_byte_signed_aligned(
1293+
bs : BytesView,
1294+
byte_offset : Int,
1295+
) -> Int {
1296+
bs.unsafe_get(byte_offset).to_uint().extend_sign(8)
1297+
}
1298+
1299+
///|
1300+
#internal(experimental, "subject to breaking change without notice")
1301+
#doc(hidden)
1302+
pub fn BytesView::unsafe_extract_uint16_le_aligned(
1303+
bs : BytesView,
1304+
byte_offset : Int,
1305+
) -> UInt16 {
1306+
bs.unsafe_read_uint16_le(byte_offset)
1307+
}
1308+
1309+
///|
1310+
#internal(experimental, "subject to breaking change without notice")
1311+
#doc(hidden)
1312+
pub fn BytesView::unsafe_extract_uint16_be_aligned(
1313+
bs : BytesView,
1314+
byte_offset : Int,
1315+
) -> UInt16 {
1316+
bs.unsafe_read_uint16_be(byte_offset)
1317+
}
1318+
1319+
///|
1320+
#internal(experimental, "subject to breaking change without notice")
1321+
#doc(hidden)
1322+
pub fn BytesView::unsafe_extract_int16_le_aligned(
1323+
bs : BytesView,
1324+
byte_offset : Int,
1325+
) -> Int {
1326+
bs.unsafe_read_uint16_le(byte_offset).to_uint().extend_sign(16)
1327+
}
1328+
1329+
///|
1330+
#internal(experimental, "subject to breaking change without notice")
1331+
#doc(hidden)
1332+
pub fn BytesView::unsafe_extract_int16_be_aligned(
1333+
bs : BytesView,
1334+
byte_offset : Int,
1335+
) -> Int {
1336+
bs.unsafe_read_uint16_be(byte_offset).to_uint().extend_sign(16)
1337+
}
1338+
1339+
///|
1340+
#internal(experimental, "subject to breaking change without notice")
1341+
#doc(hidden)
1342+
pub fn BytesView::unsafe_extract_uint_le_aligned(
1343+
bs : BytesView,
1344+
byte_offset : Int,
1345+
) -> UInt {
1346+
bs.unsafe_read_uint32_le(byte_offset)
1347+
}
1348+
1349+
///|
1350+
#internal(experimental, "subject to breaking change without notice")
1351+
#doc(hidden)
1352+
pub fn BytesView::unsafe_extract_uint_be_aligned(
1353+
bs : BytesView,
1354+
byte_offset : Int,
1355+
) -> UInt {
1356+
bs.unsafe_read_uint32_be(byte_offset)
1357+
}
1358+
1359+
///|
1360+
#internal(experimental, "subject to breaking change without notice")
1361+
#doc(hidden)
1362+
pub fn BytesView::unsafe_extract_int_le_aligned(
1363+
bs : BytesView,
1364+
byte_offset : Int,
1365+
) -> Int {
1366+
bs.unsafe_read_uint32_le(byte_offset).reinterpret_as_int()
1367+
}
1368+
1369+
///|
1370+
#internal(experimental, "subject to breaking change without notice")
1371+
#doc(hidden)
1372+
pub fn BytesView::unsafe_extract_int_be_aligned(
1373+
bs : BytesView,
1374+
byte_offset : Int,
1375+
) -> Int {
1376+
bs.unsafe_read_uint32_be(byte_offset).reinterpret_as_int()
1377+
}
1378+
1379+
///|
1380+
#internal(experimental, "subject to breaking change without notice")
1381+
#doc(hidden)
1382+
pub fn BytesView::unsafe_extract_uint64_le_aligned(
1383+
bs : BytesView,
1384+
byte_offset : Int,
1385+
) -> UInt64 {
1386+
bs.unsafe_read_uint64_le(byte_offset)
1387+
}
1388+
1389+
///|
1390+
#internal(experimental, "subject to breaking change without notice")
1391+
#doc(hidden)
1392+
pub fn BytesView::unsafe_extract_uint64_be_aligned(
1393+
bs : BytesView,
1394+
byte_offset : Int,
1395+
) -> UInt64 {
1396+
bs.unsafe_read_uint64_be(byte_offset)
1397+
}
1398+
1399+
///|
1400+
#internal(experimental, "subject to breaking change without notice")
1401+
#doc(hidden)
1402+
pub fn BytesView::unsafe_extract_int64_le_aligned(
1403+
bs : BytesView,
1404+
byte_offset : Int,
1405+
) -> Int64 {
1406+
bs.unsafe_read_uint64_le(byte_offset).reinterpret_as_int64()
1407+
}
1408+
1409+
///|
1410+
#internal(experimental, "subject to breaking change without notice")
1411+
#doc(hidden)
1412+
pub fn BytesView::unsafe_extract_int64_be_aligned(
1413+
bs : BytesView,
1414+
byte_offset : Int,
1415+
) -> Int64 {
1416+
bs.unsafe_read_uint64_be(byte_offset).reinterpret_as_int64()
1417+
}

0 commit comments

Comments
 (0)