Re: foreach (i; taskPool.parallel(0..2_000_000)

2023-04-05 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Apr 06, 2023 at 01:20:28AM +, Paul via Digitalmars-d-learn wrote:
[...]
> Yes I understand, basically, what's going on in hardware.  I just
> wasn't sure if the access type was linked to the container type.  It
> seems obvious now, since you've both made it clear, that it also
> depends on how I'm accessing my container.
> 
> Having said all of this, isn't a D 'range' fundamentally a sequential
> access container (i.e popFront) ?

D ranges are conceptually sequential, but the actual underlying memory
access patterns depends on the concrete type at runtime. An array's
elements are stored sequentially in memory, and arrays are ranges.  But
a linked-list can also have a range interface, yet its elements may be
stored in non-consecutive memory locations.  So the concrete type
matters here; the range API only gives you conceptual sequentiality, it
does not guarantee physically sequential memory access.


T

-- 
Many open minds should be closed for repairs. -- K5 user


Re: foreach (i; taskPool.parallel(0..2_000_000)

2023-04-05 Thread Paul via Digitalmars-d-learn

On Wednesday, 5 April 2023 at 23:06:54 UTC, H. S. Teoh wrote:

So your data structures and algorithms should be designed in a 
way that takes advantage of linear access where possible.



T


Yes I understand, basically, what's going on in hardware.  I just 
wasn't sure if the access type was linked to the container type.  
It seems obvious now, since you've both made it clear, that it 
also depends on how I'm accessing my container.


Having said all of this, isn't a D 'range' fundamentally a 
sequential access container (i.e popFront) ?


Re: constant pointer failing to compile

2023-04-05 Thread Steven Schveighoffer via Digitalmars-d-learn

On 4/5/23 8:59 PM, Mathias LANG wrote:

immutable ubyte[4] data = [1, 2, 3, 4];


Using a static array instead of a slice will do the trick. You can leave 
the `__gshared` if you want, but it is redundant on a global, 
initialized `immutable` variable.


I found out the same thing. But I don't really understand why.

the error message gives a slight clue:

```
cannot use non-constant CTFE pointer in an initializer ‘&[cast(ubyte)1u, 
cast(ubyte)2u, cast(ubyte)3u, cast(ubyte)4u][0]’

```

That *isn't* a CTFE pointer, it's a pointer to a static immutable. Yes, 
the initialization value is a CTFE array, but the variable itself has an 
address. Notice how the expression has turned into an address of the 
initializer.


I think this is a compiler bug.

-Steve


Re: constant pointer failing to compile

2023-04-05 Thread Mathias LANG via Digitalmars-d-learn

immutable ubyte[4] data = [1, 2, 3, 4];


Using a static array instead of a slice will do the trick. You 
can leave the `__gshared` if you want, but it is redundant on a 
global, initialized `immutable` variable.


constant pointer failing to compile

2023-04-05 Thread Josh Holtrop via Digitalmars-d-learn
I am trying to port a small C project to D and am getting a 
compilation error I don't understand.


I've simplified the situation down to the example here.

This C version compiles fine:

```c
#include 

static const unsigned char data[] = {1, 2, 3, 4};

static const unsigned char * p = [0];

int main(int argc, char * argv[])
{
printf("*p = %u\n", *p);
return 0;
}
```

My attempt to do the same in D:

```d
import std.stdio;

__gshared immutable ubyte[] data = [1, 2, 3, 4];

__gshared immutable ubyte * p = data.ptr;

int main()
{
writeln("*p = ", *p);
return 0;
}
```

This fails to compile with gdc:

```
constarrptr.d:5:45: error: cannot use non-constant CTFE pointer 
in an initializer ‘&[cast(ubyte)1u, cast(ubyte)2u, cast(ubyte)3u, 
cast(ubyte)4u][0]’

5 | __gshared immutable(immutable(ubyte) *) p = data.ptr;
  | ^
```

And also with ldc2:

```
constarrptr.d(5): Error: cannot use non-constant CTFE pointer in 
an initializer `cast(immutable(ubyte)*)data`

```

Why? And how can I do the equivalent to what I have been doing in 
C? I want these pointers to be generated at compile time, not 
initialized at runtime.


(the full project is generating this file containing the data 
array (which is much longer) and multiple pointer constants to 
locations within it)


Re: foreach (i; taskPool.parallel(0..2_000_000)

2023-04-05 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Apr 05, 2023 at 10:34:22PM +, Paul via Digitalmars-d-learn wrote:
> On Tuesday, 4 April 2023 at 22:20:52 UTC, H. S. Teoh wrote:
> 
> > Best practices for arrays in hot loops:
[...]
> > - Where possible, prefer sequential access over random access (take
> >   advantage of the CPU cache hierarchy).
> 
> Thanks for sharing Teoh!  Very helpful.
> 
> would this be random access? for(size_t i; i indices?  ...and this be sequential foreach(a;arr) ?
> 
> or would they have to be completely different kinds of containers?  a
> dlang 'range' vs arr[]?
[...]

The exact syntactic construct you use is not important; under the hood,
for(i; i

Re: foreach (i; taskPool.parallel(0..2_000_000)

2023-04-05 Thread Steven Schveighoffer via Digitalmars-d-learn

On 4/5/23 6:34 PM, Paul wrote:

On Tuesday, 4 April 2023 at 22:20:52 UTC, H. S. Teoh wrote:


Best practices for arrays in hot loops:
- Avoid appending if possible; instead, pre-allocate outside the loop.
- Where possible, reuse existing arrays instead of discarding old ones
  and allocating new ones.
- Use slices where possible instead of making copies of subarrays (this
  esp. applies to strings).
- Where possible, prefer sequential access over random access (take
  advantage of the CPU cache hierarchy).


Thanks for sharing Teoh!  Very helpful.

would this be random access? for(size_t i; iindices?

...and this be sequential foreach(a;arr) ?


No, random access is access out of sequence. Those two lines are pretty 
much equivalent, and even a naive compiler is going to produce exactly 
the same generated code from both of them.


A classic example is processing a 2d array:

```d
for(int i = 0; i < arr[0].length; ++i)
   for(int j = 0; j < arr.length; ++j)
 arr[j][i]++;

// vs
for(int j = 0; j < arr.length; ++j)
   for(int i = 0; i < arr[0].length; ++i)
 arr[j][i]++;
```

The first accesses elements *by column*, which means that the array data 
is accessed non-linearly in memory.


To be fair, both are "linear" in terms of algorithm, but one is going to 
be faster because of cache coherency (you are accessing sequential 
*hardware addresses*).


-Steve


Re: foreach (i; taskPool.parallel(0..2_000_000)

2023-04-05 Thread Paul via Digitalmars-d-learn

On Tuesday, 4 April 2023 at 22:20:52 UTC, H. S. Teoh wrote:


Best practices for arrays in hot loops:
- Avoid appending if possible; instead, pre-allocate outside 
the loop.
- Where possible, reuse existing arrays instead of discarding 
old ones

  and allocating new ones.
- Use slices where possible instead of making copies of 
subarrays (this

  esp. applies to strings).
- Where possible, prefer sequential access over random access 
(take

  advantage of the CPU cache hierarchy).


Thanks for sharing Teoh!  Very helpful.

would this be random access? for(size_t i; iusing indices?

...and this be sequential foreach(a;arr) ?

or would they have to be completely different kinds of containers?
a dlang 'range' vs arr[]?




Re: Writing a dejargoniser - producing read ke analysis output in English that explains GDC / LDC asm code’s parameters and clobbers

2023-04-05 Thread z via Digitalmars-d-learn

On Wednesday, 5 April 2023 at 15:19:55 UTC, Cecil Ward wrote:
How much code do you thing I would need to write for this? I’m 
still thinking about its feasibility. I don’t want to invent 
the wheel and write a custom parser by hand, so’d rather steal 
the code using sim eg called ‘a library’. :-)


The idea would be that the user could run this to sanity-check 
her understanding of the sometimes arcane GDC asm code 
outputs/inputs/clobbers syntax, and see what her asm code’s 
constraints are actually going to do rather than what she 
thinks it’s going to do. Clearly I can’t readily start parsing 
the asm body itself, I would just inspect the meta info. (If 
that’s the right word?)


I would have a huge problem with LDC’s alternative syntax 
unless I could think of some way to pre-transform and munge it 
into GDC format.


I do wish LDC (and DMD) would now converge on the GDC asm 
syntax. Do you think that’s reasonably doable?


Maybe try a translator approach? A GDC/LDC to the other(or a 
custom format, maybe even NASM with comments explaining what the 
inline assembly metadata says) translator(assuming x86 here, but 
at a glance it seems ARM is affected by similar MASMvsAT and 
compiler inline assembly nightmare fuel) would probably help, 
especially considering you appear to prefer GDC's inline asm to 
LLVM's.


As for the amount of effort, it will possibly require a few 
structs to represent an intermediary format(maybe) and pattern 
matching routines to convert to that format.


On a more personal note, i was faced with the same 
dissatisfaction you appear to be having and found great success 
with NASM, it was easier to write code for it and also helps get 
one familiarized with usage of D/dub in cross language projects. 
It's also compatible with DMD by virtue of being compiler 
independent.


Using the D-integrated `asm` statement may work but it certainly 
lacks support of too many instructions and registers for me to 
recommend using it.(unless this changed.)


Writing a dejargoniser - producing read ke analysis output in English that explains GDC / LDC asm code’s parameters and clobbers

2023-04-05 Thread Cecil Ward via Digitalmars-d-learn
How much code do you thing I would need to write for this? I’m 
still thinking about its feasibility. I don’t want to invent the 
wheel and write a custom parser by hand, so’d rather steal the 
code using sim eg called ‘a library’. :-)


The idea would be that the user could run this to sanity-check 
her understanding of the sometimes arcane GDC asm code 
outputs/inputs/clobbers syntax, and see what her asm code’s 
constraints are actually going to do rather than what she thinks 
it’s going to do. Clearly I can’t readily start parsing the asm 
body itself, I would just inspect the meta info. (If that’s the 
right word?)


I would have a huge problem with LDC’s alternative syntax unless 
I could think of some way to pre-transform and munge it into GDC 
format.


I do wish LDC (and DMD) would now converge on the GDC asm syntax. 
Do you think that’s reasonably doable?


Re: Virtual method call from constructor

2023-04-05 Thread Steven Schveighoffer via Digitalmars-d-learn

On 4/4/23 3:08 AM, Chris Katko wrote:
Second, could you give me some case examples where this problem occurs? 
Is the issue if I override refresh in a derived class, and the base 
class will accidentally use child.refresh()?




An example of a problem:

```d
class Base
{
   this() { virtualCall(); }
   void virtualCall() {}
}

class Derived : Base
{
   int *data;
   this() { data = new int; }
   override void virtualCall() { *data = 5; }
}
```

A derived class constructor without an explicit `super()` call, is 
injected with a `super()` call at the beginning of the constructor.


So in this case, the `Base` constructor runs before the `Derived` 
constructor. The `Base` ctor calls `virtualCall` before `Derived` is 
ready for it.


To fix this, you can explicitly call `super()` after initializing the data:

```d
this() {data = new int; super(); }
```

So there are ways to do this in a reasonable way, but that is why the 
warning exists.


-Steve


Re: undefined reference to "main"

2023-04-05 Thread Richard (Rikki) Andrew Cattermole via Digitalmars-d-learn
Originally vibe.d included its own main function by default. That is now 
opt-in instead of opt-out. Circa 2016.


You can either add the version ``VibeDefaultMain`` or use a main 
function and call ``runApplication`` yourself.


https://vibed.org/docs#first-steps


Re: undefined reference to "main"

2023-04-05 Thread FeepingCreature via Digitalmars-d-learn
On Wednesday, 5 April 2023 at 09:19:17 UTC, Alexander Zhirov 
wrote:
How to compile the example given in the book correctly? When 
compiling, an error occurs that the main function is missing. 
If I replace `shared static this()` with `void main()', then 
everything starts. What does the compilation string in `dub` 
and `dmd` look like correctly?


```d
import vibe.d;

shared static this()
{
  auto settings = new HTTPServerSettings;
  settings.port = 8080;
  settings.bindAddresses = ["::1", "127.0.0.1"];
  listenHTTP(settings, );

  logInfo("Please open http://127.0.0.1:8080/ in your 
browser.");

}

void hello(HTTPServerRequest req, HTTPServerResponse res)
{
  res.writeBody("Hello, World!");
}
```


This seems to work for me:

```d
/+ dub.json: {
"name": "test",
"dependencies": {
"vibe-d": "*"
}
} +/
import vibe.d;

shared static this()
{
  auto settings = new HTTPServerSettings;
  settings.port = 8080;
  settings.bindAddresses = ["::1", "127.0.0.1"];
  listenHTTP(settings, );

  logInfo("Please open http://127.0.0.1:8080/ in your browser.");
}

void main() {
runApplication;
}

void hello(HTTPServerRequest req, HTTPServerResponse res)
{
  res.writeBody("Hello, World!");
}
```

Run with

```
dub run --single test.d
```


undefined reference to "main"

2023-04-05 Thread Alexander Zhirov via Digitalmars-d-learn
How to compile the example given in the book correctly? When 
compiling, an error occurs that the main function is missing. If 
I replace `shared static this()` with `void main()', then 
everything starts. What does the compilation string in `dub` and 
`dmd` look like correctly?


```d
import vibe.d;

shared static this()
{
  auto settings = new HTTPServerSettings;
  settings.port = 8080;
  settings.bindAddresses = ["::1", "127.0.0.1"];
  listenHTTP(settings, );

  logInfo("Please open http://127.0.0.1:8080/ in your browser.");
}

void hello(HTTPServerRequest req, HTTPServerResponse res)
{
  res.writeBody("Hello, World!");
}
```


Re: Virtual method call from constructor

2023-04-05 Thread Johan via Digitalmars-d-learn

On Tuesday, 4 April 2023 at 07:08:52 UTC, Chris Katko wrote:

dscanner reports this as a warning:

```D
struct foo{
this()
  {
  /* some initial setup */
  refresh();
  }
void refresh() { /* setup some more stuff */}
// [warn] a virtual call inside a constructor may lead to 
unexpected results in the derived classes


}
```

Firstly, are all calls virtual in a struct/class in D? Is this 
any different from C++?


Regarding this warning, the big difference between C++ and D 
classes is that a D class object is of type Child its whole life 
including during the Base class constructor execution. In C++ a 
class object starts as Base, Base::constructor is executed, then 
type is changed to Child (implemented by overwriting the vtable 
pointer), then Child::constructor is executed.


-Johan