-
Notifications
You must be signed in to change notification settings - Fork 32
Working in a @nogc environment
Probably the largest hurdle to cross when learning Dplug is getting used to working without the runtime enabled. It may be confusing or even a little frustrating at first, but once you learn a few key tricks, it's a breeze. Here are some important things to remember when writing Plug-ins with Dplug.
Dplug does not use the -betterC
switch but instead let the runtime disabled. The term "runtime-free D" has been coined (as opposed to "runtime-less").
This allows to get back most features of the language, except for heap closures. No runtime enabled implies no GC.
Dplug generally uses malloc
throughout, however some construct use alignedMalloc
, alignedRealloc
and alignedFree
.
Don't mix and match memory allocated with malloc
and memory allocated with alignedMalloc
.
Slices can be allocated using malloc
/free
, and the functions mallocSlice
, mallocSliceNoInit
, and freeSlice
provides are wrappers to do just that.
Example:
float[] myBuf = mallocSliceNoInit(128);
// later
freeSlice(myBuf);
Another handy way to allocate audio buffer is to use reallocBuffer
. This function also takes an alignment.
Example:
float[] myAudioBuf;
myAudioBuf.reallocBuffer(frames, 16); // takes optional alignment (default = 1)
// later
myAudioBuf.reallocBuffer(0, 16); // must repeat alignment
Since there is no runtime enabled (hence no GC) the keyword new
cannot be used to allocate memory for classes. Instead classes must be allocated using auto mallocNew(T, Args...)(Args args)
.
Once you are finished using the class, you may deallocate it using void destroyFree(T)(T p)
Example:
class Foo
{
public:
this(int i)
{
f = i;
}
private:
int f;
}
// Create a new object of type foo and pass 3 to its constructor.
Foo foo = mallocNew!Foo(3);
// Done using the class so the memory can be freed.
foo.destroyFree();
See: https://p0nce.github.io/d-idioms/#@nogc-Array-Literals:-Breaking-the-Limits
If you need exception in runtime-free D, use the following construct:
Example:
try
{
if (error)
throw mallocEmplace!Exception("An error message without format() call");
}
catch(Exception e)
{
// do something with e
e.destroyFree();
}
One disadvantage to using @nogc is that it makes much of the standard library off limits. If you are unsure of what you can and can't use, you can check the documentation here Phobos Documentation, if the function is nothrow @nogc
then it can be used. Most of the core
modules can be used, and everything in core.stdc
is nothrow @nogc
.
Note that template functions have their attributes inferred most of the time: https://p0nce.github.io/d-idioms/#Automatic-attribute-inference-for-function-templates
An exception to these rules is when using CTFE(Compile-Time Function Evaluation). Since the D runtime is available during compile time, it is possible to use every feature using the GC: new
, heap closures, array literals, GC slices, etc.
Another exception is host application (using dplug:host), will have the runtime enabled.
In general, nothrow @nogc
code can be used both by regular code using the runtime and nothrow @nogc
code.