汇编 - 线性嵌套类布局

发布于 2025-01-22 13:44:41 字数 962 浏览 3 评论 0原文

我正在研究线性数据布局,其中组件在内存中彼此并肩。一切顺利,直到我意识到我没有办法进行OffsetofChangeType在处理嵌套类时调用。

例如,这是按预期的:


class Vec2{
    x:u8
    y:u8
}
const size = offsetof<Vec2>() // 2 -- ok
const ptr = heap.alloc(size)
changeType<Vec2>(ptr).x = 7 // memory = [7,0] -- ok

自然而然地,这种方法在嵌套类时失败了,

class Player{
    position:Vec2
    health:u8
}
const size = offsetof<Player>() //5 -- want 3, position is a pointer
const ptr = heap.alloc(size)
changeType<Player>(ptr).position.x = 7 //[0,0,0,0,0] -- want [7,0,0], instead accidentally changed pointer 0

目标是让内存布局看起来像这样:

| Player 1 | Player 2 | ...
| x y z h  | x y z h  |

理想情况下,我很想能够创建“值型”字段,或者如果这不是一件事,还有其他方法吗?

我希望每当编写新组件时避免大量的样板,即手动尺寸计算,并在其偏移等上为每个字段进行ChangeType进行ChangeType

I'm working on a linear data layout where components are alongside each other in memory. Things were going ok until I realized I don't have a way for making offsetof and changetype calls when dealing with nested classes.

For instance, this works as intended:


class Vec2{
    x:u8
    y:u8
}
const size = offsetof<Vec2>() // 2 -- ok
const ptr = heap.alloc(size)
changeType<Vec2>(ptr).x = 7 // memory = [7,0] -- ok

Naturally this approach fails when nesting classes

class Player{
    position:Vec2
    health:u8
}
const size = offsetof<Player>() //5 -- want 3, position is a pointer
const ptr = heap.alloc(size)
changeType<Player>(ptr).position.x = 7 //[0,0,0,0,0] -- want [7,0,0], instead accidentally changed pointer 0

The goal is for the memory layout to look like this:

| Player 1 | Player 2 | ...
| x y z h  | x y z h  |

Ideally I'd love to be able to create 'value-type' fields, or if this isnt a thing, are there alternative approaches?

I'm hoping to avoid extensive boilerplate whenever writing a new component, ie manual size calculation and doing a changetype for each field at its offset etc.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

云柯 2025-01-29 13:44:41

如果有人有兴趣,我将在此处发布我当前的解决方案。该实现有点混乱,但使用自定义脚本或编译器变换肯定可以自动化。

目标:为以下类创建线性代理,以便main函数的行为如预期:

class Foo {
    position: Vec2
    health: u8
}
export function main(): Info {
    
    const ptr = heap.alloc(FooProxy.size)
    const foo = changetype<FooProxy>(ptr)

    foo.health = 3
    foo.position.x = 9
    foo.position.y = 10
}

解决方案:计算每个字段的偏移和对齐。


class TypeMetadataBase{
    get align():u32{return 0}
    get offset():u32{return 0}
}
class TypeMetadata<T> extends TypeMetadataBase{
    get align():u32{return alignof<T>()}
    get offset():u32{return offsetof<T>()}

    constructor(){
        super()
        if(this.offset == 0)
        throw new Error('offset shouldnt be zero, for primitive types use PrimitiveMetadata')
    }
};
class PrimitiveMetadata<T> extends TypeMetadataBase{
    get align():u32{return sizeof<T>()}
    get offset():u32{return sizeof<T>()}
};

class LinearSchema{

    metadatas:StaticArray<TypeMetadataBase>
    size:u32
    offsets:StaticArray<u32>
    constructor(metadatas:StaticArray<TypeMetadataBase>){
        let align:u32 = 0
        const offsets = new StaticArray<u32>(metadatas.length)
        for (let i = 0; i < metadatas.length; i++){
            if(metadatas[i].align !== 0)
                while(align % metadatas[i].align !== 0)
                    align++
            offsets[i] = align
            align += metadatas[i].offset
        }
        this.offsets = offsets
        this.metadatas = metadatas
        this.size = align
    }
}


class Vec2 {
    x: u8
    y: u8
}

class FooSchema extends LinearSchema{
    constructor(){
        super([
            new PrimitiveMetadata<u8>(),
            new TypeMetadata<Vec2>(),
        ])
    }

}
const schema = new FooSchema()

class FooProxy{
    static get size():u32{return schema.size}
    set health(value:u8){store<u8>(changetype<usize>(this) + schema.offsets[0],value)}
    get health():u8{return load<u8>(changetype<usize>(this) + schema.offsets[0])}
    get position():Vec2{return changetype<Vec2>(changetype<usize>(this) + schema.offsets[1])}
}




In case anybody is interested I'll post my current solution here. The implementation is a little messy but is certainly automatable using custom scripts or compiler transforms.

Goal: Create a linear proxy for the following class so that the main function behaves as expected:

class Foo {
    position: Vec2
    health: u8
}
export function main(): Info {
    
    const ptr = heap.alloc(FooProxy.size)
    const foo = changetype<FooProxy>(ptr)

    foo.health = 3
    foo.position.x = 9
    foo.position.y = 10
}

Solution: calculate offsets and alignments for each field.


class TypeMetadataBase{
    get align():u32{return 0}
    get offset():u32{return 0}
}
class TypeMetadata<T> extends TypeMetadataBase{
    get align():u32{return alignof<T>()}
    get offset():u32{return offsetof<T>()}

    constructor(){
        super()
        if(this.offset == 0)
        throw new Error('offset shouldnt be zero, for primitive types use PrimitiveMetadata')
    }
};
class PrimitiveMetadata<T> extends TypeMetadataBase{
    get align():u32{return sizeof<T>()}
    get offset():u32{return sizeof<T>()}
};

class LinearSchema{

    metadatas:StaticArray<TypeMetadataBase>
    size:u32
    offsets:StaticArray<u32>
    constructor(metadatas:StaticArray<TypeMetadataBase>){
        let align:u32 = 0
        const offsets = new StaticArray<u32>(metadatas.length)
        for (let i = 0; i < metadatas.length; i++){
            if(metadatas[i].align !== 0)
                while(align % metadatas[i].align !== 0)
                    align++
            offsets[i] = align
            align += metadatas[i].offset
        }
        this.offsets = offsets
        this.metadatas = metadatas
        this.size = align
    }
}


class Vec2 {
    x: u8
    y: u8
}

class FooSchema extends LinearSchema{
    constructor(){
        super([
            new PrimitiveMetadata<u8>(),
            new TypeMetadata<Vec2>(),
        ])
    }

}
const schema = new FooSchema()

class FooProxy{
    static get size():u32{return schema.size}
    set health(value:u8){store<u8>(changetype<usize>(this) + schema.offsets[0],value)}
    get health():u8{return load<u8>(changetype<usize>(this) + schema.offsets[0])}
    get position():Vec2{return changetype<Vec2>(changetype<usize>(this) + schema.offsets[1])}
}




~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文