module pind.samples.ja.memory.memory_8; interface Animal { string sing(); } class Cat : Animal { string sing() { return "meow"; } } class Parrot : Animal { string[] lyrics; this(string[] lyrics) { this.lyrics = lyrics; } string sing() { /* std.algorithm.joinerは、指定された区切り文字で * 範囲の要素を結合する。 */ return lyrics.joiner(", ").to!string; } } T * nextAlignedAddress(T)(T * candidateAddr) { import std.traits; static if (is (T == class)) { const alignment = classInstanceAlignment!T; } else { const alignment = T.alignof; } const result = (cast(size_t)candidateAddr + alignment - 1) / alignment * alignment; return cast(T*)result; } void * nextAlignedAddress(T)(void * candidateAddr) { return nextAlignedAddress(cast(T*)candidateAddr); } import std.stdio; import std.algorithm; import std.conv; import core.memory; // ... void main() { /* Animal変数(Animalオブジェクトではない)のスライス。 */ Animal[] animals; /* 任意の容量のバッファを割り当て、 * この例では2つのオブジェクトがその領域に収まると仮定する。 * 通常、この条件は * 検証する必要がある。 */ const capacity = 10_000; void * buffer = GC.calloc(capacity); /* まず、Catオブジェクトを配置しよう。 */ void * catCandidateAddr = buffer; void * catAddr = nextAlignedAddress!Cat(catCandidateAddr); writeln("Cat address : ", catAddr); /* emplace()はクラスオブジェクトに対してvoid[]を必要とするため、 * まずポインタからスライスを生成する必要がある。 */ size_t catSize = __traits(classInstanceSize, Cat); void[] catPlace = catAddr[0..catSize]; /* そのメモリスライス内にCatオブジェクトを構築し、 * 返されたクラス変数を後で使用するために格納する。 */ Cat cat = emplace!Cat(catPlace); animals ~= cat; /* 次に、アライメント要件を満たす次の利用可能なアドレスに * Parrotオブジェクトを構築する。 */ void * parrotCandidateAddr = catAddr + catSize; void * parrotAddr = nextAlignedAddress!Parrot(parrotCandidateAddr); writeln("Parrot address: ", parrotAddr); size_t parrotSize = __traits(classInstanceSize, Parrot); void[] parrotPlace = parrotAddr[0..parrotSize]; Parrot parrot = emplace!Parrot(parrotPlace, [ "squawk", "arrgh" ]); animals ~= parrot; /* オブジェクトを使用する。 */ foreach (animal; animals) { writeln(animal.sing()); } }