mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
all: add offsetof (#8380)
This commit is contained in:
parent
c0685eeefc
commit
8c70920695
18
doc/docs.md
18
doc/docs.md
@ -112,6 +112,7 @@ For more details and troubleshooting, please visit the [vab GitHub repository](h
|
|||||||
* [Profiling](#profiling)
|
* [Profiling](#profiling)
|
||||||
* [Advanced Topics](#advanced-topics)
|
* [Advanced Topics](#advanced-topics)
|
||||||
* [Memory-unsafe code](#memory-unsafe-code)
|
* [Memory-unsafe code](#memory-unsafe-code)
|
||||||
|
* [sizeof and __offsetof](#sizeof-and-__offsetof)
|
||||||
* [Calling C functions from V](#calling-c-functions-from-v)
|
* [Calling C functions from V](#calling-c-functions-from-v)
|
||||||
* [Debugging generated C code](#debugging-generated-c-code)
|
* [Debugging generated C code](#debugging-generated-c-code)
|
||||||
* [Conditional compilation](#conditional-compilation)
|
* [Conditional compilation](#conditional-compilation)
|
||||||
@ -2991,6 +2992,22 @@ println(baz)
|
|||||||
println(qux)
|
println(qux)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## sizeof and __offsetof
|
||||||
|
|
||||||
|
V supports the usage of `sizeof` to calculate sizes of structs and
|
||||||
|
`__offsetof` to calculate struct field offsets.
|
||||||
|
|
||||||
|
```v
|
||||||
|
struct Foo {
|
||||||
|
a int
|
||||||
|
b int
|
||||||
|
}
|
||||||
|
|
||||||
|
println(sizeof(Foo))
|
||||||
|
println(__offsetof(Foo, a))
|
||||||
|
println(__offsetof(Foo, b))
|
||||||
|
```
|
||||||
|
|
||||||
## Calling C functions from V
|
## Calling C functions from V
|
||||||
|
|
||||||
```v
|
```v
|
||||||
@ -3734,6 +3751,7 @@ type
|
|||||||
typeof
|
typeof
|
||||||
union
|
union
|
||||||
unsafe
|
unsafe
|
||||||
|
__offsetof
|
||||||
```
|
```
|
||||||
See also [Types](#types).
|
See also [Types](#types).
|
||||||
|
|
||||||
|
@ -13,9 +13,9 @@ pub type Expr = AnonFn | ArrayDecompose | ArrayInit | AsCast | Assoc | AtExpr |
|
|||||||
CTempVar | CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall |
|
CTempVar | CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall |
|
||||||
ComptimeSelector | ConcatExpr | EnumVal | FloatLiteral | GoExpr | Ident | IfExpr |
|
ComptimeSelector | ConcatExpr | EnumVal | FloatLiteral | GoExpr | Ident | IfExpr |
|
||||||
IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr | MapInit |
|
IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr | MapInit |
|
||||||
MatchExpr | None | OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectExpr |
|
MatchExpr | None | OffsetOf | OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr |
|
||||||
SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral | StructInit |
|
SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral |
|
||||||
Type | TypeOf | UnsafeExpr
|
StructInit | Type | TypeOf | UnsafeExpr
|
||||||
|
|
||||||
pub type Stmt = AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl | DeferStmt |
|
pub type Stmt = AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl | DeferStmt |
|
||||||
EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt |
|
EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt |
|
||||||
@ -1068,6 +1068,13 @@ pub mut:
|
|||||||
typ table.Type
|
typ table.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct OffsetOf {
|
||||||
|
pub:
|
||||||
|
struct_type table.Type
|
||||||
|
field string
|
||||||
|
pos token.Position
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Likely {
|
pub struct Likely {
|
||||||
pub:
|
pub:
|
||||||
expr Expr
|
expr Expr
|
||||||
@ -1197,7 +1204,7 @@ pub fn (expr Expr) position() token.Position {
|
|||||||
}
|
}
|
||||||
ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr, CastExpr, ChanInit, CharLiteral,
|
ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr, CastExpr, ChanInit, CharLiteral,
|
||||||
ConcatExpr, Comment, EnumVal, FloatLiteral, GoExpr, Ident, IfExpr, IndexExpr, IntegerLiteral,
|
ConcatExpr, Comment, EnumVal, FloatLiteral, GoExpr, Ident, IfExpr, IndexExpr, IntegerLiteral,
|
||||||
Likely, LockExpr, MapInit, MatchExpr, None, OrExpr, ParExpr, PostfixExpr, PrefixExpr,
|
Likely, LockExpr, MapInit, MatchExpr, None, OffsetOf, OrExpr, ParExpr, PostfixExpr, PrefixExpr,
|
||||||
RangeExpr, SelectExpr, SelectorExpr, SizeOf, SqlExpr, StringInterLiteral, StringLiteral,
|
RangeExpr, SelectExpr, SelectorExpr, SizeOf, SqlExpr, StringInterLiteral, StringLiteral,
|
||||||
StructInit, Type, TypeOf, UnsafeExpr {
|
StructInit, Type, TypeOf, UnsafeExpr {
|
||||||
return expr.pos
|
return expr.pos
|
||||||
|
@ -290,6 +290,9 @@ pub fn (x Expr) str() string {
|
|||||||
SizeOf {
|
SizeOf {
|
||||||
return 'sizeof($x.expr)'
|
return 'sizeof($x.expr)'
|
||||||
}
|
}
|
||||||
|
OffsetOf {
|
||||||
|
return '__offsetof($x.struct_type, $x.field)'
|
||||||
|
}
|
||||||
StringInterLiteral {
|
StringInterLiteral {
|
||||||
mut res := []string{}
|
mut res := []string{}
|
||||||
res << "'"
|
res << "'"
|
||||||
|
@ -3505,6 +3505,9 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||||||
}
|
}
|
||||||
return table.u32_type
|
return table.u32_type
|
||||||
}
|
}
|
||||||
|
ast.OffsetOf {
|
||||||
|
return c.offset_of(node)
|
||||||
|
}
|
||||||
ast.SqlExpr {
|
ast.SqlExpr {
|
||||||
return c.sql_expr(mut node)
|
return c.sql_expr(mut node)
|
||||||
}
|
}
|
||||||
@ -5058,6 +5061,19 @@ pub fn (mut c Checker) chan_init(mut node ast.ChanInit) table.Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (mut c Checker) offset_of(node ast.OffsetOf) table.Type {
|
||||||
|
sym := c.table.get_final_type_symbol(node.struct_type)
|
||||||
|
if sym.kind != .struct_ {
|
||||||
|
c.error('first argument of __offsetof must be struct', node.pos)
|
||||||
|
return table.u32_type
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.table.struct_has_field(node.struct_type, node.field) {
|
||||||
|
c.error('struct `$sym.name` has no field called `$node.field`', node.pos)
|
||||||
|
}
|
||||||
|
return table.u32_type
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) check_dup_keys(node &ast.MapInit, i int) {
|
pub fn (mut c Checker) check_dup_keys(node &ast.MapInit, i int) {
|
||||||
key_i := node.keys[i]
|
key_i := node.keys[i]
|
||||||
if key_i is ast.StringLiteral {
|
if key_i is ast.StringLiteral {
|
||||||
|
@ -947,6 +947,9 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
|
|||||||
ast.SizeOf {
|
ast.SizeOf {
|
||||||
f.size_of(node)
|
f.size_of(node)
|
||||||
}
|
}
|
||||||
|
ast.OffsetOf {
|
||||||
|
f.write('__offsetof(${f.table.type_to_str(node.struct_type)}, $node.field)')
|
||||||
|
}
|
||||||
ast.SqlExpr {
|
ast.SqlExpr {
|
||||||
f.sql_expr(node)
|
f.sql_expr(node)
|
||||||
}
|
}
|
||||||
|
8
vlib/v/fmt/tests/offset_keep.vv
Normal file
8
vlib/v/fmt/tests/offset_keep.vv
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
struct Animal {
|
||||||
|
breed string
|
||||||
|
age u64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println(__offsetof(Animal, breed) + __offsetof(Animal, age))
|
||||||
|
}
|
@ -2821,6 +2821,10 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||||||
styp := g.typ(node_typ)
|
styp := g.typ(node_typ)
|
||||||
g.write('/*SizeOf*/ sizeof(${util.no_dots(styp)})')
|
g.write('/*SizeOf*/ sizeof(${util.no_dots(styp)})')
|
||||||
}
|
}
|
||||||
|
ast.OffsetOf {
|
||||||
|
styp := g.typ(node.struct_type)
|
||||||
|
g.write('/*OffsetOf*/ (u32)(__offsetof(${util.no_dots(styp)}, $node.field))')
|
||||||
|
}
|
||||||
ast.SqlExpr {
|
ast.SqlExpr {
|
||||||
g.sql_select_expr(node)
|
g.sql_select_expr(node)
|
||||||
}
|
}
|
||||||
|
@ -541,6 +541,9 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
|||||||
ast.SizeOf {
|
ast.SizeOf {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
ast.OffsetOf {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
ast.SqlExpr {
|
ast.SqlExpr {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
@ -204,6 +204,25 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
|
|||||||
pos: spos.extend(p.tok.position())
|
pos: spos.extend(p.tok.position())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.key_offsetof {
|
||||||
|
pos := p.tok.position()
|
||||||
|
p.next() // __offsetof
|
||||||
|
p.check(.lpar)
|
||||||
|
st := p.parse_type()
|
||||||
|
p.check(.comma)
|
||||||
|
if p.tok.kind != .name {
|
||||||
|
p.error_with_pos('unexpected `$p.tok.lit`, expecting struct field', p.tok.position())
|
||||||
|
return ast.Expr{}
|
||||||
|
}
|
||||||
|
field := p.tok.lit
|
||||||
|
p.next()
|
||||||
|
p.check(.rpar)
|
||||||
|
node = ast.OffsetOf{
|
||||||
|
struct_type: st
|
||||||
|
field: field
|
||||||
|
pos: pos
|
||||||
|
}
|
||||||
|
}
|
||||||
.key_likely, .key_unlikely {
|
.key_likely, .key_unlikely {
|
||||||
is_likely := p.tok.kind == .key_likely
|
is_likely := p.tok.kind == .key_likely
|
||||||
p.next()
|
p.next()
|
||||||
|
35
vlib/v/tests/offsetof_test.v
Normal file
35
vlib/v/tests/offsetof_test.v
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import math.complex
|
||||||
|
|
||||||
|
struct Cat {
|
||||||
|
name string
|
||||||
|
breed string
|
||||||
|
age int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Feline = Cat
|
||||||
|
|
||||||
|
fn test_offsetof() {
|
||||||
|
cat := Cat{name: 'Cthulhu' breed: 'Great Old One' age: 2147483647}
|
||||||
|
unsafe {
|
||||||
|
assert *(&string(byteptr(&cat) + __offsetof(Cat, name))) == 'Cthulhu'
|
||||||
|
assert *(&string(byteptr(&cat) + __offsetof(Cat, breed))) == 'Great Old One'
|
||||||
|
assert *(&int(byteptr(&cat) + __offsetof(Cat, age))) == 2147483647
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_offsetof_struct_from_another_module() {
|
||||||
|
num := complex.Complex{1.0, 1.0}
|
||||||
|
unsafe {
|
||||||
|
assert *(&f64(byteptr(&num) + __offsetof(complex.Complex, re))) == 1.0
|
||||||
|
assert *(&f64(byteptr(&num) + __offsetof(complex.Complex, im))) == 1.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_offsetof_alias() {
|
||||||
|
fel := Feline{name: 'Cthulhu' breed: 'Great Old One' age: 2147483647}
|
||||||
|
unsafe {
|
||||||
|
assert *(&string(byteptr(&fel) + __offsetof(Feline, name))) == 'Cthulhu'
|
||||||
|
assert *(&string(byteptr(&fel) + __offsetof(Feline, breed))) == 'Great Old One'
|
||||||
|
assert *(&int(byteptr(&fel) + __offsetof(Feline, age))) == 2147483647
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user