Spec for the ‘locality’ parameter to the LDC and GDC builtin magic functions for accessing special CPU prefetch instructions
I’m trying to write a cross-platform function that gives access to the CPU’s prefetch instructions such as x86 prefetch0/1/2/prefetchnta and AAarch64 too. I’ve found that the GDC and LDC compilers provide builtin magic functions for this, and are what I need. I am trying to put together a plain-English detailed spec for the respective builtin magic functions. My questions: Q1) I need to compare the spec for the GCC and LDC builtin magic functions’ "locality" parameter. Can anyone tell me if GDC and LDC have kept mutual compatibility here? Q2) Could someone help me turn the GCC and LDC specs into english regarding the locality parameter ? - see (2) and (4) below. Q3) Does the locality parameter determine which _level_ of the data cache hierarchy data is fetched into? Or is it always fetched into L1 data cache and the outer ones, and this parameter affects caches’ _future behaviour_? Q3) Will these magic builtins work on AAarch64? Here’s what I’ve found so far 1. GCC builtin published by the D runtime: import gcc.simd : prefetch; prefetch!( rw, locality )( p ); 2. GCC: builtin_prefetch (const void *addr, ...) ¶ “This function is used to minimize cache-miss latency by moving data into a cache before it is accessed. You can insert calls to __builtin_prefetch into code for which you know addresses of data in memory that is likely to be accessed soon. If the target supports them, data prefetch instructions are generated. If the prefetch is done early enough before the access then the data will be in the cache by the time it is accessed. The value of addr is the address of the memory to prefetch. There are two optional arguments, rw and locality. The value of rw is a compile-time constant one or zero; one means that the prefetch is preparing for a write to the memory address and zero, the default, means that the prefetch is preparing for a read. The value locality must be a compile-time constant integer between zero and three. A value of zero means that the data has no temporal locality, so it need not be left in the cache after the access. A value of three means that the data has a high degree of temporal locality and should be left in all levels of cache possible. Values of one and two mean, respectively, a low or moderate degree of temporal locality. The default is three.” 3. declare void @llvm.prefetch(ptr , i32 , i32 , i32 4. Regarding llvm.prefetch() I found the following spec: “rw is the specifier determining if the fetch should be for a read (0) or write (1), and locality is a temporal locality specifier ranging from (0) - no locality, to (3) - extremely local keep in cache. The cache type specifies whether the prefetch is performed on the data (1) or instruction (0) cache. The rw, locality and cache type arguments must be constant integers.” 5. I also found this snippet https://dlang.org/phobos/core_builtins.html - which is great for the syntax of the call to the LDC builtin, but the call for GDC is no good as it lacks the parameters that I want. This D runtime routine might benefit from accepting all the parameters that GCC’s prefetch builtin takes. Many thanks in advance.
Test post - please ignore
I have been getting error messages when I try to post to the forum. This is just a test, so please ignore.
Setting up a final switch from a list
Am I right in thinking that final switch can be used to check that all the elements in an enum are handled in cases? Thinking that this is a worthwhile safety check, I’d like to convert an existing list into an enum for use in a final switch. I have an existing list which I use elsewhere, enum terminators = [ '%', ':', '?' ]; I pass that to some routine. I am wondering how to safely create either an enum with values or have the enum with values declared first and then create the list from it. That is, maybe start the other way around enum terminators_t = { percent = '%', colon = ':', qmark = '?' }; and then automatically generate the list from that. The idea is to avoid duplication in the array list and enum value list, so that if I ever add one, I will not be able to update the other to match. Any suggestions? I need some good compile-time stuff. It doesn’t matter which direction we go in, from one to the other, but my money is on the all-values enum generating the array list.
Re: Anyone help me with a stack dump?
On Monday, 31 July 2023 at 14:38:52 UTC, ryuukk_ wrote: Your problem lies at line 1541 You can use `ddemangle` executable to make mangled names readable, i don't know if it comes with the compiler ``` _platform_memmove pure nothrow ref @trusted wchar[] core.internal.array.appending._d_arrayappendT!(wchar[], char)._d_arrayappendT(scope return ref wchar[], scope wchar[]) void asm_parse.AsmTransformTemplate!(wchar).__unittest_L1541_C1_1() asm_parse.__unittest asm_parse.__unittest asm_parse.__unittest asm_parse.__unittest int core.runtime.runModuleUnitTests().__foreachbody6(object.ModuleInfo*) int rt.minfo.moduleinfos_apply(scope int delegate(immutable(object.ModuleInfo*))).__foreachbody2(ref rt.sections_elf_shared.DSO) int rt.sections_elf_shared.DSO.opApply(scope int delegate(ref rt.sections_elf_shared.DSO)) int rt.minfo.moduleinfos_apply(scope int delegate(immutable(object.ModuleInfo*))) int object.ModuleInfo.opApply(scope int delegate(object.ModuleInfo*)) runModuleUnitTests void rt.dmain2._d_run_main2(char[][], ulong, extern (C) int function(char[][])*).runAll() _d_run_main2 _d_run_main start ``` Thank you all for your help. In the real code I have a struct (object) in the heap but in the unittests I first of all had it in place in the stack, then tried changing to the heap to see if that would fix the problem. That didn’t work. I first ran the struct initialisation routine in each one of the unittests, but I still suspect that the thing is not completely initialised. Maybe I forgot to set something in the init routine and it gets set to a sensible value in subsequent code, but all that code is not running in the unittests. An uninitialised field would be my best guess. I can see the AAarch64 instruction that it dies on and my AAarch64 is non-existent but I’ve done so much asm over the years that I can hazard a guess. It is doing something like p->field and it looks like a read instruction but I’m not sure about the operand ordering as we probably have the stupid ATT asm to deal with. Of course a write instruction is more likely to cause a crash. I could try and work out how to see all the relevant registers, could be p is a null pointer or perhaps just out of range. Really annoying as that code seems to work perfectly in normal use, and disabling that unittest block restores sanity. I really am going to have to go off and do a lot of reading.
Anyone help me with a stack dump?
The unitttests that I have just put in crash spectacularly with an access violation. I built the code with LDC for Aarch64 / OSX and I fired up lldb. I now have to learn lldb quick. (BTW Where can I get an x86 / linux build of lldb or similar ?) This is the stack dump, and I could do with some help decoding parts of it ⋊> cecil@janet-mac-mini ⋊> ~/a/src clear; ./got 14:01:26 0 asm_parse 0x000102a157e4 _D4core7runtime18runModuleUnitTestsUZ19unittestSegvHandlerUNbiPSQCk3sys5posix6signal9siginfo_tPvZv + 56 1 libsystem_platform.dylib0x0001a06f2a24 _sigtramp + 56 2 asm_parse 0x00010297ed88 _D4core8internal5array9appending__T15_d_arrayappendTHTAuTuZQyFNaNbNcNeMNkKQuMQxZQBa + 56 ./got: line 7: 18387 Bus error: 10 ./asm_parse ⋊> cecil@janet-mac-mini ⋊> ~/a/src sudo lldb asm_parse 14:02:49 Password: (lldb) target create "asm_parse" Current executable set to '/Users/cecil/asm_parse/src/asm_parse' (arm64). (lldb) run Process 18406 launched: '/Users/cecil/asm_parse/src/asm_parse' (arm64) Process 18406 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0xfff6) frame #0: 0x0001a06f2860 libsystem_platform.dylib`_platform_memmove + 544 libsystem_platform.dylib`: -> 0x1a06f2860 <+544>: ldpq0, q1, [x1, #-0x20] 0x1a06f2864 <+548>: subx1, x1, #0x20 0x1a06f2868 <+552>: subs x2, x2, #0x20 0x1a06f286c <+556>: b.hi 0x1a06f2858 ; <+536> Target 0: (asm_parse) stopped. (lldb) bt * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0xfff6) * frame #0: 0x0001a06f2860 libsystem_platform.dylib`_platform_memmove + 544 frame #1: 0x00016d88 asm_parse`_D4core8internal5array9appending__T15_d_arrayappendTHTAuTuZQyFNaNbNcNeMNkKQuMQxZQBa + 56 frame #2: 0x0001b1fc asm_parse`_D9asm_parse__T20AsmTransformTemplateTuZ21__unittest_L1541_C1_1FZv + 628 frame #3: 0x00010006b9b8 asm_parse`asm_parse.__unittest + 36 frame #4: 0x00010009d83c asm_parse`_D4core7runtime18runModuleUnitTestsUZ14__foreachbody6MFPS6object10ModuleInfoZi + 56 frame #5: 0x0001000ac620 asm_parse`_D2rt5minfo17moduleinfos_applyFMDFyPS6object10ModuleInfoZiZ14__foreachbody2MFKSQCz19sections_elf_shared3DSOZi + 68 frame #6: 0x0001000acee0 asm_parse`_D2rt19sections_elf_shared3DSO7opApplyFMDFKSQBqQBqQyZiZi + 56 frame #7: 0x0001000ac5b0 asm_parse`_D2rt5minfo17moduleinfos_applyFMDFyPS6object10ModuleInfoZiZi + 32 frame #8: 0x0001000a21a4 asm_parse`_D6object10ModuleInfo7opApplyFMDFPSQBhQBdZiZi + 32 frame #9: 0x00010009d6b0 asm_parse`runModuleUnitTests + 184 frame #10: 0x0001000a6518 asm_parse`_D2rt6dmain212_d_run_main2UAAamPUQgZiZ6runAllMFZv + 32 frame #11: 0x0001000a641c asm_parse`_d_run_main2 + 376 frame #12: 0x0001000a6288 asm_parse`_d_run_main + 148 frame #13: 0x0001a036bf28 dyld`start + 2236 (lldb)
Re: Unicode in strings
On Thursday, 27 July 2023 at 22:35:00 UTC, Adam D Ruppe wrote: On Thursday, 27 July 2023 at 22:15:47 UTC, Cecil Ward wrote: How do I get a wstring or dstring with a code point of 0xA0 in it ? note that you don't need wstring and dstring to express all unicode strings. I realised that I was probably generating UTF8 and only one byte, so I switched to \u00A0, I think. Must have got that wrong too because I was still getting the error message. I’ll try it again carefully.
Re: What is a dchar ?
On Wednesday, 26 July 2023 at 01:56:28 UTC, Richard (Rikki) Andrew Cattermole wrote: The spec says they are unsigned, so if ldc is using sign extension, that is probably a bug. My fault, I reread the code and the sign-extension applies to something else, coincidentally right where I was looking at this. It uses signed 32-bit displacements in a case/switch table of offsets into the code segment, and that was what mislead me. It could have used unsigned displacements but then all the labels in the code would have to be above the reference base point, and this allows +/- offsets to anywhere. So my apologies.
Re: Giant template - changing types everywhere
On Friday, 14 July 2023 at 14:15:29 UTC, Steven Schveighoffer wrote: On 7/14/23 1:51 AM, Cecil Ward wrote: [...] So templates don't automatically instantiate, you have to specify them. And then if your function is inside the template, to access it, you will need to do: [...] I can give you the code if you wish. I am cecil (at) cecil ward (dot) com. I can’t thank you enough for your generous help. I don’t want you to get sucked into a black hole with this though. I don’t understand why the public keyword fails to work inside a template, but I suppose that that’s just a wishlist feature.
Re: Giant template - changing types everywhere
On Friday, 14 July 2023 at 05:09:58 UTC, Cecil Ward wrote: On Friday, 14 July 2023 at 05:05:27 UTC, Cecil Ward wrote: On Friday, 14 July 2023 at 05:03:31 UTC, Cecil Ward wrote: On Friday, 14 July 2023 at 01:34:54 UTC, Steven Schveighoffer wrote: [...] The way I can see it going is a giant template encompassing pretty much the whole file. Does that mean that the caller who calls my one public function does so by passing the type dchar or wchar ? And then we generate the strings from that. It might be rather more natural for the caller to pass one of the string types into the template. That’s where I get rather more confused, say caller calls Transform(dstring)(dstring str) or can they just do Transform( "str"d ) and it would work out that the type is immutable dchar[] ? Perhaps I should just make up a small example file with two functions in it to see if I can get the syntax right? If I wrap the whole thing with a template declaration of the xchar type, then can I get away with no changes to the individual function definitions? I tried it, wrapped the whole thing in a template definition and it compiled, but then my test file which calls Transform( someDString ) failed to compile with errors saying it couldn’t find the definition of Transform in the other module, which is or was public. It’s as if it is no longer public because it’s now inside the template.
Re: Giant template - changing types everywhere
On Friday, 14 July 2023 at 05:05:27 UTC, Cecil Ward wrote: On Friday, 14 July 2023 at 05:03:31 UTC, Cecil Ward wrote: On Friday, 14 July 2023 at 01:34:54 UTC, Steven Schveighoffer wrote: [...] The way I can see it going is a giant template encompassing pretty much the whole file. Does that mean that the caller who calls my one public function does so by passing the type dchar or wchar ? And then we generate the strings from that. It might be rather more natural for the caller to pass one of the string types into the template. That’s where I get rather more confused, say caller calls Transform(dstring)(dstring str) or can they just do Transform( "str"d ) and it would work out that the type is immutable dchar[] ? Perhaps I should just make up a small example file with two functions in it to see if I can get the syntax right? If I wrap the whole thing with a template declaration of the xchar type, then can I get away with no changes to the individual function definitions?
Re: Giant template - changing types everywhere
On Friday, 14 July 2023 at 05:03:31 UTC, Cecil Ward wrote: On Friday, 14 July 2023 at 01:34:54 UTC, Steven Schveighoffer wrote: [...] The way I can see it going is a giant template encompassing pretty much the whole file. Does that mean that the caller who calls my one public function does so by passing the type dchar or wchar ? And then we generate the strings from that. It might be rather more natural for the caller to pass one of the string types into the template. That’s where I get rather more confused, say caller calls Transform(dstring)(dstring str) or can they just do Transform( "str"d ) and it would work out that the type is immutable dchar[] ? Perhaps I should just make up a small example file with two functions in it to see if I can get the syntax right?
Re: Giant template - changing types everywhere
On Friday, 14 July 2023 at 01:34:54 UTC, Steven Schveighoffer wrote: On 7/13/23 8:08 PM, Cecil Ward wrote: What I really want to do though is provide one single templated function with the kind of characters / strings as a parameter. I want to have something like T Transform( T )( T str) called as auto result = Transform!(dstring)( dstring str ); ```d T[] Transform(T)(T[] str) ``` Note that you don't have to specify the type when calling: ```d Transform(someDstring); // infers dchar ``` I’m quite confused as to how to proceed. This is quite a large module ~ 2k loc, and I don’t really want to go through and change every private function into a templated one. Should I just make the whole thing into a giant template containing many functions? If you have more questions, please ask. Some examples of how making a template would be painful would be helpful. -Steve The way I can see it going is a giant template encompassing pretty much the whole file. Does that mean that the caller who calls my one public function does so by passing the type dchar or wchar ? And then we generate the strings from that. It might be rather more natural for the caller to pass one of the string types into the template. That’s where I get rather more confused, say caller calls Transform(dstring)(dstring str) or can they just do Transform( "str"d ) and it would work out that the type is immutable dchar[] ?
Giant template - changing types everywhere
Some advice on a couple of points. I have been working on a module that works on either dchar / dstrings or wchar / wstrings with just two changes of alias definitions and a recompile. What I really want to do though is provide one single templated function with the kind of characters / strings as a parameter. I want to have something like T Transform( T )( T str) called as auto result = Transform!(dstring)( dstring str ); I only want to have one type as a parameter and derive other types from that: xstrings from xchars and I’ll need types of xchar arrays that are mutable and immutable. I’m quite confused as to how to proceed. This is quite a large module ~ 2k loc, and I don’t really want to go through and change every private function into a templated one. Should I just make the whole thing into a giant template containing many functions?
Re: Installing GDC / Linux / x86-64 when apt-get doesn’t work
On Tuesday, 11 July 2023 at 05:49:36 UTC, Sergey wrote: On Tuesday, 11 July 2023 at 04:11:38 UTC, Cecil Ward wrote: I’m trying to install GDC on a new Linux box and I don’t know what I’m doing. Background: I have installed LDC successfully and have installed GDC on a Raspberry Pi using 32-bit ARM. For some reason the apt-get command doesn’t work on this machine, don’t know why. The machine is a virtual server hosted on the internet and I can get support for the o/s. What is the recommended procedure for fetching the x86-64 prec-compiled GDC? Check the web about reprex and write what have you tried to run, which error you got, some more information about the system, root rights. Have you tried to download deb package manually and use dpkg command? I think the problem might have been that I did apt-get not apt and I was not running as root, just now I elevated with sudo and ran apt -y install gdc and that worked so by fumbling about I appear to have solved it. That was the x86-64 box. I haven’t been able to install GDC on my Apple M2 ARM Aarch64 Mac though, no idea how to find it for OSX Aarch64.
Re: Installing GDC / Linux / x86-64 when apt-get doesn’t work
On Tuesday, 11 July 2023 at 04:11:38 UTC, Cecil Ward wrote: I’m trying to install GDC on a new Linux box and I don’t know what I’m doing. Background: I have installed LDC successfully and have installed GDC on a Raspberry Pi using 32-bit ARM. For some reason the apt-get command doesn’t work on this machine, don’t know why. The machine is a virtual server hosted on the internet and I can get support for the o/s. What is the recommended procedure for fetching the x86-64 prec-compiled GDC? The OS is Debian v 12 x86_64.
Installing GDC / Linux / x86-64 when apt-get doesn’t work
I’m trying to install GDC on a new Linux box and I don’t know what I’m doing. Background: I have installed LDC successfully and have installed GDC on a Raspberry Pi using 32-bit ARM. For some reason the apt-get command doesn’t work on this machine, don’t know why. The machine is a virtual server hosted on the internet and I can get support for the o/s. What is the recommended procedure for fetching the x86-64 prec-compiled GDC?
Pre-expanding alloc cell(s) / reserving space for an associative array
Before I posted a question about avoiding unnecessary allocs/reallocs when adding entries to an array like so uint[ dstring ] arr; when I build it up from nothing with successive insertions. The array is accessed by a key that is a dstring. I was told that I can’t use .reserve or the like on it? Is that correct? My memory fails me, powerful pain drugs. Is there an alternate method I could use ? To be honest, the number of entries is likely to be extremely modest, so this is not a huge performance issue, six entries would be considered quite a lot. The string keys are probably not very very long. But I’m learning good habits for the day when I might have a bigger such database.
Re: Inlined functions and their original bodies - bloat
On Sunday, 9 July 2023 at 18:04:13 UTC, Cecil Ward wrote: I have a program where the various routines are all marked pragma( inline, true ). The compiler obeys this but the LDC and GDC compilers still compile the function bodies even though the bodies are not needed as they are supposed to be ‘private’ to the module, explicitly marked as such, hoping that that is like static in C. There are no pointers to the routines, so no need for the bodies because of any indirect calls. Is there a way to control this code bloat in LDC / GDC ? Using the godbolt compiler explorer with LDC and GDC I can indeed see that the code is being inlined. Does this count as a compiler performance-type bug? This is with full -O3 optimisation and -release / -frelease for LDC and GDC respectively.
Re: Toolchain with ldc and AArch64 OSX
On Sunday, 9 July 2023 at 05:32:56 UTC, Danilo Krahn wrote: On Saturday, 24 June 2023 at 15:16:37 UTC, Cecil Ward wrote: I have LDC running on an ARM Mac. If anyone else out there is an LDC or GDC user, could you knock up a quick shell program to compile and link a .d file to produce an executable ? found the linker but these tools are all new to me and a bit of help would save me a lot of trial and error and frustration as I try to find docs. GDC would be great too. I have managed to achieve this before on a Raspberry Pi AArch64 Linux Debian where the compiler can link and generate an executable just in integrated fashion in the one command. The OSX tools seem rather different however. ```d import std.stdio : writeln; void main() { writeln("Hello, world!"); } ``` Compilation using LDC on macOS is just: ``` ldc2 --release --O3 main.d ``` Or some more options, to reduce executable size: ``` ldc2 --release --O3 --flto=full -fvisibility=hidden -defaultlib=phobos2-ldc-lto,druntime-ldc-lto -L=-dead_strip -L=-x -L=-S -L=-lz main.d ``` Executable size using first command: 1.3MB Executable size using second command: 756KB Brilliant, much appreciated! :) I posted ages ago about the bloat that I see where function bodies are compiled even though they are in fact always inlined and so the original body is never needed. The address of these functions is not taken, so no indirect pointer calling, and the functions are all explicitly private which I hope is like static in C? Anyway, no one is calling them from outside the module.
Re: Dynamic array of strings and appending a zero length array
On Saturday, 8 July 2023 at 20:01:08 UTC, H. S. Teoh wrote: On Sat, Jul 08, 2023 at 05:15:26PM +, Cecil Ward via Digitalmars-d-learn wrote: I have a dynamic array of dstrings and I’m spending dstrings to it. At one point I need to append a zero-length string just to increase the length of the array by one but I can’t have a slot containing garbage. I thought about ++arr.length - would that work, while giving me valid contents to the final slot ? Unlike C/C++, the D runtime always ensures that things are initialized unless you explicitly tell it not to (via void-initialization). So ++arr.length will work; the new element will be initialized to dstring.init (which is the empty string). T Many thanks, it might give me a slightly better result just doing ++arr.length;
Re: Dynamic array of strings and appending a zero length array
On Saturday, 8 July 2023 at 17:15:26 UTC, Cecil Ward wrote: I have a dynamic array of dstrings and I’m spending dstrings to it. At one point I need to append a zero-length string just to increase the length of the array by one but I can’t have a slot containing garbage. I thought about ++arr.length - would that work, while giving me valid contents to the final slot ? [...] s/spending/appending/
Dynamic array of strings and appending a zero length array
I have a dynamic array of dstrings and I’m spending dstrings to it. At one point I need to append a zero-length string just to increase the length of the array by one but I can’t have a slot containing garbage. I thought about ++arr.length - would that work, while giving me valid contents to the final slot ? What I first did was arr ~= []; This gave no errors but it doesn’t increase the array length, so it seems. Is that a bug ? Or is it supposed to do that? Then I tried arr ~= ""d; and that did work. Is there anything more efficient that I could do instead? I actually have an alias for the type of the strings so that they can be either dstrings or wstrings with just a recompilation. How should I then generate a zero-length string that has th correct type of dstring or wstring as I am stuck with the ‘d’-suffix on the end of the ""d at the moment. Can I just cast ? Not a reinterpret cast, but a proper value conversion?
Re: Public visible entities published by a module
On Friday, 7 July 2023 at 19:49:06 UTC, Anonymouse wrote: On Friday, 7 July 2023 at 17:46:09 UTC, Cecil Ward wrote: [...] I did this. It's super ugly and even has `__traits(compiles)` in there, but as a quick and dirty solution it served well enough. ```d void printPublicMembersOfModule(string module_)() { mixin("import thisModule = " ~ module_ ~ ";"); foreach (symstring; __traits(allMembers, thisModule)) { alias symbol = __traits(getMember, thisModule, symstring); static if ( __traits(compiles, __traits(getVisibility, symbol)) && __traits(getVisibility, symbol) == "public") { pragma(msg, symstring); } } } void main() { printPublicMembersOfModule!"std.stdio"(); } ``` https://run.dlang.io/is/tvNDdp Wow, thankyou so much for your generous reply.
Public visible entities published by a module
A bit of a weird question, and I’m not sure how to word it. Say I have a module, and I’d like to list / enumerate all the public visible things that the module exports / publishes ‘ makes visible. Is there a way of doing that ? Of getting that kind of listing? I’m wondering about information leaking when things should be encapsulated.
Re: First module
On Friday, 7 July 2023 at 14:18:35 UTC, Richard (Rikki) Andrew Cattermole wrote: 1. Compiler reads in source code provided on cli 2. It gets parsed 3. imports get looked up, if not already read in, looks in the directories provided by -I based upon the full module + package import statement 4. Finish compilation 5. Linker gets passed object files to produce some artifact like an executable Very rough idea of how it works, but will do for what you are asking about. As long as you compile all at once, assume inlining will work if it thinks it should. Modules will not affect it. Brilliant, thanks Rikki.
Re: First module
On Thursday, 6 July 2023 at 21:10:39 UTC, Cecil Ward wrote: I’ve written my first non-trivial module in D. See other thread. https://forum.dlang.org/thread/pfjpqcywxrmxwsncy...@forum.dlang.org I’d like to set up something to call it from other modules, and specifically I’d like to see if inlining works across module boundaries - I have no idea whether it does or not as I don’t understand fully in detail how module imports work. How do I go about setting up such a test harness with LDC (or GDC) on either OSX/ARM or Linux Debian x86-64? I’m not sure what tools I need. Note that I cannot use DMD, this code is LDC/GDC-specific. LDC would be my preference as that is what it is ultimately aimed at. Do I just provide two filenames as inputs to the compiler ? I’m wondering if the compiler resolves the import statements rather than the linker - is that right? I only have a vague understanding of how the import statement works - pulling in digested intermediate-code or something? Will in-line functions be inlined even if the called routine is across a module boundary?
Re: Advice on debugging possible exception or crash
On Thursday, 6 July 2023 at 19:53:39 UTC, Chris Katko wrote: On Thursday, 6 July 2023 at 06:00:04 UTC, Cecil Ward wrote: My program is instrumented with a load of writeflns. At one point it looks as though it suddenly quits prematurely because the expected writeflns are not seen in the output. It could be that I am just reading the flow of control wrong as it goes ret, ret etc. I’m wondering if it is throwing an exception, or has a fault initiating a crash, perhaps even due to the fetching of arguments of one of the writeflns. In my limited experience, exceptions produce an error message though, and I’m not seeing anything. Any advice on how to debug this, silent termination ? I don’t have a debugger on this machine, but on an x86-64 box I could use gdb if I first take the time to work out how. one thing I do is have gdb/lldb break on d assert, before it destroys the stack. That helped me catch a class of bugs. ```sh # in the gdb interface before running break _d_assertp break _d_assert break _d_assert_msg # or to combine it into the commandline: gdb -ex "break _d_assert" -ex "break _d_assert_msg" -ex "run $1" ./main # can also add it to your .gdbinit startup code. This is brilliant advice. I’m building with LDC and in debug mode with -g, however gdb says it can’t find any symbol table or debug info, can’t even set breakpoints by line numbers. The Matt Godbolt Compiler Explorer can go to source line numbers in the asm. So I’m just missing something.
First module
I’ve written my first non-trivial module in D. See other thread. https://forum.dlang.org/thread/pfjpqcywxrmxwsncy...@forum.dlang.org I’d like to set up something to call it from other modules, and specifically I’d like to see if inlining works across module boundaries - I have no idea whether it does or not as I don’t understand fully in detail how module imports work. How do I go about setting up such a test harness with LDC (or GDC) on either OSX/ARM or Linux Debian x86-64? I’m not sure what tools I need. Note that I cannot use DMD, this code is LDC/GDC-specific. LDC would be my preference as that is what it is ultimately aimed at.
Re: Advice on debugging possible exception or crash
On Thursday, 6 July 2023 at 07:09:11 UTC, Richard (Rikki) Andrew Cattermole wrote: On 06/07/2023 7:07 PM, Cecil Ward wrote: On Thursday, 6 July 2023 at 06:17:34 UTC, Richard (Rikki) Andrew Cattermole wrote: 2 Recommendations: 1. Attach a debugger 2. Make sure to flush stdout whenever you write I assumed that buffering was to blame. How do I flush stdout? stdout.flush; https://dlang.org/phobos/std_stdio.html#.stdout Many, many thanks once again.
Re: Advice on debugging possible exception or crash
On Thursday, 6 July 2023 at 06:17:34 UTC, Richard (Rikki) Andrew Cattermole wrote: 2 Recommendations: 1. Attach a debugger 2. Make sure to flush stdout whenever you write I assumed that buffering was to blame. How do I flush stdout? I moved to an x86-64 box. I was using my ARM M2 Mac for which I have no debugger. There must be one somewhere though. I got a visible crash on the x86 machine, array index off the end by one, so I attached gdb and saw the bug. Yay! I’m not sure why there was no crash error message on the ARM Mac though. I had the array length wildly wrong. I then fixed the offending code that was doing the accounting wrongly.
Advice on debugging possible exception or crash
My program is instrumented with a load of writeflns. At one point it looks as though it suddenly quits prematurely because the expected writeflns are not seen in the output. It could be that I am just reading the flow of control wrong as it goes ret, ret etc. I’m wondering if it is throwing an exception, or has a fault initiating a crash, perhaps even due to the fetching of arguments of one of the writeflns. In my limited experience, exceptions produce an error message though, and I’m not seeing anything. Any advice on how to debug this, silent termination ? I don’t have a debugger on this machine, but on an x86-64 box I could use gdb if I first take the time to work out how.
Re: Zapping a dynamic string
On Tuesday, 4 July 2023 at 17:46:22 UTC, Steven Schveighoffer wrote: On 7/4/23 1:01 PM, Cecil Ward wrote: I have a mutable dynamic array of dchar, grown by successively appending more and more. When I wish to zap it and hand the contents to the GC to be cleaned up, what should I do? What happens if I set the .length to zero? If you want to forget it so the GC can clean it up, set it to `null`. If you set the length to 0, the array reference is still pointing at it. If you want to reuse it (and are sure that no other things are referring to it), you can do: ```d arr.length = 0; arr.assumeSafeAppend; ``` Now, appending to the array will reuse the already-allocated buffer space. Obviously, if you have data in there that is still used, you don't want to use this option. -Steve Many many thanks for that tip, Steve!
Inserting into zero-length dynamic array
I have a dynamic array of strings of length zero. When i write to the first element the program crashes, not surprisingly, but what should I be doing? dstring[] arr; arr[0] = "my string"d; // BANG !!
Re: Zapping a dynamic string
On Tuesday, 4 July 2023 at 17:01:42 UTC, Cecil Ward wrote: I have a mutable dynamic array of dchar, grown by successively appending more and more. When I wish to zap it and hand the contents to the GC to be cleaned up, what should I do? What happens if I set the .length to zero? I do want to restart the .length at zero in any case as I’m going to begin the appending afresh, so I wish to restart from nothing.
Re: Bug in usage of associative array: dynamic array with string as a key
On Friday, 30 June 2023 at 19:05:23 UTC, Cecil Ward wrote: I have code roughly like the following: dstring str = "name"d; uint ordinal = (( str in Decls.ordinals ) !is null) ? Decls.ordinals[ str ] : -1; struct Decls { uint[ dstring] ordinals; } //and Decls.ordinals[ str ] = ordinal_counter++; The problem is that it always returns ordinal== -1 from the expression. Can you sort me out? I took this from the example given in the language reference under arrays, testing for membership (or similar, I forget the subssection title). From good old printfs it seems to be the case that the array is being populated (elsewhere) with the expected correct values. Taking out the if doesn’t seem to help either. I don’t have a way of examining the contents of the dynamic array directly to check that they are actually being stored as expected, other than seeing that that line of code is indeed being executed with the expected values of str going in. Note that I’m using 32-bit dstrings everywhere, not strings of bytes. Fool that I am. I did those good old printfs a while back, and now I recheck them I see that something has become broken and it seems that the insertions are not happening now. So thankyou for your kindness and I’ll post again if that doesn’t solve the non-issue.
Re: Bug in usage of associative array: dynamic array with string as a key
On Friday, 30 June 2023 at 21:25:23 UTC, H. S. Teoh wrote: On Fri, Jun 30, 2023 at 07:05:23PM +, Cecil Ward via Digitalmars-d-learn wrote: [...] It would help if you could post the complete code that reproduces the problem. Or, if you do not wish to reveal your code, reduce it to a minimal case that still exhibits the same problem, so that we can see it for ourselves. The snippets you provided do not provide enough information to identify the problem. T I would indeed need to cut it down massively, as the original code is ~2k lines. Mind you, I will just end up with the example at https://dlang.org/spec/hash-map.html#testing_membership in the language docs, under associative arrays - 13.3 testing membership. Would anyone else care to try that example out as that might be quicker? That’s because as all I did was copy that basically, with the only substantive change being deleting the variable p, but I’m still testing whether or not I get a null pointer. I thought I had checked that the insertions were all as expected, so I’ll go and recheck that next.
Re: Bug in usage of associative array: dynamic array with string as a key
On Friday, 30 June 2023 at 19:58:39 UTC, FeepingCreature wrote: On Friday, 30 June 2023 at 19:05:23 UTC, Cecil Ward wrote: I have code roughly like the following: dstring str = "name"d; uint ordinal = (( str in Decls.ordinals ) !is null) ? Decls.ordinals[ str ] : -1; struct Decls { uint[ dstring] ordinals; } //and Decls.ordinals[ str ] = ordinal_counter++; The problem is that it always returns ordinal== -1 from the expression. Can you sort me out? Impossible to tell without a complete repro, I'm afraid. The expression, at least, looks correct at first glance. Note that you can do `uint ordinal = Decls.ordinals.get(str, -1);`. Is the second argument an ‘else’ then, my friend?
Re: Bug in usage of associative array: dynamic array with string as a key
On Friday, 30 June 2023 at 20:12:08 UTC, Ali Çehreli wrote: On 6/30/23 12:05, Cecil Ward wrote: > I have code roughly like the following: > > dstring str = "name"d; Aside: One almost never needs dstring. > uint ordinal = (( str in Decls.ordinals ) !is null) ? > Decls.ordinals[ str ] : -1; > > struct Decls > { > uint[ dstring] ordinals; Do you mean 'ordinals' is 'static'? Otherwise, Decls.ordinals does not compile. > } > > //and > Decls.ordinals[ str ] = ordinal_counter++; Are you doing that *after* you initialize 'ordinal' as you show here? :) Ali Hi Ali, ‘ordinal’ is a static initialised explicitly with zero.
Bug in usage of associative array: dynamic array with string as a key
I have code roughly like the following: dstring str = "name"d; uint ordinal = (( str in Decls.ordinals ) !is null) ? Decls.ordinals[ str ] : -1; struct Decls { uint[ dstring] ordinals; } //and Decls.ordinals[ str ] = ordinal_counter++; The problem is that it always returns ordinal== -1 from the expression. Can you sort me out? I took this from the example given in the language reference under arrays, testing for membership (or similar, I forget the subssection title). From good old printfs it seems to be the case that the array is being populated (elsewhere) with the expected correct values. Taking out the if doesn’t seem to help either. I don’t have a way of examining the contents of the dynamic array directly to check that they are actually being stored as expected, other than seeing that that line of code is indeed being executed with the expected values of str going in. Note that I’m using 32-bit dstrings everywhere, not strings of bytes.
Re: Debugging by old fashioned trace log printfs / writefln
On Thursday, 29 June 2023 at 23:54:45 UTC, Chris Katko wrote: On Thursday, 29 June 2023 at 18:27:22 UTC, Cecil Ward wrote: I’m trying to debug my D program with old-fashioned printfs stuck in various strategic places, actually using writefln(). My problem is that the addition of printf fights with the existing declarations for pure nothrow @nogc @safe and I have to adjust them, then put them back correctly when the writefln() trace statements are later removed. Is there something else I could be using, something that is allowed to violate the checking rules for purity, nothrow, @nogc? Would pragma( msg, "…" ) do the trick? Is that what I should be using? pragma(msg, "") is only for compile time. It for debugging functions/templates if they're actually used (which static path is used), instantiated, and you can also get type values from template inputs to confirm they're what you expect. "Oh this is a char[][] not a char[]!" pragmas are the D equivalent of C/C++ pragmas. In this case, C/C++: ```C #pragma message( message-string ) ``` Since I can pass my main function some compile-time-defined input, the whole program should be capable of being executed with CTFE, no? So in that case pragma( msg ) should suffice for a test situation? Would pragma(message) have the advantage over writefln that I don’t have to pervert the function attributes like nogc nothrow pure ?
Debugging by old fashioned trace log printfs / writefln
I’m trying to debug my D program with old-fashioned printfs stuck in various strategic places, actually using writefln(). My problem is that the addition of printf fights with the existing declarations for pure nothrow @nogc @safe and I have to adjust them, then put them back correctly when the writefln() trace statements are later removed. Is there something else I could be using, something that is allowed to violate the checking rules for purity, nothrow, @nogc? Would pragma( msg, "…" ) do the trick? Is that what I should be using?
Re: Counting an initialised array, and segments
On Monday, 26 June 2023 at 22:19:25 UTC, Jonathan M Davis wrote: On Monday, June 26, 2023 1:09:24 PM MDT Cecil Ward via Digitalmars-d-learn wrote: [...] [...] I completely agree with everything you said. I merely used aliases to give me the freedom to switch between having text in either UTF16 or UTF32 in memory, and see how the performance changes. That’s the only reason for me doing that. I also want to keep a clear distinction between words in me memory and code points in registers.
Re: Counting an initialised array, and segments
On Monday, 26 June 2023 at 12:28:15 UTC, Jonathan M Davis wrote: On Monday, June 26, 2023 5:08:06 AM MDT Cecil Ward via Digitalmars-d-learn wrote: On Monday, 26 June 2023 at 08:26:31 UTC, Jonathan M Davis wrote: > On Sunday, June 25, 2023 4:08:19 PM MDT Cecil Ward via > > Digitalmars-d-learn wrote: >> I recently had some problems >> >> dchar[] arr = [ ‘ ‘, TAB, CR, LF … ]; >> >> and I got errors from the compiler which led to me having to >> count the elements in the initialiser and declare the array >> with >> an explicit size. I don’t want the array to be mutable so I >> later >> added immutable to it, but that didn’t help matters. At one >> point, because the array was quite long, I got the arr[ >> n_elements ] number wrong, it was too small and the >> remainder >> of >> the array was full of 0xffs (or something), which was good, >> helped me spot the bug. >> >> Is there any way to get the compiler to count the number of >> elements in the initialiser and set the array to that size >> ? And it’s immutable. > > Without seeing the errors, I can't really say what the > problem was, but most character literals are going to be > char, not dchar, so you may have had issues related to the > type that the compiler was inferring for the array literal. > I don't recall at the moment how exactly the compiler > decides the type of an array literal when it's given values > of differing types for the elements. > > Either way, if you want a static array, and you don't want > to have to count the number of elements, then > https://dlang.org/phobos/std_array.html#staticArray should > take care of that problem. > > - Jonathan M Davis Where I used symbolic names, such as TAB, that was defined as an int (or uint) enum TAB = 9; or enum uint TAB = 9; I forget which. So I had at least one item that was typed something wider than a char. I tried the usual sizeof( arr )/ sizeof dchar, compiler wouldn’t have that for some reason, and yes I know it should be D syntax, god how I long for C sizeof()! sizeof is a property in D. So, you can do char.sizeof or varName.sizeof. But regardless, there really is no reason to use sizeof with D arrays under normal circumstances. And in the case of dynamic arrays, sizeof will give you the size of the dynamic array itself, not the slice of memory that it refers to. You're essentially using sizeof on struct DynamicArray(T) { size_t length; T* ptr; } which is not going to tell you anything about the memory it points to. The length property of an array already tells you the length of the array (be it static or dynamic), so using sizeof like you're talking about really does not apply to D. And I wouldn't advise using uint for a character in D. That's what char, wchar, and dchar are for. Depending on the circumstances, you get implicit conversions between character and integer types, but they are distinct types, and mixing and matching them willy-nilly could result in compilation errors depending on what your code is doing. - Jonathan M Davis No, point taken, a sloppy example. I don’t in fact do that in the real code. I use dchar everywhere appropriate instead of uint. In fact I have aliases for dstring and dchar and successfully did an alternative build with the aliases renamed to use 16-bits wchar / w string instead of 32-bits and rebuilt and all was well, just to test that it is code word size-independent. I would need to do something different though if I ever decided to change to use 16-bit code words in memory because I would still be wanting to manipulate 32-bit values for char code points when they are being handled in registers, for efficiency too as well as code correctness, as 16-bit ‘partial words’ are bad news for performance on x86-64. I perhaps ought to introduce a new alias called codepoint, which is always 32-bits, to distinguish dchar in registers from words in memory. It turns out that I can get away with not caring about utf16, as I’m merely _scanning_ a string. I couldn’t ever get away with changing the in-memory code word type to be 8-bit chars, and then using utf8 though, as I do occasionally deal with non-ASCII characters, and I would have to either preconvert the Utf8 to do the decoding, or parse 8-bit code words and handle the decoding myself on the fly which would be madness. If I have to handle utf8 data I will just preconvert it.
Re: Scope guards
On Monday, 26 June 2023 at 17:41:16 UTC, Paul Backus wrote: On Saturday, 24 June 2023 at 17:00:36 UTC, Cecil Ward wrote: I would like to use scope guards but in the guard I need to get access to some local variables at the end of the routine. This doesn’t really seem to make sense as to how it would work, because their values depend on the exact point where the scope guard is called at in the last, exiting line(s) of the routine. Am I misunderstanding? Scope guards are syntax sugar for try/catch/finally. For example, when you write auto f = open("foo"); scope(exit) close(f); doSomethingWith(f); ...it gets transformed by the compiler into auto f = open("foo"); try { doSomethingWith(f); } finally { close(f); } I do not understand exactly what the problem is you are having, but hopefully this lets you figure out how to solve it. Sorry for being stupid, but say you have something like this == { size_t p = offset; ++p; scope(exit) { writeOutput( 0, p ); ++p … ++p; return; } == The correctness of its behaviour depends on what the value of p is when it calls writeOutput(), and the value of p is being changed. To be correct, the final value of p needs to be passed to writeOutput( p ). That was what I was worrying about. I could have course introduce another variable to capture this final value and use that in the scope guard, but then I can’t make the scope guard general if I have more than one exit route. The compiler sounded as if it did not like the local variable p in the scope guard, but I need to try it again to get the error message.
Re: Counting an initialised array, and segments
On Monday, 26 June 2023 at 08:26:31 UTC, Jonathan M Davis wrote: On Sunday, June 25, 2023 4:08:19 PM MDT Cecil Ward via Digitalmars-d-learn wrote: I recently had some problems dchar[] arr = [ ‘ ‘, TAB, CR, LF … ]; and I got errors from the compiler which led to me having to count the elements in the initialiser and declare the array with an explicit size. I don’t want the array to be mutable so I later added immutable to it, but that didn’t help matters. At one point, because the array was quite long, I got the arr[ n_elements ] number wrong, it was too small and the remainder of the array was full of 0xffs (or something), which was good, helped me spot the bug. Is there any way to get the compiler to count the number of elements in the initialiser and set the array to that size ? And it’s immutable. Without seeing the errors, I can't really say what the problem was, but most character literals are going to be char, not dchar, so you may have had issues related to the type that the compiler was inferring for the array literal. I don't recall at the moment how exactly the compiler decides the type of an array literal when it's given values of differing types for the elements. Either way, if you want a static array, and you don't want to have to count the number of elements, then https://dlang.org/phobos/std_array.html#staticArray should take care of that problem. - Jonathan M Davis Where I used symbolic names, such as TAB, that was defined as an int (or uint) enum TAB = 9; or enum uint TAB = 9; I forget which. So I had at least one item that was typed something wider than a char. I tried the usual sizeof( arr )/ sizeof dchar, compiler wouldn’t have that for some reason, and yes I know it should be D syntax, god how I long for C sizeof()!
Counting an initialised array, and segments
I recently had some problems dchar[] arr = [ ‘ ‘, TAB, CR, LF … ]; and I got errors from the compiler which led to me having to count the elements in the initialiser and declare the array with an explicit size. I don’t want the array to be mutable so I later added immutable to it, but that didn’t help matters. At one point, because the array was quite long, I got the arr[ n_elements ] number wrong, it was too small and the remainder of the array was full of 0xffs (or something), which was good, helped me spot the bug. Is there any way to get the compiler to count the number of elements in the initialiser and set the array to that size ? And it’s immutable. The only reason that I’m giving it a name is that I want the object to be used in several places and I don’t want multiple copies of it in the code/readonly initialised data segment. Another couple of unrelated questions: is there such a thing as a no-execute initialised readonly data segment? I’m seeing immutables going into the code segment, I think, with x86 LDC at least, can’t remember about GDC. Anyway on x86-64 immutables are addressed as [rip + displ] which is very pleasing as it’s vastly more efficient than accessing statics in TLS which seems to be a nightmare in Linux at least. In MS Windows, isn’t TLS dealt with using FS: ( or GS: ?) prefixes? Shame this doesn’t seem to be exploited in Linux, or am I wrong? I’d like to deal with the overhead of retrieving the static base address all the time in the Linux situation (if I have got the right end of the stick) but having an ‘application object’ which contains all the statics in a struct in an alloc cell or something, and passing a pointer to this static base app object everywhere seems a nightmare too as it eats a register and worse eats one of the limited number of precious function argument registers which are in short supply in eg x86-64, where there are less than half a dozen argument registers allowed. I realise that one can deal with that limited number by rolling some passed arguments up into a passed struct, but that’s introducing a level of indirection and other overhead, that or just live with the fact that the extra args are going into the stack, which isn’t the worst thing in the world. I wonder what others do about statics in TLS?
Re: Large statics
On Sunday, 25 June 2023 at 21:08:13 UTC, Ali Çehreli wrote: On 6/25/23 13:41, Cecil Ward wrote: > The docs say that there is a limit on the size of large statics Customers (at least Weka) did request larger statics in the past. Since they use LDC, the limit was removed for LDC. I did not try it. :) Ali Ah, I did not know that, many thanks, I’m using LDC and GDC. A wishlist for the docs on the website would be to have them mention, and link to additional documentation regarding GDC and LDC, not just DMD. The docs should mainly be about the D language not solely about the DMD compiler.
Large statics
The docs say that there is a limit on the size of large statics of 16 MB. Is it desirable to remove this limit ? I realise that with new code there is the option to alloc the space instead where the static is uninitialised. There are other possibilities, such as an object filled with compile-time generated data maybe. The documentation also points out the crazy but understandable bloat on the exe size. Is it possible to place a large object in BSS by using ubyte arr[ enormous ] = void;
Re: Mixin and compile-time functions for code generation
On Saturday, 24 June 2023 at 17:43:52 UTC, Adam D Ruppe wrote: On Saturday, 24 June 2023 at 17:31:31 UTC, Cecil Ward wrote: Can I get mixin whatever to do this for me? Mixin with a function that runs at compile-time and creates the required source ? have you tried it? No, not so far. Adam, if you think that is a workable approach then I certainly will do so. It’s going to be very awkward generating literal strings in D code using literal strings in the meta-mixin-code or whatever I should call it.
Mixin and compile-time functions for code generation
I have a function that can be run at compile-time and which will be able to output code to be injected into the D source code stream. Can I get mixin whatever to do this for me? Mixin with a function that runs at compile-time and creates the required source ? Like D’s solution for a replacement for function-style C preprocessor macros ? - but far more advanced and capable ? I need to re-read Ali Çehreli’s excellent book for the third time.
Re: How does D’s ‘import’ work?
On Tuesday, 20 June 2023 at 17:56:27 UTC, Ali Çehreli wrote: On 6/20/23 08:09, Cecil Ward wrote: > I’m used to slow compilers on fast machines and compiling > gives me an excuse for more coffee and possibly fruity buns. Yes, all of us in past projects accepted C++'s slowness. We did get coffee, etc. One of my current colleagues regularly plays solitaire when waiting for C++ compilations. Not only it's not a professional sight, but C++ is proving to be a professional mistake. Nobody should suffer from such context switches. I have a hunch, without any backing research data, that C++'s contribution to humanity may be net negative. D is nothing like that: My turnaround is a few seconds: Write, compile, run, see the effect... I use only dmd partly because of laziness: it just works. Although I take full advantage D's low level powers, my programs have mostly been I/O bound with huge files, so dmd's less-than ideal optimization powers are hidden because most threads are waiting for file system I/O. Aside: std.parallelism and std.concurrency have been very helpful. Ali In the 1980s on our VAX 11/750, compile jobs were batch jobs placed in a queue. Half hour waits were not unknown. A build of the new o/s we were working on took around 40 mins on a 33 MHz 386 Dell PC (later a 486!) iirc. So time for patisserie even. But in oractice you simply got on with other jobs, like writing new code that was not yet integrated, code reviews, all sorts of things.
Compiling the runtime library
Is it possible to recompile the LDC and GDC runtimes yourself so you can do so with the switches you desire? (eg regarding optimisation, release vs debug build modes.) I think I saw a mention of something to help with this in the LDC docs, GDC would be a different story though. I’d have to get hold of the code first somehow, of course.
Unused routines and inlining
(Apologies if I have talked about this before, but my memory is shot because of strong pain drugs that I’m on, and it never was any good before either, so I may be repeating myself.) I’m using GDC and LDC, comparing the two, and in a medium sized routine that I have written pretty much every routine is inlined all the time. No-one takes the addresses of the routines, and they are not called externally to the module, marked private. (Is that the same as ‘static’ in C and D ?) So there’s no reason for the compiled copies of the function bodies to still exist. This makes the module unnecessarily huge with all this unused code just sitting there. Is there anything I can be doing about this, to make them go away, with appropriate configuration? It’s a wishlist item for the compilers, to check for zero-usage-count in functions that are always inlined, private and where there’s no pointer-taking so no chance of indirect calls. Is that sufficient?
Re: Unused routines and inlining
On Saturday, 24 June 2023 at 16:55:05 UTC, Cecil Ward wrote: (Apologies if I have talked about this before, but my memory is shot because of strong pain drugs that I’m on, and it never was any good before either, so I may be repeating myself.) [...] s/medium sized routine/medium-sized module/
Re: A couple of questions about arrays and slices
On Saturday, 24 June 2023 at 16:42:45 UTC, Cecil Ward wrote: On Saturday, 24 June 2023 at 15:12:14 UTC, Jonathan M Davis wrote: [...] Yeah, it would take me forever to get my head around that, and I only want a crude toy partial parser for certain portions of the grammar, and the parsing code is done now. A hand-written recursive descent type thing mainly dealing with things like comments and literal string that have to be taken account of as they prevent hazards to naive straight string searching for what you want to find, as comments and eg double-quoted strings could have things in them that are red-herrings or the things that you want to find items in, depending on circumstances. [...] I read an article about just that good strings trick many many years back, and the author called it ‘a string universe’, which I really liked.
Re: A couple of questions about arrays and slices
On Saturday, 24 June 2023 at 15:12:14 UTC, Jonathan M Davis wrote: On Saturday, June 24, 2023 8:43:00 AM MDT Cecil Ward via Digitalmars-d-learn wrote: I started out looking into a number of runtime library routines, but in the end it seemed quicker to roll my own code for a crude recursive descent parser/lexer that parses part of D’s grammar for expressions, and (again partial grammar) parser for string literal expressions and so on. I find certain special elements and execute actions which involve doing the AA lookup and replacing variable names with ordinal numbers in decimal in the output stream. Admission: The parsing is the thing that has to be fast, even though again the size of the D language text is not likely to be huge at all. But 40 years ago, I came from a world with 2k RAM and 0.9 MHz clock rates so I have developed a habit of always thinking about speed before I do anything, needful or not, to be honest. I once wrote a program that took 35 mins to evaluate 2+2 and print out the answer, so I’m now ashamed of writing slow code. Those were bad days, to be honest. 4 GHz+ and ILP is nicer. Well, dmd is open source (and Boost-licensed, so it doesn't really have any restrictions), so depending on what you're doing, it might make sense to just take code from that (and it's very fast). IIRC, it pulls some fun tricks like replacing identical strings with pointers to the same string so that it can just compare pointers. - Jonathan M Davis Yeah, it would take me forever to get my head around that, and I only want a crude toy partial parser for certain portions of the grammar, and the parsing code is done now. A hand-written recursive descent type thing mainly dealing with things like comments and literal string that have to be taken account of as they prevent hazards to naive straight string searching for what you want to find, as comments and eg double-quoted strings could have things in them that are red-herrings or the things that you want to find items in, depending on circumstances. I’m trying to get my head round the differences between OSX tools and those for Linux relating to LDC and GDC which seems slightly inferior in some situations. I’m a serious professional asm programmer of old, before compilers were of usable output quality for git-hard applications. (‘a git’ a disreputable person, colloquial English English. ‘git hard’ - brain-meltingly hard, like quantum gravity.)
Toolchain with ldc and AArch64 OSX
I have LDC running on an ARM Mac. If anyone else out there is an LDC or GDC user, could you knock up a quick shell program to compile and link a .d file to produce an executable ? found the linker but these tools are all new to me and a bit of help would save me a lot of trial and error and frustration as I try to find docs. GDC would be great too. I have managed to achieve this before on a Raspberry Pi AArch64 Linux Debian where the compiler can link and generate an executable just in integrated fashion in the one command. The OSX tools seem rather different however. I’m going to try installing GDC on the Mac next, have got that running on the Pi too successfully.
Re: A couple of questions about arrays and slices
On Saturday, 24 June 2023 at 12:05:26 UTC, Jonathan M Davis wrote: On Saturday, June 24, 2023 1:43:53 AM MDT Cecil Ward via Digitalmars-d-learn wrote: On Saturday, 24 June 2023 at 07:36:26 UTC, Cecil Ward wrote: > [...] I just realised something, your point about altering the table and having to rehash, is well taken. I hadn’t considered that. The reason for my foolishness in failing to realise that I’m asking the impractical is my pattern of usage. I add all the entries into the mapping table and have no interest in any lookups until it is fully built. Then a second function starts to do lookups while the data remains unchanging and that usage pattern can be guaranteed. I could even idup it if that would help, as copying < 32 uints wouldn’t take forever. A typical value would be a mere 5 or less. I only picked 32 to be completely safely ott. Well, if the key were a struct or a class, the hashing function would be opHash. For built-in types, the runtime has hashing functions that it uses. Either way, with AAs, you really don't worry about managing the memory, because it's completely outside of your control. You just put the elements in there using their associated keys, and if you want to try to speed it up after you've populated it, you use rehash so that the runtime can try to move the elements around within the container so that lookup speeds will be closer to optimal. As such, for the most part, when dealing with AAs and worrying about efficiency, the question really becomes whether AAs are the correct solution rather than much of anything having to do with how you manage their memory. With so few elements, it's also possible that using std.algorithm.searching.find would be faster - e.g. having a dynamic array of strings where the matching int is at the same index in a dynamic array of ints - or you could use std.typecons.Tuple!(string, int)[] with something like arr.find!(a => a[0] == key)() to find the tuple with the int you want. Simply comparing a small number of strings like that might be faster than what goes on with hashing the string and then finding the corresponding element within the AA - or it might not be. You'd have to test that to know. The AA would definitely be faster with a large number of elements, but with a small number of elements, the algorithmic complexity doesn't really matter, and the extra overhad with the AA lookups could actually mean that the search through the dynamic array is faster even though it's O(n). But you can only know which is faster by testing it out with the actual data that you're dealing with. Regardless, you need to remember that associative arrays are not arrays in the C sense. Rather, they're hash tables, so they function very differently from dynamic arrays, and the rehash function is the closest that you're going to get to affecting how the elements are laid out internally or how much memory the AA is using. - Jonathan M Davis I started out looking into a number of runtime library routines, but in the end it seemed quicker to roll my own code for a crude recursive descent parser/lexer that parses part of D’s grammar for expressions, and (again partial grammar) parser for string literal expressions and so on. I find certain special elements and execute actions which involve doing the AA lookup and replacing variable names with ordinal numbers in decimal in the output stream. Admission: The parsing is the thing that has to be fast, even though again the size of the D language text is not likely to be huge at all. But 40 years ago, I came from a world with 2k RAM and 0.9 MHz clock rates so I have developed a habit of always thinking about speed before I do anything, needful or not, to be honest. I once wrote a program that took 35 mins to evaluate 2+2 and print out the answer, so I’m now ashamed of writing slow code. Those were bad days, to be honest. 4 GHz+ and ILP is nicer.
Re: A couple of questions about arrays and slices
On Saturday, 24 June 2023 at 07:36:26 UTC, Cecil Ward wrote: Jonathan, is it possible that I wanted one thing and got another? My description in the earlier post was of the _aim_ of the program. What I ended up with might be something else? I wanted an array of uints whose values are the results/outputs of the mapping function. Since it is keyed by strings I assumed that the runtime generates some kind of hash for fast lookup when I ask it to retrieve an entry by the string (key) associated with it. I assumed that in some sense the hashing was sort of separate with some degree of independence from the underlying array, if that makes sense. The lookup is just assumed to be fast but how it is done we don’t really care. I just wanted to expand the array as I did successfully elsewhere with reserve, as I built this structure by successive additions of data. I have a number of strings and the map is meant to output the ordinal number in which I first saw them, zero-based. Then I want to come back and randomly look up one ordinal given a string preferably with a very fast lookup. The number of entries can not practically be more than 30, and even that would be highly unusual, maybe ten is the practical limit in my particular case, so it’s hardly MySQL. I just realised something, your point about altering the table and having to rehash, is well taken. I hadn’t considered that. The reason for my foolishness in failing to realise that I’m asking the impractical is my pattern of usage. I add all the entries into the mapping table and have no interest in any lookups until it is fully built. Then a second function starts to do lookups while the data remains unchanging and that usage pattern can be guaranteed. I could even idup it if that would help, as copying < 32 uints wouldn’t take forever. A typical value would be a mere 5 or less. I only picked 32 to be completely safely ott.
Re: A couple of questions about arrays and slices
On Saturday, 24 June 2023 at 01:28:03 UTC, Jonathan M Davis wrote: On Friday, June 23, 2023 7:02:12 PM MDT Cecil Ward via Digitalmars-d-learn wrote: I just had a fight with LDC over the following code when I tried out reserve. I have an associative array that maps strings to ‘ordinals’ ie uints that are unique, and the compiler hates the call to reserve. == struct decls_t { uintn_entries = 0; uint[ dstring ] ordinals; // Associative array maps variable names to ordinals } static decls_t Decls; enum NPreAllocEntries = 32; Decls.ordinals.reserve( NPreAllocEntries ); source>(82): Error: none of the overloads of template `object.reserve` are callable using argument types `!()(uint[dstring], ulong)` /opt/compiler-explorer/ldc1.32.1/ldc2-1.32.1-linux-x86_64/bin/../import/obje ct.d(3983):Candidate is: `reserve(T)(ref T[] arr, size_t newcapacity)` Compiler returned: 1 Associative arrays and dynamic arrays are completely different things. Associative arrays are hash tables, and reserve really doesn't make sense for them. reserve is for telling the GC to make sure that a dynamic array has at least a specific amount of room to grow into before the GC needs to do a reallocation so that the dynamic array refers to a different memory block with enough memory to hold the data, whereas if and when associative arrays have to reallocate any of their internals is largely implementation-defined. Any time that you add or remove elements from an AA, it might reallocate some of its internals depending on its current state and what the key of the element is - and that could be different between different compiler releases (though it's unlikely to change very often, since I don't think that the AA implementation gets messed with much). You can use the rehash function on AAs to tell the GC to try to reorder how it's structured all of its buckets so that lookups are more efficient with the data that's currently in there, and you can call clear to remove all its elements, but in general, you don't do much to manage an AA's memory. It's a much more complicated data structure than an array. https://dlang.org/spec/hash-map.html - Jonathan M Davis Jonathan, is it possible that I wanted one thing and got another? My description in the earlier post was of the _aim_ of the program. What I ended up with might be something else? I wanted an array of uints whose values are the results/outputs of the mapping function. Since it is keyed by strings I assumed that the runtime generates some kind of hash for fast lookup when I ask it to retrieve an entry by the string (key) associated with it. I assumed that in some sense the hashing was sort of separate with some degree of independence from the underlying array, if that makes sense. The lookup is just assumed to be fast but how it is done we don’t really care. I just wanted to expand the array as I did successfully elsewhere with reserve, as I built this structure by successive additions of data. I have a number of strings and the map is meant to output the ordinal number in which I first saw them, zero-based. Then I want to come back and randomly look up one ordinal given a string preferably with a very fast lookup. The number of entries can not practically be more than 30, and even that would be highly unusual, maybe ten is the practical limit in my particular case, so it’s hardly MySQL.
Re: A couple of questions about arrays and slices
On Thursday, 22 June 2023 at 05:21:52 UTC, Cecil Ward wrote: On Thursday, 22 June 2023 at 01:44:22 UTC, Jonathan M Davis wrote: On Wednesday, June 21, 2023 7:05:28 PM MDT Paul Backus via Digitalmars-d-learn wrote: [...] To add to that, it _has_ to know the element type, because aside from anything related to a type's size, it bit-blits the type's init value onto the new elements when it increases the length of the dynamic array. You'd probably be dealing with bytes if you were explicitly asking for memory and the like (e.g. with malloc), but a dynamic array is properly typed, and everything you do with it in @safe code is going to deal with it as properly typed. For it to be otherwise would require @system casts. - Jonathan M Davis Thankyou Jonathan! I just had a fight with LDC over the following code when I tried out reserve. I have an associative array that maps strings to ‘ordinals’ ie uints that are unique, and the compiler hates the call to reserve. == struct decls_t { uintn_entries = 0; uint[ dstring ] ordinals; // Associative array maps variable names to ordinals } static decls_t Decls; enum NPreAllocEntries = 32; Decls.ordinals.reserve( NPreAllocEntries ); source>(82): Error: none of the overloads of template `object.reserve` are callable using argument types `!()(uint[dstring], ulong)` /opt/compiler-explorer/ldc1.32.1/ldc2-1.32.1-linux-x86_64/bin/../import/object.d(3983): Candidate is: `reserve(T)(ref T[] arr, size_t newcapacity)` Compiler returned: 1
Re: A couple of questions about arrays and slices
On Thursday, 22 June 2023 at 01:44:22 UTC, Jonathan M Davis wrote: On Wednesday, June 21, 2023 7:05:28 PM MDT Paul Backus via Digitalmars-d-learn wrote: [...] To add to that, it _has_ to know the element type, because aside from anything related to a type's size, it bit-blits the type's init value onto the new elements when it increases the length of the dynamic array. You'd probably be dealing with bytes if you were explicitly asking for memory and the like (e.g. with malloc), but a dynamic array is properly typed, and everything you do with it in @safe code is going to deal with it as properly typed. For it to be otherwise would require @system casts. - Jonathan M Davis Thankyou Jonathan!
Re: A couple of questions about arrays and slices
On Thursday, 22 June 2023 at 01:05:28 UTC, Paul Backus wrote: On Thursday, 22 June 2023 at 00:10:19 UTC, Cecil Ward wrote: Is .reserve()’s argument scaled by the entry size after it is supplied, that is it is quoted in elements or is it in bytes? I’m not sure whether the runtime has a knowledge of the element type so maybe it doesn’t know anything about scale factors, not sure. length, reserve, and capacity all use the same unit, which is elements. reserve passes a TypeInfo instance to the runtime so that it knows the size of the elements. You can see the implementation here: https://github.com/dlang/dmd/blob/v2.104.0/druntime/src/object.d#L3910 Many thanks Paul, I should have found that!
Re: A couple of questions about arrays and slices
On Wednesday, 21 June 2023 at 15:48:56 UTC, H. S. Teoh wrote: On Wed, Jun 21, 2023 at 02:09:26AM +, Cecil Ward via Digitalmars-d-learn wrote: First is an easy one: 1.) I have a large array and a sub-slice which I want to set up to be pointing into a sub-range of it. What do I write if I know the start and end indices ? Concerned about an off-by-one error, I have start_index and past_end_index (exclusive). array[start_idx .. one_past_end_idx] 2.) I have a dynamic array and I wish to preinitialise its alloc cell to be a certain large size so that I don’t need to reallocate often initially. I tell myself that I can set the .length property. Is that true? You can use `array.reserve(preinitSize);`. 2a.) And what happens when the cell is extended, is the remainder zero-filled or remaining full of garbage, or is the size of the alloc cell something separate from the dynamic array’s knowledge of the number of valid elements in it ? The size of the allocated cell is managed by druntime. On the user code side, all you know is the slice (start pointer + length). The allocated region outside the current array length is not initialized. Assigning to array.length initializes the area that the array occupies after the length has been extended. T Is .reserve()’s argument scaled by the entry size after it is supplied, that is it is quoted in elements or is it in bytes? I’m not sure whether the runtime has a knowledge of the element type so maybe it doesn’t know anything about scale factors, not sure.
Re: A couple of questions about arrays and slices
On Wednesday, 21 June 2023 at 04:52:06 UTC, Jonathan M Davis wrote: On Tuesday, June 20, 2023 8:09:26 PM MDT Cecil Ward via Digitalmars-d-learn wrote: [...] When slicing, the end index is exclusive. e.g. [...] Actually concerning the garbage, I was rather hoping that it _would_ be garbage so as to avoid the cost of a zero-fill in time and also possibly in cache pollution, unless it uses the non-temporal cache-friendliness management tech that is found on eg x86.
Re: A couple of questions about arrays and slices
On Wednesday, 21 June 2023 at 04:52:06 UTC, Jonathan M Davis wrote: On Tuesday, June 20, 2023 8:09:26 PM MDT Cecil Ward via Digitalmars-d-learn wrote: [...] When slicing, the end index is exclusive. e.g. [...] Thankyou to both posters for your exceptionally helpful and generous replies, which will serve as a help to others if I made the title searchable. I need to look at the appended and try to find some (more) example code.
A couple of questions about arrays and slices
First is an easy one: 1.) I have a large array and a sub-slice which I want to set up to be pointing into a sub-range of it. What do I write if I know the start and end indices ? Concerned about an off-by-one error, I have start_index and past_end_index (exclusive). 2.) I have a dynamic array and I wish to preinitialise its alloc cell to be a certain large size so that I don’t need to reallocate often initially. I tell myself that I can set the .length property. Is that true? 2a.) And what happens when the cell is extended, is the remainder zero-filled or remaining full of garbage, or is the size of the alloc cell something separate from the dynamic array’s knowledge of the number of valid elements in it ?
Re: How does D’s ‘import’ work?
On Monday, 19 June 2023 at 16:24:03 UTC, rempas wrote: On Monday, 19 June 2023 at 12:48:26 UTC, Cecil Ward wrote: If I have sources to all the library routines, not libraries or .obj files. I am simply completely ignorant about the D tools including DUB, so off to do some reading. I’ve just been seeing how good LDC and GDC are, and the answer is extremely, especially LDC, which perhaps has a slight edge in code generation quality. I haven’t looked at AAarch64 code yet, only AMD64. Very impressed with all the work! Of course, DMD uses it's own custom backend so it's only fair to not expect for it to have the same runtime performance and optimizations as the other two compilers than use LLVM and GCC. If you only use x86_64, DMD will be amazing for your debug cycles! I’ve never used DMD. I don’t support that it will run on Aarch64. I’m running ldc on an ARM M2 Mac OSX. Also on x86-64 VMs at Godbolt.org but I must get access to an x86-64 box myself.
Re: How does D’s ‘import’ work?
On Sunday, 18 June 2023 at 21:51:14 UTC, Jonathan M Davis wrote: On Sunday, June 18, 2023 2:24:10 PM MDT Cecil Ward via Digitalmars-d-learn wrote: I wasn’t intending to use DMD, rather ldc if possible or GDC because of their excellent optimisation, in which DMD seems lacking, is that fair? (Have only briefly looked at dmd+x86 and haven’t given DMD’s back end a fair trial.) In general, dmd is fantastic for its fast compilation speed. So, it works really well for developing whatever software you're working on (whereas ldc and gdc are typically going to be slower at compiling). And depending on what you're doing, the code is plenty fast. However, if you want to maximize the efficiency of your code, then you definitely want to be building the binaries that you actually use or release with ldc or gdc. - Jonathan M Davis Good point. I’m used to slow compilers on fast machines and compiling gives me an excuse for more coffee and possibly fruity buns. I’m incredibly impressed with LDC, GDC slightly less so, as it sometimes calls runtime library routines where Ldc doesn’t. Like in things to do with arrays, for one example. I hate calls to runtime library routines unless they are really substantial, mind you many calls to a modest-sized routine can get you a hotter cache, and even micro-op cache, and keep the whole code size down so as to improve cache overload or even pollution.
Re: How does D’s ‘import’ work?
On Monday, 19 June 2023 at 08:46:31 UTC, rempas wrote: On Sunday, 18 June 2023 at 20:17:50 UTC, Cecil Ward wrote: target.obj: target.c include1.h include2.h cc.exe cc target.c and you either have to pray that you have kept the list of .h files that are mentioned inside target.c and other .h files referenced recursively from within these .h files etc. I listed the compiler as a dependency too, and I should really have a pseudo-target somehow that depends on the nature of the command line because changing the command line affects the generated code. If you have an automaking compiler that will generate the list of .h files then that’s so, so much safer. First of all, If we are talking about C files, D can import and compile them so you don't even need a Makefile! Now, if you need to compile C++ files and then either link or create a library (and link with it from the D project), then you can just run Dub in the end of the job in your make file! You can then have a variable called `DUB_FLAGS` in your Makefile and this is where the arguments that will be passed for the Dub will be. Will this be good enough for you? If I have sources to all the library routines, not libraries or .obj files. I am simply completely ignorant about the D tools including DUB, so off to do some reading. I’ve just been seeing how good LDC and GDC are, and the answer is extremely, especially LDC, which perhaps has a slight edge in code generation quality. I haven’t looked at AAarch64 code yet, only AMD64. Very impressed with all the work!
Re: How does D’s ‘import’ work?
On Thursday, 8 June 2023 at 05:11:04 UTC, Ali Çehreli wrote: On 6/7/23 21:17, Cecil Ward wrote: > I was thinking about the situation in C where I have a rule in a make > file that lists the .h files as well as the .c all as dependencies in > creating an object file. dmd's -makedeps command line switch should be helpful there. (I did not use it.) Ali I wasn’t intending to use DMD, rather ldc if possible or GDC because of their excellent optimisation, in which DMD seems lacking, is that fair? (Have only briefly looked at dmd+x86 and haven’t given DMD’s back end a fair trial.)
Re: How does D’s ‘import’ work?
On Sunday, 18 June 2023 at 17:34:51 UTC, rempas wrote: On Thursday, 8 June 2023 at 04:17:20 UTC, Cecil Ward wrote: I was thinking about the situation in C where I have a rule in a make file that lists the .h files as well as the .c all as dependencies in creating an object file. I don't think I'm aware of what you mean with "lists .h and .c files". Could you provide a small makefile that does that so I can run and examine? target.obj: target.c include1.h include2.h cc.exe cc target.c and you either have to pray that you have kept the list of .h files that are mentioned inside target.c and other .h files referenced recursively from within these .h files etc. I listed the compiler as a dependency too, and I should really have a pseudo-target somehow that depends on the nature of the command line because changing the command line affects the generated code. If you have an automaking compiler that will generate the list of .h files then that’s so, so much safer.
Re: SIMD c = a op b
On Sunday, 18 June 2023 at 04:54:08 UTC, Cecil Ward wrote: Is it true that this doesn’t work (in either branch)? float4 a,b; static if (__traits(compiles, a/b)) c = a / b; else c[] = a[] / b[]; I tried it with 4 x 64-bit ulongs in a 256-bit vector instead. Hoping I have done things correctly, I got an error message about requiring a destination variable as in c = a op b where I tried simply "return a / b;" In the else branch, I got a type conversion error. Is that because a[] is an array of 256-bit vectors, in the else case, not an array of ulongs? Correction I should have written ‘always work’ - I just copied the example straight from the language documentation for simd and adapted it to use ulongs and a wider vector. I was using GDC.
Re: Como puedo hacer funciones asincronas?
On Saturday, 17 June 2023 at 22:05:37 UTC, Danico wrote: hola gente, quisiera saber como es que puedo hacer funciones asincronas. ` #!/usr/bin/env dmd import std; import std.stdio; import std.concurrency; //import archivo2; alias print = writeln; void main () { auto tarea1 = spawn(); auto tarea2 = spawn(); print("realizando tareas "); } void saludo () { print("hola"); } async saludo2 () { print("hola2"); } ` This is something I have wanted to achieve also.
Parser
I’m thinking that I might had to end up writing a partial, rather rough parser for parts of the D language. Could I get some suggestions for help that I might find in the way of software components? D has a very powerful regex module, I believe. I have been writing inline asm library routines for GDC as a learning exercise and unfortunately I can’t build them under LDC because LDC does not yet offer full support for the GCC in-line asm grammar, specifically named in-asm arguments such as " mov %[dest], %[src]" - where you see the names enclosed in [ ]. I’m thinking that I might have to fix this deficiency myself. There’s no way that I can enhance LDC myself as I wouldn’t even know where to start. I could pre-process the string expressions used in inline asm so that LDC could understand an alternative easier grammar, one where there are numbers instead of "[names]", eg "%0" instead of the meaningful "%[dest]". It seems that the compilers take string _expressions_ everywhere rather than just simple literal strings. Can I generate fragments of D and inject them into the rest of the code using mixin? Not really sure how to use it. There are three string expressions involved: the string containing the asm, which needs to be scanned for %[ names ], and these need to be replaced with numbers in order of occurrence of declarations of the names, then an outputs section and an inputs section which can both contain declarations of these names, eg ‘: [ dest ] "=r" ( d-expression ) ,’ … ‘: [ src ]’…. The arbitrary fragment of D in d-expression can unfortunately be anything, and there’s no way I can write a full D lexer/parser to scan that properly, but luckily I just have to pass over it to find its terminator which is either a ‘,’ or a ‘:’. (There might be a case where there is a ‘;’ as a terminator instead of a ‘:’, I’m not sure if that’s permitted in the grammar immediately after the inputs section. But having to parse all the types of strings and operators in a string-expression is hard enough. I will also have to deal with all the possible comment types wherever they can occur, which is all over the place within, before and after these expressions. Any tips, modules that I could use would be most welcome. I’m very much out of my depth here.
Re: byte and short data types use cases
On Sunday, 11 June 2023 at 00:05:52 UTC, H. S. Teoh wrote: On Sat, Jun 10, 2023 at 09:58:12PM +, Cecil Ward via Digitalmars-d-learn wrote: On Friday, 9 June 2023 at 15:07:54 UTC, [...] On contemporary machines, the CPU is so fast that memory access is a much bigger bottleneck than processing speed. So unless an operation is being run hundreds of thousands of times, you're not likely to notice the difference. OTOH, accessing memory is slow (that's why the memory cache hierarchy exists). So utf8 is actually advantageous here: it fits in a smaller space, so it's faster to fetch from memory; more of it can fit in the CPU cache, so less DRAM roundtrips are needed. Which is faster. Yes you need extra processing because of the variable-width encoding, but it happens mostly inside the CPU, which is fast enough that it generally outstrips the memory roundtrip overhead. So unless you're doing something *really* complex with the utf8 data, it's an overall win in terms of performance. The CPU gets to do what it's good at -- running complex code -- and the memory cache gets to do what it's good at: minimizing the amount of slow DRAM roundtrips. I completely agree with H. S. Teoh. That is exactly what I was going to say. The point is that considerations like this have to be thought through carefully and width of types really does matter in the cases brought up. But outside these cases, as I said earlier, stick to uint, size_t and ulong, or uint32_t and uint64_t if exact size is vital, but do also check out the other std.stdint types too as very occasionally they are needed.
Re: byte and short data types use cases
On Saturday, 10 June 2023 at 21:58:12 UTC, Cecil Ward wrote: On Friday, 9 June 2023 at 15:07:54 UTC, Murloc wrote: On Friday, 9 June 2023 at 12:56:20 UTC, Cecil Ward wrote: [...] Is this some kind of property? Where can I read more about this? My last example is comms. Protocol headers need economical narrow data types because of efficiency, it’s all about packing as much user data as possible into each packet and fatter, longer headers reduce the amount of user data as the total has a hard limit on it. A pair of headers totalling 40 bytes in IPv4+TCP takes up nearly 3% of the total length allowed, so that’s a ~3% speed loss, as the headers are just dead weight. So here narrow types help comms speed.
Re: byte and short data types use cases
On Friday, 9 June 2023 at 15:07:54 UTC, Murloc wrote: On Friday, 9 June 2023 at 12:56:20 UTC, Cecil Ward wrote: On Friday, 9 June 2023 at 11:24:38 UTC, Murloc wrote: If you have four ubyte variables in a struct and then an array of them, then you are getting optimal memory usage. Is this some kind of property? Where can I read more about this? So you can optimize memory usage by using arrays of things smaller than `int` if these are enough for your purposes, but what about using these instead of single variables, for example as an iterator in a loop, if range of such a data type is enough for me? Is there any advantages on doing that? A couple of other important use-cases came to me. The first one is unicode which has three main representations, utf-8 which is a stream of bytes each character can be several bytes, utf-16 where a character can be one or rarely two 16-bit words, and utf32 - a stream of 32-bit words, one per character. The simplicity of the latter is a huge deal in speed efficiency, but utf32 takes up almost four times as memory as utf-8 for western european languages like english or french. The four-to-one ratio means that the processor has to pull in four times the amount of memory so that’s a slowdown, but on the other hand it is processing the same amount of characters whichever way you look at it, and in utf8 the cpu is having to parse more bytes than characters unless the text is entirely ASCII-like. The second use-case is about SIMD. Intel and AMD x86 machines have vector arithmetic units that are either 16, 32 or 64 bytes wide depending on how recent the model is. Taking for example a post-2013 Intel Haswell CPU, which has 32-byte wide units, if you choose smaller width data types you can fit more in the vector unit - that’s how it works, and fitting in more integers or floating point numbers of half width means that you can process twice as many in one instruction. On our Haswell that means four doubles or four quad words, or eight 32-bit floats or 32-bit uint32_ts, and similar doubling s’s for uint16_t. So here width economy directly relates to double speed.
Re: byte and short data types use cases
On Friday, 9 June 2023 at 15:07:54 UTC, Murloc wrote: On Friday, 9 June 2023 at 12:56:20 UTC, Cecil Ward wrote: On Friday, 9 June 2023 at 11:24:38 UTC, Murloc wrote: If you have four ubyte variables in a struct and then an array of them, then you are getting optimal memory usage. Is this some kind of property? Where can I read more about this? So you can optimize memory usage by using arrays of things smaller than `int` if these are enough for your purposes, but what about using these instead of single variables, for example as an iterator in a loop, if range of such a data type is enough for me? Is there any advantages on doing that? Read up on ‘structs’ and the ‘align’ attribute in the main d docs, on this website. Using smaller fields in a struct that is in memory saves RAM if there is an array of such structs. Even in the case where there is only one struct, let’s say that you are returning a struct by value from some function. If the struct is fairly small in total, and the compiler is good (ldc or gdc, not dmd - see godbolt.org) then the returned struct can fit into a register sometimes, rather than being placed in RAM, when it is returned to the function’s caller. Yesterday I returned a struct containing four uint32_t fields from a function and it came back to the caller in two 64-bit registers, not in RAM. Clearly using smaller fields if possible might make it possible for the whole struct to be under the size limit for being returned in registers. As for your question about single variables. The answer is very definitely no. Rather, the opposite: always use primary CPU-‘natural’ types, widths that are most natural to the processor in question. 64-bit cpus will sometimes favour 32-bit types an example being x86-64/AMD64, where code handling 32-bit ints generates less code (saves bytes in the code segment) but the speed and number of instructions is the same on such a 64-bit processor where you’re dealing with 32- or 64- bit types. Always use size_t for index variables into arrays or the size of anything in bytes, never int or uint. On a 64-bit machine such as x86-64, size_t is 64-bit, not 32. By using int/uint when you should have used size_t you could in theory get a very rare bug when dealing with eg file sizes or vast amounts of (virtual) memory, say bigger than 2GB (int limit) or 4GB (uint limit) when the 32-bit types overflow. There is also a ptrdiff_t which is 64-bit on a 64-bit cpu, probably not worth bothering with as its raison d’être was historical (early 80s 80286 segmented architecture, before the 32-bit 386 blew it away).
Re: byte and short data types use cases
On Friday, 9 June 2023 at 11:24:38 UTC, Murloc wrote: Hi, I was interested why, for example, `byte` and `short` literals do not have their own unique suffixes (like `L` for `long` or `u` for `unsigned int` literals) and found the following explanation: - "I guess short literal is not supported solely due to the fact that anything less than `int` will be "promoted" to `int` during evaluation. `int` has the most natural size. This is called integer promotion in C++." Which raised another question: since objects of types smaller than `int` are promoted to `int` to use integer arithmetic on them anyway, is there any point in using anything of integer type less than `int` other than to limit the range of values that can be assigned to a variable at compile time? Are these data types there because of some historical reasons (maybe `byte` and/or `short` were "natural" for some architectures before)? People say that there is no advantage for using `byte`/`short` type for integer objects over an int for a single variable, however, as they say, this is not true for arrays, where you can save some memory space by using `byte`/`short` instead of `int`. But isn't any further manipulations with these array objects will produce results of type `int` anyway? Don't you have to cast these objects over and over again after manipulating them to write them back into that array or for some other manipulations with these smaller types objects? Or is this only useful if you're storing some array of constants for reading purposes? Some people say that these promoting and casting operations in summary may have an even slower overall effect than simply using int, so I'm kind of confused about the use cases of these data types... (I think that my misunderstanding comes from not knowing how things happen at a slightly lower level of abstractions, like which operations require memory allocation, which do not, etc. Maybe some resource recommendations on that?) Thanks! For me there are two use cases for using byte and short, ubyte and ushort. The first is simply to save memory in a large array or neatly fit into a ‘hole’ in a struct, say next to a bool which is also a byte. If you have four ubyte variables in a struct and then an array of them, then you are getting optimal memory usage. In the x86 for example the casting operations for ubyte to uint use instructions that have zero added cost compared to a normal uint fetch. And casting to a ubyte generates no code at all. So the costs of casting in total are zero. The second use-case is where you need to interface to external specifications that deman uint8_t (ubyte), or uint16_t (ushort) where I am using the standard definitions from std.stdint. These types are the in C. If you are interfacing to externally defined struct in data structures in ram or in messages, that’s one example. The second example is where you need to interface to machine code that has registers or operands of 8-bit or 16-bit types. I like to use the stdint types for the purposes of documentation as it rams home the point that these are truly fixed width types and can not change. (And I do know that in D, unlike C, int, long etc are of defined fixed widths. Since C doesn’t have those guarantees that’s why the C stdint.h is needed in C too.) As well as machine code, we could add other high-level languages where interfaces are defined in the other language and you have to hope that the other language’s type widths don’t change.
Re: How does D’s ‘import’ work?
On Friday, 2 June 2023 at 12:07:09 UTC, rempas wrote: On Thursday, 1 June 2023 at 03:47:00 UTC, Cecil Ward wrote: I have another question if I may, what do we do about getting makefiles right given that we have imports ? What do you mean with that? Give some more info please! I was thinking about the situation in C where I have a rule in a make file that lists the .h files as well as the .c all as dependencies in creating an object file.
Re: Indenting standards religions K, whitesmiths etc
On Thursday, 1 June 2023 at 09:37:43 UTC, Dukc wrote: On Wednesday, 31 May 2023 at 16:24:38 UTC, Cecil Ward wrote: I wanted to ask how some of the leaders of our group feel about D indentation standards. `i realise that this causes some religious fervour in C. I could be in trouble here because in all my years at work, we never used K & R ‘one true brace style’ indenting, with the house style I’m used to being more like whitesmiths. Wikipedia explains this better. Something like the following below. So my question: would I get lynched for the following? (below) Check out this module from me: https://github.com/dukc/nuklearbrowser/blob/master/source/nuklearbrowser.d Plus similar style in most of my posts and bug reports. I'm still alive :D. Your code is your code. There, you may do as you wish. You have to aknowledge that an esoteric style may make it more difficult to read for some, but we're not lynching people for other factors of code readability either. Brace style is no different. Plus, what brace style is considered readable by the majority is a culture issue. There has to be some way to challege the established culture. If you don't exercise your power to code as you wish, someone will make your choice for you. Coding culture, or even culture in general, cannot develop if people never challege the present status quo. When you're coding with others, though, then you should obey the style guideline of that project if there is one. Even there you're as entitled as anyone for an opinion what the style policy should be (and to whether there should be style policy at all), but you then should (usually) obey the decision regardless whether it's the one you were advocating for. I wonder how much work it would be to write a D pretty printer / beautifier. Doing things such as lining up parameters or comments and breaking and re-wrapping comments etc if necessary because of the changes in whitespace. I’ve no idea what the ‘official story’ is with nested functions. I have some experience with that because I used to write Pascal (on a Z80 box and on a VAX), and that feature is like the return of an old friend, I love it so much and for me it’s quite a serious advantage over C. I’m always guilty of overcommenting, for various reasons although I’m not guilt of the likes of /* add 1 to x */! ;-) It’s partly because I have a shocking memory and maintenance becomes literally impossible for me, for me just as important I want the comments to spell out original intent, not the implementation choices, so if you see later that the two don’t match then you’ve spotted the bug. Many people comment in a very minimal way which makes the code look neat. I did sort of find an /* add 1 to x */ though as it was explaining and giving a caveat about GCC in-line asm constraints, and the comment saved me having to go and look things up in the bible.
Re: Indenting standards religions K, whitesmiths etc
On Thursday, 1 June 2023 at 09:37:43 UTC, Dukc wrote: On Wednesday, 31 May 2023 at 16:24:38 UTC, Cecil Ward wrote: I wanted to ask how some of the leaders of our group feel about D indentation standards. `i realise that this causes some religious fervour in C. I could be in trouble here because in all my years at work, we never used K & R ‘one true brace style’ indenting, with the house style I’m used to being more like whitesmiths. Wikipedia explains this better. Something like the following below. So my question: would I get lynched for the following? (below) Check out this module from me: https://github.com/dukc/nuklearbrowser/blob/master/source/nuklearbrowser.d Plus similar style in most of my posts and bug reports. I'm still alive :D. Your code is your code. There, you may do as you wish. You have to aknowledge that an esoteric style may make it more difficult to read for some, but we're not lynching people for other factors of code readability either. Brace style is no different. Plus, what brace style is considered readable by the majority is a culture issue. There has to be some way to challege the established culture. If you don't exercise your power to code as you wish, someone will make your choice for you. Coding culture, or even culture in general, cannot develop if people never challege the present status quo. When you're coding with others, though, then you should obey the style guideline of that project if there is one. Even there you're as entitled as anyone for an opinion what the style policy should be (and to whether there should be style policy at all), but you then should (usually) obey the decision regardless whether it's the one you were advocating for. Agree completely. You are not a criminal though because your closing braces are not indented out with the block they’re closing as I do. I find K hard to read even though we see it everywhere, or variants of it. I do wonder if my style in that earlier post hurts normal people’s eyeballs a lot. ;-) I’m told that Irish speakers can’t understand Scottish Gaelic on the radio a native speaker said to me that ‘it’s just a noise’. But as a ScG learner myself I can understand some spoken Irish even though I’ve never really studied the modern language (only the stuff of more that 1100 yrs ago.) So the pain isn’t symmetrical.
Re: How does D’s ‘import’ work?
On Wednesday, 31 May 2023 at 18:43:52 UTC, Cecil Ward wrote: Is there an explanation of how D’s ‘import’ works somewhere? I’m trying to understand the comparison with the inclusion of .h files, similarities if any and differences with the process. I have another question if I may, what do we do about getting makefiles right given that we have imports ?
Re: How does D’s ‘import’ work?
On Wednesday, 31 May 2023 at 18:56:02 UTC, H. S. Teoh wrote: On Wed, May 31, 2023 at 06:43:52PM +, Cecil Ward via Digitalmars-d-learn wrote: Is there an explanation of how D’s ‘import’ works somewhere? I’m trying to understand the comparison with the inclusion of .h files, similarities if any and differences with the process. Unlike C's #include, `import` does NOT paste the contents of the imported file into the context of `import`, like #include would do. Instead, it causes the compiler to load and parse the imported file, placing the parsed symbols into a separate symbol table dedicated for that module (in D, a file == a module). These symbols are then pulled into the local symbol table so that they become available to code containing the import declaration. (There's a variation, `static import`, that does the same thing except the last step of pulling symbols into the local symbol table. So the symbols will not "pollute" the current namespace, but are still accessible via their fully-qualified name (FQN), i.e., by the form `pkg.mod.mysymbol`, for a symbol `mysymbol` defined in the module `pkg.mod`, which in turn is a module under the package `pkg`.) For more information: https://tour.dlang.org/tour/en/basics/imports-and-modules https://dlang.org/spec/module.html T Thank you so very much for the links and for your generous help. Some C compilers used to have a thing called ‘precompiled headers’, potential source of trouble and ai always felt uneasy about it rightly or wrongly. It’s great that D has got rid of header file includes though, they were ridiculously painful. I used to use the automake feature that was built into the JPI C compiler at work which took care of all the .h dependencies so you no longer had to worry about it. And you only loaded the compiler from disk and started it up once as it stayed in memory handling all the C parts of a make.
Re: Indenting standards religions K, whitesmiths etc
On Wednesday, 31 May 2023 at 22:06:50 UTC, Ernesto Castellotti wrote: On Wednesday, 31 May 2023 at 16:24:38 UTC, Cecil Ward wrote: I wanted to ask how some of the leaders of our group feel about D indentation standards. `i realise that this causes some religious fervour in C. I could be in trouble here because in all my years at work, we never used K & R ‘one true brace style’ indenting, with the house style I’m used to being more like whitesmiths. Wikipedia explains this better. Something like the following below. [...] Excuse me but for me the only style I like is the K I can accept Allman but the rest is heretical to me ;-) don't worry, just a joke Is there even such as thing as a pretty-printer / beautifier for D ? Has anyone adapted one ? `it might save me from a lynch mob. :-) :-)
How does D’s ‘import’ work?
Is there an explanation of how D’s ‘import’ works somewhere? I’m trying to understand the comparison with the inclusion of .h files, similarities if any and differences with the process.
Indenting standards religions K, whitesmiths etc
I wanted to ask how some of the leaders of our group feel about D indentation standards. `i realise that this causes some religious fervour in C. I could be in trouble here because in all my years at work, we never used K & R ‘one true brace style’ indenting, with the house style I’m used to being more like whitesmiths. Wikipedia explains this better. Something like the following below. So my question: would I get lynched for the following? (below) And can anyone recommend a beautifier / pretty printer tool for D that is customisable to your house style if that is a thing that’s needed? I assume I would need that if I were to donate code, unless some helpful recipient would run such a tool on .d files received. — pure nothrow etc T foo( T, T2 )( in T param x, in T2 param y ) if ( template-qualification-whatever ) in { static assert( … ); } out ( ret ) { … assert( test ret ); } do { blah if ( test ) { … if-body … } back to main block … … } /* end of function, notice the indent level stays out with the content */
Re: Code duplication where you wish to have a routine called with either immutable or mutable arguments
On Wednesday, 31 May 2023 at 09:14:49 UTC, Dom DiSc wrote: On Wednesday, 31 May 2023 at 03:29:33 UTC, Cecil Ward wrote: I have to admit that I don’t really understand immutable. I have an idea that it could mean that an object has an address in ROM, so its value will never change. Maybe const doesn’t give you such a strong guarantee, disallows ‘you’ from modifying it but others might do so, but who knows. There are two perspectives: that of the value handed to a function and that of the function taking the value. "immutable" (or "mutable") is a property of the value, "const" is a property of the function. If the function can work with mutable values, but in fact doesn't mutate them itself, it could also work with immutable values. The fact that others could modify your "const" value doesn't matter for immutable values, because they of course can't be modified by others. For the function it doesn't matter, because it only guarantees not to modify it itself, don't care about what other can or can't do. Without a guarantee as strong as the first idea I can’t really understand how const can work properly. "You treat it as const so do not modify it, but it might not be eternally fixed and unchanging" that doesn’t seem to have enough value to me. Why? What guarantee are you missing? Your function can work with mutable data, so you don't care if it can be modified also by others. Now it happens that you doesn't modify the data. So why shouldn't you be able to work on data that guarantees that it also will not be changed by others? You don't care for such modification anyway. The meaning of "immutable" is: I cannot be modified. Not by you and not by anybody else. It's a property of a value. The meaning of "mutable" is: I can be modified by anybody. Work with me only if that is ok for you. It's a property of a value. The meaning of "const" is: I don't care if others modify the data or not, I won't modify it myself. It's a property of a function. Dom, you explain it well. I’m just too stupid. Literally, as I’m on strong pain drugs all the time, so things are a bit fuzzy. As a professional C programmer for some years, I understood the word const and used it all the time, as much as possible at every opportunity, so I had some expectations. But the errors I’m getting don’t fit in with the previous understanding I had with the familiar ‘const’ keyword and make me think there must be something else going on. So I will need to capture an example in the wild, cage it and bring it in for scientific examination. I can’t ask for an explanation of things going on that you can’t inspect for yourself, obviously. And I don’t understand what the problem is with using in as much as possible yet having to remove it sometimes when something immutable is in use.
Re: Code duplication where you wish to have a routine called with either immutable or mutable arguments
On Wednesday, 31 May 2023 at 03:23:01 UTC, Cecil Ward wrote: On Tuesday, 30 May 2023 at 04:15:22 UTC, Ali Çehreli wrote: On 5/29/23 19:57, Cecil Ward wrote: > I wish to have one routine > that can be called with either immutable or (possibly) mutable argument > values. 'const' should take both immutable and mutable. Can you show your case with a short example? > Could I make the one routine into a template? That could work but give 'in' parameters a try: https://dlang.org/spec/function.html#in-params Ali T2 foo( in T1 x ) { return bar( x ) }; It was with something vaguely like the above that I had to remove the in (templatised generic function possibly) in order to get it to compile with GDC or LDC on godbolt.org (or d.godbolt.org) latest versions available. -O3 -release/-frelease -march=native/-mcpu-native I have to admit that I don’t really understand immutable. I have an idea that it could mean that an object has an address in ROM, so its value will never change. Maybe const doesn’t give you such a strong guarantee, disallows ‘you’ from modifying it but others might do so, but who knows. Without a guarantee as strong as the first idea I can’t really understand how const can work properly. "You treat it as const so do not modify it, but it might not be eternally fixed and unchanging" that doesn’t seem to have enough value to me. But maybe I’ve got the whole thing wrong. In an architecture where you have strongly typed (tagged ? segmented?) different kinds of addresses, I can see why you might be getting type mismatch errors when passing addresses around.
Re: Code duplication where you wish to have a routine called with either immutable or mutable arguments
On Tuesday, 30 May 2023 at 04:15:22 UTC, Ali Çehreli wrote: On 5/29/23 19:57, Cecil Ward wrote: > I wish to have one routine > that can be called with either immutable or (possibly) mutable argument > values. 'const' should take both immutable and mutable. Can you show your case with a short example? > Could I make the one routine into a template? That could work but give 'in' parameters a try: https://dlang.org/spec/function.html#in-params Ali T2 foo( in T1 x ) { return bar( x ) }; It was with something vaguely like the above that I had to remove the in (templatised generic function possibly) in order to get it to compile with GDC or LDC on godbolt.org (or d.godbolt.org) latest versions available. -O3 -release/-frelease -march=native/-mcpu-native
Code duplication where you wish to have a routine called with either immutable or mutable arguments
I have often come into difficulties where I wish to have one routine that can be called with either immutable or (possibly) mutable argument values. The argument(s) in question are in, readonly, passed by value or passed by const reference. Anyway, no one is trying to write to the items passed in as args, no badness attempted. When I call the routine from one place with an argument that is immutable and then from another that is not, or it could be const as well, or not, that’s when I get all kinds of type mismatch errors. And I certainly don’t want to pour cast-like type conversion operations over all the place at these problem occurrences. it’s surely asking for problems. Could I make the one routine into a template? Even if I did, that would perhaps create additionally problems, since even if it all worked and instantiated either immutable or mutable forms of the routine, what happens if I have two args and they have a mixture of immutable and no immutable args ? So nargs * 2 ( or more) possibilities? I’m out of my depth here.
Re: quick question, probably of little importance...
On Monday, 1 May 2023 at 03:53:24 UTC, Cecil Ward wrote: On Wednesday, 26 April 2023 at 23:07:39 UTC, WhatMeWorry wrote: [...] Correction: I can’t count. There are only two instructions in parallel with another pair running alongside, not three. The first reg, reg move counts as zero cycles, so the total time is just the sum of the following three instructions’ times, ignoring the other parallel stream.
Re: quick question, probably of little importance...
On Wednesday, 26 April 2023 at 23:07:39 UTC, WhatMeWorry wrote: On Wednesday, 26 April 2023 at 23:02:07 UTC, Richard (Rikki) Andrew Cattermole wrote: Don't forget ``num % 2 == 0``. None should matter, pretty much all production compilers within the last 30 years should recognize all forms of this and do the right thing. Thanks. Fastest reply ever! And I believe across the world? I suppose my examples required overhead of a function call. So maybe num % 2 == 0 is fastest? I made a small change, making the retval a bool rather than an int. I got slightly better code generation with the int, as it seems that some of the compilers have not yet got all the good tricks they should be using when manipulating bool-typed expressions and also it can be one extra instruction converting values to bool strictly zero or one, not zero or any non-zero value. Here’s the D, enlarged a little so that we can see your routine in action, inlined. Your isEven boils down to two instructions with a seriously optimising compiler. I’ve included the x86-64 machine code generated by the GDC and LDC compilers so you can see how fast it is. GDC made a bit of a dog’s breakfast of my longer routine whereas LDC performed superbly. GDC generated twice as much code, but its excellent instruction scheduler and what looks like an awareness of ILP mean that the two streams of instructions will be carried out in parallel so the two streams will only take three instruction times - ie whatever the total time is for those three instruction in the one stream - not six. bool isEven( int num ) { return ! ( num & 1 ); } bool AreBothEven( int a, int b ) // returns true if both arguments are even { return isEven( a ) && isEven( b ); } === Compiler output:: GDC:: x86-64: -O3 -mcpu=native -frelease bool isEven( int ): mov eax, edi not eax and eax, 1 ret bool AreBothEven( int, int ): mov eax, edi not esi not eax and esi, 1 and eax, 1 cmovne eax, esi ret === Compiler LDC: x86-64: -O3 -mcpu=native -release bool isEven( int ): testdil, 1 seteal ret bool AreBothEven( int, int ): or edi, esi testdil, 1 seteal ret
Re: std.socket tutorials? examples?
On Sunday, 30 April 2023 at 22:37:48 UTC, Adam D Ruppe wrote: On Sunday, 30 April 2023 at 22:10:31 UTC, Cecil Ward wrote: How do we wait for an ‘or’ of multiple asynchronous events in this kind of code? You can set a timeout value for Socket.select, but Phobos isn't going to help you with anything other than sockets and timeouts (despite the fact the underlying operating systems can, in fact, do it). There's a few other libs that can help with this, including one I'm aiming to release some time in May, or vibe.d has its own ways of doing it, among others. You can also import core.sys.stuff and call the OS functions without a middle man. But the D stdlib is quite underpowered when it comes to these things. Socket.select is ok but just the basics. Many thanks, Adam.
Re: std.socket tutorials? examples?
On Saturday, 29 April 2023 at 11:26:20 UTC, Adam D Ruppe wrote: On Saturday, 29 April 2023 at 10:56:46 UTC, Jan Allersma wrote: auto clientResult = Socket.select(clientSet, null, null); There's probably nothing in clientSet, so it is waiting for nothing you almost always want to have just one call to select in the program, not two, the whole point is to combine checks. I wrote a thing you might want to read too: http://dpldocs.info/this-week-in-d/Blog.Posted_2019_11_11.html#sockets-tutorial How do we wait for an ‘or’ of multiple asynchronous events in this kind of code? In WinNT iirc there is a very nice o/s function that can wait on various kinds of asynch i/o, waiting on operations of different types if I’ve understood it correctly. The kind of thing I might want to do is wait on an or of IP packets arriving, send-completion of IP packets, timers completing, IPC messages coming in, key presses or event mouse events and the order in which these events arrive is of course not predictable. I might want a key press event to break out of something or to control an application. Everyone wants timer events for timeouts.
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: enum and const or immutable ‘variable’ whose value is known at compile time
On Thursday, 17 September 2020 at 01:57:39 UTC, Mike Parker wrote: On Thursday, 17 September 2020 at 00:32:40 UTC, Cecil Ward So can the result of declaring certain things with enum ever have an _address_ then? (According to legit D code that is, never mind the underlying implementation details, which may not be observable) No. Think of it as a named literal. Thank you Mike. That’s exactly what I thought. And it’s another reason in favour of using enum - that it forbids address-taking and so declares that there will be none.
Re: enum and const or immutable ‘variable’ whose value is known at compile time
On Wednesday, 16 September 2020 at 17:19:13 UTC, Adam D. Ruppe wrote: On Wednesday, 16 September 2020 at 17:12:47 UTC, Cecil Ward wrote: then is there any downside to just using enum all the time? For a non-string array, enum may give runtime allocations that static immutable won't. Generally think of enum as being replaced with the literal representation and array literals actually make a new array. This may or may not matter to you. So can the result of declaring certain things with enum ever have an _address_ then? (According to legit D code that is, never mind the underlying implementation details, which may not be observable) I actually really hate the way enum was bent out of shape and twisted from its original purpose so that finally we end up with a way of defining only one value, not the whole range of permissible values for a type as in the beginning. I wish there were just a keyword ‘constant’ or something (yes, I know, you could just call that something ‘enum’, or ‘const’)
enum and const or immutable ‘variable’ whose value is known at compile time
A really stupid question, I fear. If I have some kind of declaration of some ‘variable’ whose value is strictly known at compile time and I do one of the following (rough syntax) either enum foo = bar; or const foo = bar; or immutable foo = bar; then is there any downside to just using enum all the time? - I don’t need to take the address of foo, in fact want to discourage , (as I said, given that I can do so) Is there any upside either to using enum? I’m a bit nervous about using immutable having had bad allergic reactions when passing immutable ‘variables’ to functions and so just tend to use const or enum.