Thread overview
How to implement this?
Apr 08, 2022
Elvis Zhou
Apr 08, 2022
Era Scarecrow
Apr 08, 2022
Era Scarecrow
Apr 08, 2022
Ali Çehreli
Apr 08, 2022
Elvis Zhou
Apr 08, 2022
Elvis Zhou
Apr 08, 2022
Stanislav Blinov
Apr 08, 2022
Elvis Zhou
April 08, 2022
struct A {}
struct B { A a; }
struct C { A a; }

A*[] structs;

B b;
init(&b);
structs ~= cast(A*)&b;
//Error: copying `cast(A*)& b` into allocated memory escapes a reference to local variable `b`

C c;
init(&c);
structs ~= cast(A*)&c;
//Error: copying `cast(A*)& c` into allocated memory escapes a reference to local variable `c`

batch_process(structs);
April 08, 2022

On Friday, 8 April 2022 at 04:31:45 UTC, Elvis Zhou wrote:

>

B b;
init(&b);
structs ~= cast(A*)&b;
//Error: copying cast(A*)\& b into allocated memory escapes a reference to local variable b

Maybe it should be cast(A*) \&b.a?

April 08, 2022

On Friday, 8 April 2022 at 04:54:35 UTC, Era Scarecrow wrote:

>

Maybe it should be cast(A*) &b.a?

Confusing HTML entities bit on here. Probably just ignore it.

Maybe you are doing it backwards.

What if you had

struct B {
A* a;
}

A[] arraylist;

then in the init append a new item to A's array list, before doing:

arraylist ~= A();
a = &arraylist[$-1];

Alternately, add a static list and have the batch function access both lists?

struct B {
static A[] list;
int a_index=-1;
}

a_index=list.length;
list ~= A();

then reference the item by list[a_index] or something similar.

April 07, 2022
On 4/7/22 21:31, Elvis Zhou wrote:
>
> struct A {}
> struct B { A a; }
> struct C { A a; }
>
> A*[] structs;
>
> B b;
> init(&b);
> structs ~= cast(A*)&b;
> //Error: copying `cast(A*)& b` into allocated memory escapes a reference
> to local variable `b`

If that really is the case, you want to place the objects on memory that will not go away. Dynamic arrays provide "memory" that is owned by the GC.

The following program emplaces alternating Bs and Cs into a buffer and then batch_process'es them:

struct A { int i; }
struct B { A a; }
struct C { A a; }

A*[] structs;

void append(T, Args...)(ref ubyte[] structs, Args args) {
  import std.conv : emplace;

  structs.length += sizeWithPadding!T;
  auto where = cast(T*)(&structs[$ - sizeWithPadding!T]);
  emplace(where, args);
}

void main() {
  ubyte[] structs;

  foreach (i; 0 .. 10) {
    if (i % 2) {
      structs.append!B(A(i));

    } else {
      structs.append!C(A(i));
    }
  }

  batch_process(structs);
}

auto process(T)(const(ubyte)[] structs) {
  import std.stdio : writeln;

  writeln(*cast(T*)structs.ptr);
  return structs[sizeWithPadding!T..$];
}

void batch_process(const(ubyte)[] structs) {
  import std.range : empty;

  for (size_t i = 0; !structs.empty; i++) {
    if (i % 2) {
      structs = structs.process!B();

    } else {
      structs = structs.process!C();
    }
  }
}

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);
}

size_t sizeWithPadding(T)() {
  static if (is (T == class)) {
    const candidateAddr = __traits(classInstanceSize, T);

  } else {
    const candidateAddr = T.sizeof;
  }

  return cast(size_t)nextAlignedAddress(cast(T*)candidateAddr);
}

I copied nextAlignedAddress() and sizeWithPadding() functions from this chapter:

  http://ddili.org/ders/d.en/memory.html

Everything I did in the program above is explained there.

Ali

April 08, 2022
On Friday, 8 April 2022 at 04:31:45 UTC, Elvis Zhou wrote:
>
> struct A {}
> struct B { A a; }
> struct C { A a; }
>
> A*[] structs;
>
> B b;
> init(&b);
> structs ~= cast(A*)&b;
> //Error: copying `cast(A*)& b` into allocated memory escapes a reference to local variable `b`
>
> C c;
> init(&c);
> structs ~= cast(A*)&c;
> //Error: copying `cast(A*)& c` into allocated memory escapes a reference to local variable `c`
>
> batch_process(structs);

I know where the issue comes from, dynamic array is GCed and save the reference of a local variable in GCed memory is not allowed, but here structs is assumed to not escape, it can be simply achieved by using a fixed-size array instead, ie A*[32] structs; int i = 0; structs[i++] = cast(A*)&b; However I wonder if there be a stack allocated array with max capacity limits, which can be concated like with normal dynamic one.
April 08, 2022
On Friday, 8 April 2022 at 05:46:56 UTC, Elvis Zhou wrote:
> On Friday, 8 April 2022 at 04:31:45 UTC, Elvis Zhou wrote:
>> [...]
>
> I know where the issue comes from, dynamic array is GCed and save the reference of a local variable in GCed memory is not allowed, but here structs is assumed to not escape, it can be simply achieved by using a fixed-size array instead, ie A*[32] structs; int i = 0; structs[i++] = cast(A*)&b; However I wonder if there be a stack allocated array with max capacity limits, which can be concated like with normal dynamic one.

like,

assumeNoEscapeOrWhatever!DynamicArray structs;
structs ~= cast(A*)&b;

is it possible?
April 08, 2022
On Friday, 8 April 2022 at 05:53:03 UTC, Elvis Zhou wrote:

> assumeNoEscapeOrWhatever!DynamicArray structs;
> structs ~= cast(A*)&b;
>
> is it possible?

That's what `@trusted` is for. And that's also why it should be used with care, and on the smallest code possible.

```d
struct A {}
struct B { A a; }
struct C { A a; }

void main()
{
    A*[] structs;

    B b;
    C c;

    () @trusted {
        structs ~= cast(A*)&b;
        structs ~= cast(A*)&c;
    } ();
}
```
April 08, 2022
On Friday, 8 April 2022 at 09:08:07 UTC, Stanislav Blinov wrote:
> On Friday, 8 April 2022 at 05:53:03 UTC, Elvis Zhou wrote:
>
>> assumeNoEscapeOrWhatever!DynamicArray structs;
>> structs ~= cast(A*)&b;
>>
>> is it possible?
>
> That's what `@trusted` is for. And that's also why it should be used with care, and on the smallest code possible.
>
> ```d
> struct A {}
> struct B { A a; }
> struct C { A a; }
>
> void main()
> {
>     A*[] structs;
>
>     B b;
>     C c;
>
>     () @trusted {
>         structs ~= cast(A*)&b;
>         structs ~= cast(A*)&c;
>     } ();
> }
> ```

Thank you, this is exactly what I'm looking for!

But why this doesn't work?
void func() @trusted
{
    A*[] structs;
    B b;
    structs ~= cast(A*)&b; // still error
}