On Saturday, 25 February 2017 at 20:02:56 UTC, ikod wrote:
On Saturday, 25 February 2017 at 19:59:29 UTC, ikod wrote:
Hello,
I have a method for range:
struct Range {
immutable(ubyte[]) _buffer;
size_t _pos;
@property void popFront() pure @safe {
enforce(_pos < _buffer.length, "popFront from empty
buffer");
_pos++;
}
}
I'd like to have @nogc here, but I can't because enforce() is
non-@nogc.
I have a trick but not sure if it is valid, especially I don't
know if optimization will preserve code, used for throwing:
import std.string;
struct Range {
immutable(ubyte[]) _buffer;
size_t _pos;
this(immutable(ubyte[]) s) {
_buffer = s;
}
@property void popFront() pure @safe @nogc {
if (_pos >= _buffer.length ) {
auto _ = _buffer[$]; // throws RangeError
}
_pos++;
}
}
void main() {
auto r = Range("1".representation);
r.popFront();
r.popFront(); // throws
}
Is it ok to use it? Is there any better solution?
Thanks!
Found that I can use
@property void popFront() pure @safe @nogc {
if (_pos >= _buffer.length ) {
assert(0, "popFront for empty range");
}
_pos++;
}
which is both descriptive and can't be optimized out.
I made a test:
void main()
{
assert(0);
}
it builds and doesn't throw if I compile with:
dmd -release
though it causes a segfault, what is probably a dmd bug. So I
suppose it can be optimized out. And it isn't very discriptive,
you probably throws the same AssertError for all errors. You can
throw in @nogc code, you only have to allocate the exception not
on the GC heap and free it after catching. I'm writing myself a
library that is complete @nogc and I use exceptions this way:
- Allocate the exception
- throw
- catch
- free
A wrapper that unifies these 4 steps like enforce is pretty easy
to implement.