Re: foreach (i; taskPool.parallel(0..2_000_000)
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)
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
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
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
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)
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)
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)
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
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
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
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"
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"
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"
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
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