You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
However, `lc.Ref[T]` is more powerful than `inout` in GLSL/HLSL. You can even return a reference from a function and use it later.
70
73
71
-
When overloading subscript operator or attribute access, you actually return a local reference to the object.
74
+
```python
75
+
@lc.func
76
+
defget_ref(a: lc.float3) -> lc.Ref[lc.float]:
77
+
return a.x
72
78
73
-
#### Local References
74
-
Local references are like pointers in C++. However, they cannot escape the expression boundary. This means that you cannot store a local reference in a variable and use it later. While you can return a local reference from a function, it must be returned from a uniform path. That is you cannot return different local references based on a condition.
79
+
a = lc.float3(1.0, 2.0, 3.0)
80
+
b = byref(get_ref(a)) # byref is necessary to indicate that the argument is passed by reference
81
+
b =2.0
82
+
lc.print(f'{a.x}{b}') # prints 2.0 2.0
83
+
```
84
+
85
+
**Important**: `lc.Ref[T]` is not a true reference type nor a pointer. It is a logical reference that is resolved at compile time. This means that you cannot store a `lc.Ref[T]` in an aggregate type, such as an array or a struct. If you want to return a reference from a function, the function must be inlineable. You also cannot define a local reference inside non-uniform control flow such as `if` or `for` statements. See the following example for the semantics of local references.
86
+
```python
87
+
a: lc.Ref[T] = byref(some_ref_func()) # a is bound to the reference returned by some_ref_func()
88
+
if cond():
89
+
a = another_ref_func() # does not bound `a` to a new reference, but changes the value of the reference
90
+
b: lc.Ref[T] = another_ref_func() # error, cannot define a local reference inside non-uniform control flow
91
+
# to workaround the above issue, you should define a new scope
92
+
@lc.block
93
+
definner():
94
+
b: lc.Ref[T] = another_ref_func() # this is fine
95
+
# do something with b
96
+
inner()
97
+
```
98
+
Further more, when matching template arguments, matching `lc.Ref[T]` to a template argument `U` would result in `U` being `T` instead of `lc.Ref[T]`.
99
+
To force `U` to be `lc.Ref[T]`, you can use `lc.Ref[U]` as the template argument.
75
100
76
101
102
+
Certain special methods must return a local reference. For example, `__getitem__` and `__getattr__` must return a local reference.
103
+
77
104
```python
78
105
@lc.struct
79
106
classInfiniteArray:
80
-
def__getitem__(self, index: int) -> int:
107
+
def__getitem__(self, index: int) -> lc.Ref[int]:
81
108
returnself.data[index] # returns a local reference
82
109
83
110
# this method will be ignored by the compiler. but you can still put it here for linting
84
111
def__setitem__(self, index: int, value: int):
85
112
pass
86
113
87
114
# Not allowed, non-uniform return
88
-
def__getitem__(self, index: int) -> int:
115
+
def__getitem__(self, index: int) -> lc.Ref[int]:
89
116
if index ==0:
90
117
returnself.data[0]
91
118
else:
@@ -94,9 +121,6 @@ class InfiniteArray:
94
121
```
95
122
96
123
97
-
98
-
99
-
100
124
### User-defined Structs
101
125
```python
102
126
@lc.struct
@@ -105,6 +129,39 @@ class Sphere:
105
129
radius: lc.float
106
130
```
107
131
132
+
133
+
### Control Flow
134
+
```python
135
+
# the following control flow constructs are supported
136
+
if cond:
137
+
pass
138
+
elif cond:
139
+
pass
140
+
else:
141
+
pass
142
+
143
+
while cond:
144
+
pass
145
+
146
+
for i in lc.range(10):
147
+
pass
148
+
```
149
+
Additionally, we provide a `lc.block` decorator that can be used to define a block of code that can be inlined into other functions. This is useful for defining shadowing variables or local references.
150
+
151
+
```python
152
+
a =1
153
+
b =2
154
+
@lc.block
155
+
definner():
156
+
nonlocal b
157
+
a =2
158
+
b =3
159
+
inner()
160
+
lc.print(a) # prints 1
161
+
lc.print(b) # prints 3
162
+
163
+
```
164
+
108
165
### Define DSL Operation for Non-DSL Types
109
166
Sometimes we want to use a non-DSL type in our DSL code. Such type could be imported from a third-party library or a built-in Python type. As long as we know the object layout, we can define the DSL operation for it by first defining a proxy struct that mirrors the object layout, and then define the operation for the proxy struct.
110
167
@@ -176,9 +233,8 @@ def call_n_times(f: F):
176
233
# or
177
234
lc.embed_code('apply_func(f, i)')
178
235
179
-
# Hint a parameter is constexpr
180
-
@lc.func(n=lc.comptime) # without this, n will be treated as a runtime variable and result in an error
0 commit comments