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)
|
||||
* [Advanced Topics](#advanced-topics)
|
||||
* [Memory-unsafe code](#memory-unsafe-code)
|
||||
* [sizeof and __offsetof](#sizeof-and-__offsetof)
|
||||
* [Calling C functions from V](#calling-c-functions-from-v)
|
||||
* [Debugging generated C code](#debugging-generated-c-code)
|
||||
* [Conditional compilation](#conditional-compilation)
|
||||
@ -2991,6 +2992,22 @@ println(baz)
|
||||
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
|
||||
|
||||
```v
|
||||
@ -3734,6 +3751,7 @@ type
|
||||
typeof
|
||||
union
|
||||
unsafe
|
||||
__offsetof
|
||||
```
|
||||
See also [Types](#types).
|
||||
|
||||
|
@ -13,9 +13,9 @@ pub type Expr = AnonFn | ArrayDecompose | ArrayInit | AsCast | Assoc | AtExpr |
|
||||
CTempVar | CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall |
|
||||
ComptimeSelector | ConcatExpr | EnumVal | FloatLiteral | GoExpr | Ident | IfExpr |
|
||||
IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr | MapInit |
|
||||
MatchExpr | None | OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectExpr |
|
||||
SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral | StructInit |
|
||||
Type | TypeOf | UnsafeExpr
|
||||
MatchExpr | None | OffsetOf | OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr |
|
||||
SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral |
|
||||
StructInit | Type | TypeOf | UnsafeExpr
|
||||
|
||||
pub type Stmt = AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl | DeferStmt |
|
||||
EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt |
|
||||
@ -1068,6 +1068,13 @@ pub mut:
|
||||
typ table.Type
|
||||
}
|
||||
|
||||
pub struct OffsetOf {
|
||||
pub:
|
||||
struct_type table.Type
|
||||
field string
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub struct Likely {
|
||||
pub:
|
||||
expr Expr
|
||||
@ -1197,7 +1204,7 @@ pub fn (expr Expr) position() token.Position {
|
||||
}
|
||||
ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr, CastExpr, ChanInit, CharLiteral,
|
||||
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,
|
||||
StructInit, Type, TypeOf, UnsafeExpr {
|
||||
return expr.pos
|
||||
|
@ -290,6 +290,9 @@ pub fn (x Expr) str() string {
|
||||
SizeOf {
|
||||
return 'sizeof($x.expr)'
|
||||
}
|
||||
OffsetOf {
|
||||
return '__offsetof($x.struct_type, $x.field)'
|
||||
}
|
||||
StringInterLiteral {
|
||||
mut res := []string{}
|
||||
res << "'"
|
||||
|
@ -3505,6 +3505,9 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
||||
}
|
||||
return table.u32_type
|
||||
}
|
||||
ast.OffsetOf {
|
||||
return c.offset_of(node)
|
||||
}
|
||||
ast.SqlExpr {
|
||||
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) {
|
||||
key_i := node.keys[i]
|
||||
if key_i is ast.StringLiteral {
|
||||
|
@ -947,6 +947,9 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
|
||||
ast.SizeOf {
|
||||
f.size_of(node)
|
||||
}
|
||||
ast.OffsetOf {
|
||||
f.write('__offsetof(${f.table.type_to_str(node.struct_type)}, $node.field)')
|
||||
}
|
||||
ast.SqlExpr {
|
||||
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)
|
||||
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 {
|
||||
g.sql_select_expr(node)
|
||||
}
|
||||
|
@ -541,6 +541,9 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
||||
ast.SizeOf {
|
||||
// TODO
|
||||
}
|
||||
ast.OffsetOf {
|
||||
// TODO
|
||||
}
|
||||
ast.SqlExpr {
|
||||
// TODO
|
||||
}
|
||||
|
@ -204,6 +204,25 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
|
||||
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 {
|
||||
is_likely := p.tok.kind == .key_likely
|
||||
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