Swift 中的标签指针!
这意味着我们有额外的 20 位可以利用!使用这个库,你可以通过 Swift 类型 TaggedPointer<>
轻松实现这一点。
let x = 5
withUnsafePointer(to: x) { p in
var tp = TaggedPointer(p)
tp.bitTag0 = true
tp.bitTag1 = true
tp.bitTag2 = true
tp.dataInt17 = 23
assert(tp.getPointer() == p)
}
你也可以查看测试作为示例。
以下是指针在内存中的布局方式。
Raw storage: |-----------------------------64 bits----------------------------|
Pointer anatomy: |--16 bits--|------1 bit-----|---- 44 bits ---|------3 bits------|
|unused bits|is kernel space?|the pointer guts|alignment artifact|
| all 0s | 0 | ??? | all 0s |
Raw storage: |-----------------------------64 bits----------------------------|
Simplified Pointer anatomy: |-----17 bits-----|--------------44 bits--------------|--3 bits--|
| all 0s | significant bits of pointer | all 0s |
|----------------------------------------------------------------|
前 16 位始终为 0,因为操作系统假设内存永远不会超过 48 位指针可以寻址的范围(48 位指针可以寻址 256 TB 的内存)。当指针位于内核空间时,内核空间标志为 1,当指针位于用户空间时,内核空间标志为 0。我们假设程序运行在用户空间中。 后 3 位始终为 0,因为指针是 8 字节对齐的,即第一个地址将是 0x0,然后是 0x8,然后是 0x10,依此类推。 如果你将指针十六进制值转换为二进制,你会发现后 3 位始终为 0。
TaggedPointer<>
利用指针中的额外位来让你塞入你自己的数据和位标志。
Raw storage: |-----------------------------64 bits----------------------------|
TaggedPointer anatomy: |-------17 bits-------|------44 bits-------|--------3 bits-------|
| custom 17 bit data | pointer data | custom 3 bit tag |
| | `getPointer` | |
| | `setPointer` | |
|----------------------------------------------------------------|
|-----------------------------64 bits----------------------------|
|--------61 bits-------|-----------------3 bits------------------|
| | `tagUInt3` |
| |----1 bit----|----1 bit----|----1 bit----|
| | `bitTag2` | `bitTag1` | `bitTag0` |
|----------------------------------------------------------------|
|-----------------------------64 bits----------------------------|
|------------17 bits----------|--------------47 bits-------------|
| `dataInt17` | |
|-----16 bits-----|---1 bit---| |
| magnitude | `signBit` | |
|----------------------------------------------------------------|
|-----------------------------64 bits----------------------------|
|-----16 bits-----|---------------------48 bits------------------|
| `dataUInt16` | |
| `dataInt16` | |
|----------------------------------------------------------------|
你可以将标签用作 3 位整数(表示为 UInt8 tagAsUInt8
)或用作 3 个单独的位(bitTag0
、bitTag1
、bitTag2
)。 你可以将数据用作 17 位有符号整数 (data17
) 或用作 16 位无符号整数 (dataUInt16
)。 你也可以直接访问数据的符号位 (signBit
)。
你可以简单地复制实现(只有一个文件)这里,或者你可以将其添加为 Swift 包。
// swift-tools-version:5.9
import PackageDescription
let package = Package(
name: "MyPackage",
dependencies: [
.package(
url: "https://github.com/joehinkle11/SwiftTaggedPointer.git",
.upToNextMajor(from: "1.0.0") // or `.upToNextMinor
)
],
targets: [
.target(
name: "MyTarget",
dependencies: [
.product(name: "SwiftTaggedPointer", package: "SwiftTaggedPointer")
]
)
]
)