Re: How use ldc pragmas?
On Friday, 1 October 2021 at 19:23:06 UTC, james.p.leblanc wrote: D-ers, Update from myself to myself (and any others who might use the bash command from my origin posting), I try to compile the above using: ```bash ldc2 -mattr=+avx2 myexample.d -H ~/ldc2/import/ldc/gccbuiltins_x86.di ``` Remove the "-H ..." this should not be used (based on an earlier misunderstanding of mine). Instead, simply use: ```bash ldc2 -mattr=+avx2 myexample.d ``` Cheers, jpl
Re: How use ldc pragmas?
On Friday, 1 October 2021 at 20:19:39 UTC, Imperatorn wrote: Take a look at my post ;) YES! === Thanks to both Imperatorn, and Max for their helpful and quick responses. The problem is SOLVED! I didn't realize that the pragma had to be placed outside of the main() ... but it seems that I should have known this! (Tomorrow, I shall dive into the deeper waters with avx2.) Sometimes, getting a simple example to build from can be the hardest part, eh? Thanks Again, James
Re: How use ldc pragmas?
On Friday, 1 October 2021 at 19:58:30 UTC, max haughton wrote: On Friday, 1 October 2021 at 19:23:06 UTC, james.p.leblanc Is it sqrt.32 or sqrt.f32? Try the latter, LLVM docs seem to agree. Hello Max, Thanks for the correction... unfortunately, even after changing the "32", to "f32", **I receive the same error**. So there is something of a bigger nature that **I am still doing wrong.** I should have noted earlier that I am just trying to mirror the docs found at: https://wiki.dlang.org/LDC-specific_language_changes ```d // provide square root intrinsics pragma(LDC_intrinsic, "llvm.sqrt.f32") float sqrt(float); pragma(LDC_intrinsic, "llvm.sqrt.f64") double sqrt(double); pragma(LDC_intrinsic, "llvm.sqrt.f80") real sqrt(real); // x86 only ``` Any additional hints for ldc instrinsics are greatly appreciated. James
How use ldc pragmas?
D-ers, After experimenting with ldc's autovectorization of avx code, it appears there may be counter-intuitiveness to the autovectorization (especially for complex numbers). (My comment may be wrong, so any corrections are quite welcome). Based on this, I wanted to investigate the use of ldc's pragma capabilities (as found in ldc2/import/gccbuiltins_x86.di). However, getting the ball rolling is a bit difficult, as I have not found a simple example showing the whole process. What I have just now is: ```d // my example.d import std.stdio; import ldc.intrinsics; void main() { writeln("hello"); float x; pragma(LDC_intrinsic, "llvm.sqrt.32") float sqrt(float); } ``` I try to compile the above using: ```bash ldc2 -mattr=+avx2 myexample.d -H ~/ldc2/import/ldc/gccbuiltins_x86.di ``` But receive the following: ```console ldcint.d(11): Error: unrecognized `pragma(LDC_intrinsic)` ``` I get the feeling that I am really "lost in the woods" here, probably missing important aspects. Are there any pointers this forum might have to help here? (A very simple and complete example would be greatly appreciated!) Thanks! James
Re: Rather Bizarre slow downs using Complex!float with avx (ldc).
On Thursday, 30 September 2021 at 16:52:57 UTC, Johan wrote: On Thursday, 30 September 2021 at 16:40:03 UTC, james.p.leblanc Generally, for performance issues like this you need to study assembly output (`--output-s`) or LLVM IR (`--output-ll`). First thing I would look out for is function inlining yes/no. cheers, Johan Johan, Thanks kindly for your reply. As suggested, I have looked at the assembly output. Strangely the fused multiplay add are indeed there in the avx version, but example still runs slower for **Complex!float** data type. I have stripped the code down to a minimum, which demonstrates the weird result: ```d import ldc.attributes; // with or without this line makes no difference import std.stdio; import std.datetime.stopwatch; import std.complex; alias T = Complex!float; auto typestr = "COMPLEX FLOAT"; /* alias T = Complex!double; */ /* auto typestr = "COMPLEX DOUBLE"; */ auto alpha = cast(T) complex(0.1, -0.2); // dummy values to fill arrays auto beta = cast(T) complex(-0.7, 0.6); auto dotprod( T[] x, T[] y) { auto sum = cast(T) 0; foreach( size_t i ; 0 .. x.length) sum += x[i] * conj(y[i]); return sum; } void main() { int nEle = 1000; int nIter = 2000; auto startTime = MonoTime.currTime; auto dur = cast(double) (MonoTime.currTime-startTime).total!"usecs"; T[] x, y; x.length = nEle; y.length = nEle; T z; x[] = alpha; y[] = beta; startTime = MonoTime.currTime; foreach( i ; 0 .. nIter){ foreach( j ; 0 .. nIter){ z = dotprod(x,y); } } auto etime = cast(double) (MonoTime.currTime-startTime).total!"msecs" / 1.0e3; writef(" result: % 5.2f%+5.2fi comp time: %5.2f \n", z.re, z.im, etime); } ``` For convenience I include bash script used compile/run/generate assembly code / and grep: ```bash echo echo "With AVX:" ldc2 -O3 -release question.d --ffast-math -mcpu=haswell question ldc2 -output-s -O3 -release question.d --ffast-math -mcpu=haswell mv question.s question_with_avx.s echo echo "Without AVX" ldc2 -O3 -release question.d question ldc2 -output-s -O3 -release question.d mv question.s question_without_avx.s echo echo "fused multiply adds are found in avx code (as desired)" grep vfmadd *.s /dev/null ``` Here is output when run on my machine: ```console With AVX: result: -190.00+80.00i comp time: 6.45 Without AVX result: -190.00+80.00i comp time: 5.74 fused multiply adds are found in avx code (as desired) question_with_avx.s:vfmadd231ss %xmm2, %xmm5, %xmm3 question_with_avx.s:vfmadd231ss %xmm0, %xmm2, %xmm3 question_with_avx.s:vfmadd231ss %xmm2, %xmm4, %xmm1 question_with_avx.s:vfmadd231ss %xmm3, %xmm5, %xmm1 question_with_avx.s:vfmadd231ss %xmm3, %xmm1, %xmm0 ``` Repeating the experiment after changing to datatype of Complex!double shows AVX code to be twice as fast (perhaps more aligned with expectations). **I admit my confusion as to why the Complex!float is misbehaving.** Does anyone have insight to what is happening? Thanks, James
Rather Bizarre slow downs using Complex!float with avx (ldc).
D-Ers, I have been getting counterintuitive results on avx/no-avx timing experiments. Storyline to date (notes at end): **Experiment #1)** Real float data type (i.e. non-complex numbers), speed comparison. a) moving from non-avx --> avx shows non-realistic speed up of 15-25 X. b) this is weird, but story continues ... **Experiment #2)** Real double data type (non-complex numbers), a) moving from non-avx --> avx again shows amazing gains, but the gains are about half of those seen in Experiment #1, so maybe this looks plausible? **Experiment #3)** Complex!float datatypes: a) now **going from non-avx to avx shows a serious performance LOSS** of 40% to breaking even at best. What is happening here? **Experiment #4)** Complex!double: a) non-avx --> avx shows performancegains again about 2X (so the gains appear to be reasonable). The main question I have is: **"What is going on with the Complex!float performance?"** One might expect floats to have a better perfomance than doubles as we saw with the real-value data (becuase of vector packaging, memory bandwidth, etc). But, **Complex!float shows MUCH WORSE avx performance than Complex!Double (by a factor of almost 4).** ```d //Table of Computation Times // // self math std math // explicit no-explicit explicit no-explicit // align alignalign align // 0.12 0.21 0.15 0.21 ; # Float with AVX // 3.23 3.24 3.30 3.22 ; # Float without AVX // 0.31 0.42 0.31 0.42 ; # Double with AVX // 3.25 3.24 3.24 3.27 ; # Double without AVX // 6.42 6.62 6.61 6.59 ; # Complex!float with AVX // 4.04 4.17 6.68 5.82 ; # Complex!float without AVX // 1.67 1.69 1.73 1.71 ; # Complex!double with AVX // 3.34 3.42 3.28 3.31# Complex!double without AVX ``` Notes: 1) Based on forum hints from ldc experts, I got good guidance on enabling avx ( i.e. compiling modules on command line, using --fast-math and -mcpu=haswell on command line). 2) From Mir-glas experts I received hints to try to implement own version of the complex math. (this is what the "self-math" column refers to). I understand that detail of the computations are not included here, (I can do that if there is interest, and if I figure out an effective way to present it in a forum.) But, I thought I might begin with a simple question, **"Is there some well-known issue that I am missing here". Have others been done this road as well?** Thanks for any and all input. Best Regards, James PS Sorry for the inelegant table ... I do not believe there is a way to include the beautiful bars charts on this forum. Please correct me if there is a way...)
Re: Modules ... "import" vs. "compilation" ... what is the real process here?
On Tuesday, 28 September 2021 at 05:26:29 UTC, Ali Çehreli wrote: On 9/27/21 10:38 AM, james.p.leblanc wrote: In addition to what Mike Parker said, templates do complicate matters here: Templates are instantiated (i.e. compiled for a specific set of template arguments) by modules that actually use those templates. Ali Ali, this is great! ...I had been tempted to also ask about how templates figure into this, but realized that including this in my question would be over complicating the question, so it remained unasked. But, now I have this part answered as well. I very much appreciate the mind-reading tricks going on here on the forum! Thank You, and Best Regards, James
Re: Modules ... "import" vs. "compilation" ... what is the real process here?
On Tuesday, 28 September 2021 at 02:05:43 UTC, Mike Parker wrote: On Monday, 27 September 2021 at 17:38:29 UTC, james.p.leblanc mpilations". Does that help? **Yes!...** === ... this helped immensely! This explanation gave me a much better understanding of how the whole process works. Mike, thanks very much for the time and thought you put into this. Best Regards, James
Modules ... "import" vs. "compilation" ... what is the real process here?
Dear D-ers, I have trouble understanding "module imports" vs. "module compilations". For example, in the dlang.org/tour, we have: **"The import statement makes all public functions and types from the given module available."** And from the dlang.org/spec we have: **"Modules are always compiled at global scope and are unaffected by surrounding attributes or other modifiers."** Finally, there have been discussions about allowing new ways of "compiling a module" by including its name on the command line. For example this from 2017: https://forum.dlang.org/post/tcrdpvqvwxffnewzo...@forum.dlang.org The more I look into this, the more that I realize that I do not understand this as well as I had hoped. So, when we specify the module name on the command line, then it gets compiled along with the other files on the command line (seems reasonable). But, if it is NOT a command line argument, then when does it get compiled?? (I believe that at first cut, only the public functions and types are "grabbed"). But, when and how are the subsequent and necessary module compilation (and linking) steps performed? Finally, we use a "-I" for telling dmd to look for imports in a directory, but why only "look for imports", and not "grab anything from there that is used, AND compile them"? (This question is prompted by some recent desires to use ldc and "fastmath"... which, if I understand correctly, will require me to include all of the related modules on the command line for immediate compilation). But, in a broader sense, I need to understand the related issues better. Thank for all responses, as well as continued patience with my questions. Best Regards, James
Re: AVX for math code ... avx instructions later disappearing ?
On Sunday, 26 September 2021 at 19:00:54 UTC, kinke wrote: On Sunday, 26 September 2021 at 18:08:46 UTC, james.p.leblanc wrote: or even moving the array declarations to before the dot product function, and the avx instructions will disappear! That's because the `@fastmath` UDA applies to the next declaration only, which is the `x` array in your 2nd example (where it obviously has no effect). Either use `@fastmath:` with the colon to apply it to the entire scope, or use `-ffast-math` in the LDC cmdline. Similarly, when moving the function to another module and you don't include that module in the cmdline, it's only imported and not compiled and won't show up in the resulting assembly. Wrt. stack alignment, there aren't any issues with LDC AFAIK (not limited to 16 or whatever like DMD). Kinke, Thanks very much for your response. There were many issues that I had been misunderstanding in my attempts. The provided explanation helped me understand the broader scope of what is happening. (I never even thought about the @fastmath UDA aspect! ... a bit embarrassing for me!) Using the -ffast-math in the LDC cmdline seems to be a most elegant solution. Much appreciated! Regards, James
AVX for math code ... avx instructions later disappearing ?
Dear D-ers, I enjoyed reading some details of incorporating AVX into math code from Johan Engelen's programming blog post: http://johanengelen.github.io/ldc/2016/10/11/Math-performance-LDC.html Basically, one can use the ldc compiler to insert avx code, nice! In playing with some variants of his example code, I realize that there are issues I do not understand. For example, the following code successfully incorporates the avx instructions: ```d // File here is called dotFirst.d import ldc.attributes : fastmath; @fastmath double dot( double[] a, double[] b) { double s = 0.0; foreach (size_t i; 0 .. a.length) { s += a[i] * b[i]; } return s; } double[8] x =[0.0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, ]; double[8] y =[0.0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, ]; void main() { double z = 0.0; z = dot(x, y); } ``` If we run: ldc2 -c -output-s -O3 -release dotFirst.d -mcpu=haswell echo "Results of grep ymm dotFirst.s:" grep ymm dotFirst.s The "grep" shows a number of vector instructions, such as: **vfmadd132pd 160(%rcx,%rdi,8), %ymm5, %ymm1** However, subtle changes in the code (such as moving the dot product function to a module, or even moving the array declarations to before the dot product function, and the avx instructions will disappear! ```d import ldc.attributes : fastmath; @fastmath double[8] x =[0.0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, ]; double[8] y =[0.0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, ]; double dot( double[] a, double[] b) { double s = 0.0; foreach (size_t i; 0 .. a.length) { ... ``` Now a grep will not find a single **ymm**. It is understood that ldc needs proper alignment to be able to do the vector instructions... **But my question is:** how is proper alignment guaranteed? (Most importantly how guaranteed among code using modules)?? (There are related stack alignment issues -- 16?) Best Regards, James PS I have come across scattered bits of (sometimes contradictory) information on avx/simd for dlang. Is there a canonical source for vector info?
Re: Casting JSONValues arrays to native arrays ... ??? ...
On Thursday, 23 September 2021 at 20:32:36 UTC, james.p.leblanc wrote: On Thursday, 23 September 2021 at 19:18:11 UTC, james.p.leblanc wrote: On Thursday, 23 September 2021 at 19:04:47 UTC, Steven Schveighoffer wrote: On 9/23/21 2:20 PM, james.p.leblanc wrote: ``` Produces: typeid(jj): std.json.JSONValue, jj: {"ba":[true,false,true],"d":[1.23399]} typeid(z5): question.main.MapResult!(__lambda2, JSONValue[]).MapResult, z5: [true, false, true] z5: [true, false, true] Sigh ... my suggested "minor edit" above produces a "map result" instead of the desired native array ... here is the **fix** by appending ".array" at the end (which is the suffix Steve originally offered). The following gives the desired **bool[]** result. ```d import std.array; auto z5 = jj["ba"].array.map!(v => v.get!bool).array; writeln("typeid(z5): ", typeid(z5), ", z5: ", z5); writeln("z5: ", z5); ``` Regards, James
Re: Casting JSONValues arrays to native arrays ... ??? ...
On Thursday, 23 September 2021 at 19:18:11 UTC, james.p.leblanc wrote: On Thursday, 23 September 2021 at 19:04:47 UTC, Steven Schveighoffer wrote: On 9/23/21 2:20 PM, james.p.leblanc wrote: Dear D-ers, Here comes a minor update (small rearrangement in mapping/array ordering) for anyone who may be interested. With this small edit to the suggested code, it works just fine! Here: ```d auto z5 = jj["ba"].array.map!(v => v.get!bool); writeln("typeid(z5): ", typeid(z5), ", z5: ", z5); writeln("z5: ", z5); ``` Produces: typeid(jj): std.json.JSONValue, jj: {"ba":[true,false,true],"d":[1.23399]} typeid(z5): question.main.MapResult!(__lambda2, JSONValue[]).MapResult, z5: [true, false, true] z5: [true, false, true] Cheers, James
Re: Casting JSONValues arrays to native arrays ... ??? ...
On Thursday, 23 September 2021 at 19:04:47 UTC, Steven Schveighoffer wrote: On 9/23/21 2:20 PM, james.p.leblanc wrote: Dear D-ers, In attempting to cast JSONValues that hold arrays to "native" How you really do this: ```d import std.algorithm : map; auto z5 = jj["ba"] // get the JSONValue that is at the key "ba" .map!(v => v.get!bool) // map each value into a boolean .array // create an array out of the results; assert z5 == [true, false, true]; ``` (warning, untested) -Steve Steve, Your thorough explanations have helped me understand quite much. Thank you for your energy and patience in these forum contributions. In fact, I had begun to think that "map", may be what was needed here and I had made a few naive attempts ... but this did not go so well. With your suggested solution, I believe I can make headway on this. Thanks Again, James
Casting JSONValues arrays to native arrays ... ??? ...
Dear D-ers, In attempting to cast JSONValues that hold arrays to "native" array types, I have hit some issues. Example code: ```d import std.stdio; import std.json; void main(){ JSONValue jj; jj["d"] = [ 1.234 ]; // a "dummy" double value jj["ba"] = [ true, false, true]; // "ba" boolean array writeln("typeid(jj): ", typeid(jj), ", jj: ", jj ); // various things that I thought might work, but do NOT auto z1 = cast(bool) jj["ba"]; // attempt #1 auto z2 = cast(bool[]) jj["ba"]; // attempt #2 auto z3 = cast(bool) jj["ba"].array; // attempt #3 auto z4 = cast(bool[]) jj["ba"].array; // attempt #4 writeln("typeid(z4): ", typeid(z4), ", z4: ", z4 ); } ``` Attempts 1,2, and 3 yield compilation errors (which I somewhat understand): question.d(12): Error: cannot cast expression `jj.opIndex("ba")` of type `JSONValue` to `bool` question.d(13): Error: cannot cast expression `jj.opIndex("ba")` of type `JSONValue` to `bool[]` question.d(14): Error: cannot cast expression `jj.opIndex("ba").array()` of type `JSONValue[]` to `bool` However, if I comment out the offending attempts (1, 2, and 3), then it compiles, and can run ... but produces a result which I very much do NOT understand: typeid(jj): std.json.JSONValue, jj: {"ba":[true,false,true],"d":[1.23399]} typeid(z4): bool[], z4: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false] H... is there a standard way to push these JSONValues into nice native array types? (The real code is eventually going to be using traits and mixins ... but I do not think this should pose additional problems). All help and illumination thankfully received. Best Regards, James
Re: Merge 2 structs together (into a single struct)?
On Friday, 17 September 2021 at 00:36:42 UTC, ag0aep6g wrote: On 16.09.21 22:53, jfondren wrote: string joinstruct(A, B)(string name) { struct JoinStruct(Structs ...) { static foreach (S; Structs) { static foreach (i, alias f; S.tupleof) { mixin("typeof(f) ", __traits(identifier, f), " = S.init.tupleof[i];"); Ali, jfondren, ag0aep6g, All of your responses are greatly appreciated. I have done test implementations of them all, and they work well with my intended application. (Also, I learned something new from all of them). The struct mixin template appears to be quite robust and elegant. So, I include a simple implementation for any future readers to take it for a "test drive". ```d import std.stdio; import std.traits; template JoinStruct(Structs ...) { static foreach (S; Structs) { static foreach(i, alias f; S.tupleof) { mixin("typeof(f) ", __traits(identifier, f), " = S.init.tupleof[i];"); } } } void main(){ struct A { int alpha; float x = 1.23; } struct B { int beta; float y = 4.4; string s = "this is fine."; } struct C { int gamma = 42; double z = 1.2e8; string t = "if this was named 's', duplicate would be detected at compile time"; } struct D { mixin JoinStruct!(A,B,C); } A a; B b; C c; writeln("\na:", a); writeln("\nb:", b); writeln("\nc:", c) auto d = D(); writeln("\nd:", d); } ``` My next steps would be to include some UDA's to ease the getopt building for command line arguments. There is a sketch from Jesse Phillips at https://dev.to/jessekphillips/argument-parsing-into-structure-4p4n For example: ```d // Specify The Parameter Structure struct Options { @Option("threads", "t") @Help("Number of threads to use.") size_t threads; @Option("file") @Help("Input files") string[] files; } ``` Again, thanks to you and many of the D community with helping to learn and appreciate the capabilities of D. It is nice to be here. Best Regards, James
Merge 2 structs together (into a single struct)?
Dear All, I really thought that this would be a simple enough small project in meta programming/reflection. Consisely, merge two structures, which are coming from two different elements of the code base. (One contains standard input options for getopt, and the other is for user customization for getopt.) And while there are many hints, and partial solutions among forum posts, and books, my many attempts have not been successful. Is there some obvious, and simple solution to this conundrum of mine? ```d struct A { int alpha; float x = 1.23; } struct B { int beta; float y = 4.4; string s = "this is fine."; } ``` some static foreach magic, and mixins later ... we have the merger ```d struct AB { int alpha; float x = 1.23; int beta; float y = 4.4; string s = "this is fine."; } ``` ... the point of this is really to use the struct AB for getopt reading of command line options. All pointers, tips and info are greatly appreciated. Best Regards, James
Re: How can we view source code that has been generated (say via "static foreach") ?
On Thursday, 16 September 2021 at 03:26:46 UTC, Tejas wrote: On Wednesday, 15 September 2021 at 19:59:43 UTC, james.p.leblanc wrote: s Use the `mixin` compiler flag `dmd -mixin= file.d` Beware, this will also include **all** the mixin code from standard library and runtime. But it's manageable, reflecting on my experience. Tejas, Thank you for your kind response. Wow, at first the large output file from a small test program was a bit surprising .., but actually it is manageable to dig through to find the interesting bits. So, this is quite useful! Thanks again, now I am off to do some digging... Best Regards, James
How can we view source code that has been generated (say via "static foreach") ?
Dear All, In attempting to learn and use code generation, it would be useful to be able to view the source code that gets generated. However, with various combinations of templates, UDAs, and mixins it has not been easy. Is there some standard way this is done? Optimal would be to print out the entire generated source code to allow inspection. Best Regards, James
Re: Curious effect with traits, meta, and a foreach loop ... mystifies me.
On Thursday, 9 September 2021 at 05:37:35 UTC, Tejas wrote: On Thursday, 9 September 2021 at 05:32:29 UTC, Tejas wrote: On Tuesday, 7 September 2021 at 17:47:15 UTC, james.p.leblanc wrote: [...] writeln(&buffer[0]); scope(exit) AlignedMallocator.instance.deallocate(buffer); //... } ``` Is this it? Also, link : https://dlang.org/phobos/std_experimental_allocator_mallocator.html#.Mallocator.reallocate Adam, Tejas, Thanks for all of your kind suggestions (the struct wrapper -as_array, runtime switch), and (AlignedMallocator). All of these move me closer to a solution. Moreover, the suggestions give me a broader perspective. So I very much appreciate the time and effort volunteered by the dlang community to help newcomers such as myself. Best Regards, James
Can we rely on LDC respecting "align" (for avx) ??
Dear All, In searching through the forum archives (going back to 2013, 2016 etc), and experiments, it **appears to me** that LDC does indeed respect the standard "align" properties. (Meaning: proper alignment for using AVX with static arrays can be guaranteed). Experiments (and forum discussions) also lead me to believe that DMD does NOT respect this alignment. So, what is the "official status" of AVX alignment possibilities? Succinctly: 1) Can we truly rely on LDC's alignment for AVX ? 2) Is DMD presently **not** respecting alignment? (Or have I misunderstood?) This has important impact on performance of numerical computations. Thanks for all illumination! James
Re: Curious effect with traits, meta, and a foreach loop ... mystifies me.
On Tuesday, 7 September 2021 at 17:33:31 UTC, Adam D Ruppe wrote: On Tuesday, 7 September 2021 at 17:24:34 UTC, james.p.leblanc wrote: If you want to do a runtime lookup, you need to separate the two pieces. This pattern works: switch(runtime_index) { foreach(i, val; item.tupleof) case i: // use val } So the switch is at runtime but the loop and cases are all known at compile time. Adam, Thanks for the very fast, and very thorough explanation. I especially appreciate the fact that you seem to have predicted where my thoughts were heading with my experiments ... The "switch(runtime_index)" snippet will come in handy ... What I would **REALLY** like is to be able to do (but I think this is impossible) would be to "dig out" the needed "x" array depending on which one of them suits my alignment needs. (Yes, I am still playing with avx2 ideas ...). What I mean by "dig out" the needed "x" is: if I could alias/enum/ or someother trick be then able just to use that "x" as a simple static array. (I doubt this is possible ... but ?). Thanks again, Keep Warm in Upstate! James
Curious effect with traits, meta, and a foreach loop ... mystifies me.
Dear All, In playing with some reflection and meta programming, this curiosity appeared. Does someone understand what is happening? I would appreciate learning about it if possible. Enclosed code snippet tells the story: ```d import std.stdio; import std.traits; import std.meta; struct S0{ double[3] x; }; struct S1{ double junk0 ; double[3] x; }; union U { S0 s0; S1 s1; } void main(){ U u; double* ptr; u.s0.x = [ 0.0, 0.1, 0.3 ]; u.s1.x = [ 1.0, 1.1, 1.3 ]; writeln("typeid( u.tupleof): ",typeid( u.tupleof ) ); writeln("typeid( u.tupleof[0]): ", typeid( u.tupleof[0] ) ); writeln("typeid( u.tupleof[0].x): ", typeid( u.tupleof[0].x ) ); writeln(); // indeed both tuples exist writeln("u.tupleof[0].x.ptr: ", u.tupleof[0].x.ptr ); writeln("u.tupleof[1].x.ptr: ", u.tupleof[1].x.ptr ); // this is fine (notice that 'val' is never used foreach( i, val ; u.tupleof ){ ptr = u.tupleof[i].x.ptr; writeln("ptr: ", ptr); } // this fails with: "Error: variable 'i' cannot be read at compile time // // foreach( i ; 0 .. 3 ){ //ptr = u.tupleof[i].x.ptr; //writeln("ptr: ", ptr); // } } ``` Best Regards, James
Re: "+=" (overloads) with custom array slices on both lhs, and rhs ??
On Sunday, 5 September 2021 at 21:25:06 UTC, jfondren wrote: On Sunday, 5 September 2021 at 20:49:08 UTC, james.p.leblanc wrote: Here's a reduction of your myArray.d that works with your unchanged usage code: ```d module myArray; import std.stdio; void opOpAssign(string op)(myArray rhs) if (op == "+") { foreach (i; 0 .. length) { mixin("ptr[i] " ~ op ~ "= rhs.ptr[i];"); } } ``` Wow, these quick and helpful replies are gratefully received! They have helped me learn many new aspects of D (especially the overloading!) Serious thanks to **all**. Best Regards, James
Re: "+=" (overloads) with custom array slices on both lhs, and rhs ??
On Sunday, 5 September 2021 at 21:06:49 UTC, Ali Çehreli wrote: On 9/5/21 12:43 PM, james.p.leblanc wrote: m[4 .. $] -= 100; writeln(m); m[] *= 2; writeln(m); } Ali Ali, Thanks for your example code ... I have much to learn from this and will need to study it tomorrow when I am fresh. I hope that I will see how to extend this so that it can do slices on both the left side and right side ... for example: ```d m[ 4 .. 8 ] += q[ 7 .. 11 ]; ``` Best Regards, James
Re: "+=" (overloads) with custom array slices on both lhs, and rhs ??
On Sunday, 5 September 2021 at 20:38:29 UTC, Paul Backus wrote: On Sunday, 5 September 2021 at 19:43:20 UTC, james.p.leblanc wrote: Dear D-ers, I have constructed a custom array type that works, but is missing correct functioning on some operator overloads. [...] ```d import std.stdio; import myarray_mod; ``` Please post the source code for `myarray_mod` so that we can reproduce the errors you're seeing. Hello Paul, Thanks for having a look ... James ```d module myArray_mod; import std.stdio; struct myArray{ int* ptr; size_t length; this( int* ptr, size_t length){ this.ptr = ptr; this.length = length; } myArray opIndex(){ return this; } int opIndex(size_t i){ return ptr[i]; } int[] opIndex( SliceInfo info ){ return ptr[ info.start .. info.end ]; } void opIndexAssign(int val, size_t i){ ptr[i] = val; return; } void opIndexAssign(int val, SliceInfo info){ auto ctr=0; foreach( i ; info.start .. info.end ){ ptr[i] = val; } return; } void opIndexAssign(int[] val, SliceInfo info){ auto ctr=0; foreach( i ; info.start .. info.end ){ ptr[i] = val[ctr++]; } return; } // === void opIndexOpAssign(string op)(int val, int ind){ writeln("opIndexOpAssign with INTEGER"); if( (op == "+") || (op == "-") || (op == "*") || (op == "/") ){ mixin(" ptr[ind] " ~ op ~ "= val;"); } return; } void opIndexOpAssign(string op)(int val, SliceInfo info){ writeln("opIndexOpAssign with SLICE"); if( (op == "+") || (op == "-") || (op == "*") || (op == "/") ){ foreach( i ; 0 .. length ){ mixin(" ptr[i] " ~ op ~ "= val;"); } } return; } void opIndexOpAssign(string op)(SliceInfo rhs, SliceInfo lhs){ writeln("opIndexOpAssign with LHS SLICE and RHS SLICE "); if( (op == "+") || (op == "-") || (op == "*") || (op == "/") ){ foreach( i ; 0 .. length ){ mixin(" ptr[i] " ~ op ~ "= 1;"); } } return; } myArray opBinary(string op)(myArray rhs){ writeln("opBinary"); if( (op == "+=") || (op == "-=") || (op == "*=") || (op == "/=") ){ foreach( i ; 0 .. length ){ mixin(" ptr[i] " ~ op ~ " rhs.ptr[i];"); } } return; } struct SliceInfo{ size_t start, end; } SliceInfo opSlice(size_t dim)(size_t start, size_t end){ return SliceInfo(start, end); } void toString(scope void delegate(const(char)[]) sink) const { import std.format; sink("["); foreach( i ; 0 .. length ){ formattedWrite( sink, "%s", ptr[i] ); if( i< length-1 ) sink(", "); } sink("]"); } } ```
"+=" (overloads) with custom array slices on both lhs, and rhs ??
Dear D-ers, I have constructed a custom array type that works, but is missing correct functioning on some operator overloads. The stripped down minimum example (module) was over 100 lines (due overloading opAssign, etc.) Probably too long to be a good forum post. However, a short main may explain the issue succinctly (at end). In words: the standard D static arrays, and dynamic array can do a "vector accumulation" using: ```d f += g; ``` We can even have slices on both lhs and rhs: ```d f[ 2 .. 5 ] += g[ 4 .. 7 ]; ``` So, this **should** be possibly for custom array types. I have looked at opIndexOpAssign, and learned a great deal from Michael Parkers book on the use of opSlice, etc. with overloads. Also, I have searched for clues in the dmd source code ... but it was not easy to perceive how this is done. Here is an ugly code example (without module code -- so maybe useless). How does one overload custom types with "+=" and slices on both left and right? Thanks in advance, James **compilation error message appear as comments to right of offending lines** == ```d import std.stdio; import myarray_mod; void main(){ // static arrays int[7] x = [ 10, 11, 12, 13, 14, 15, 16 ]; int[7] y = [ 100, 101, 102, 103, 104, 105, 106 ]; // custom "arrays" auto f = myArray( x.ptr, 7 ); auto g = myArray( y.ptr, 6 ); f[ 1 ] += 909; // accumulating a scalar works fine f[] += 909; // "f.opIndex() is not an lvalue and cannot be modified f += g; // f is not a scale is is a myArray f[ 2 .. 5 ]+=g[ 2 .. 5]; //f.opIndex(f.opSlice(2LU, 5LU ... (possible missing[]) // for standard dynamic arrays, this works fine int[] a = [ 1, 2, 3, 4, 5, 6 ]; int[] b = [ 4, 5, 6, 7, 8, 9 ]; writeln("a: ", a); writeln("b: ", b); a[ 1 .. 4 ] += b[ 2 .. 5 ]; // even with slices on both lhs & rhs!! writeln("a: ", a); return; } ```
Re: Forum posting question ... how post a thread question with color syntax highlighting ??
On Sunday, 5 September 2021 at 17:55:09 UTC, Steven Schveighoffer wrote: On 9/5/21 1:48 PM, james.p.leblanc wrote: Dear All, In case you can't find it, the info is [here](https://forum.dlang.org/help#markdown) -Steve THANKS! (Also ... sigh ... I swear I have looked at the markdon page that Steve linked to several times! But, my eyes had been looking for the beautiful green and blue text as an example ... So, I completely missed the fact that the "highlight syntax" in the box was exactly what I was looking for. My fault completely ... sorry for injecting noise! James (**Sheepishly** backing away from my keyboard now).
Forum posting question ... how post a thread question with color syntax highlighting ??
Dear All, I have noticed that quite a few posts and responses on this forum include d snippets made with **nicely colored syntax highlighting.** (I do not mean just the bold markdown text.) This increases post clarity significantly. How is this being done? (I hope that this is not considered off topic. My goal would be able to make such posts myself. But also, if more post in this manner, it may help many.) Best Regards, James
Re: Singleton Object, calling member functions using UFCS (an "ugly?" example) ... better way?
On Wednesday, 1 September 2021 at 22:11:29 UTC, user1234 wrote: On Wednesday, 1 September 2021 at 22:01:12 UTC, user1234 wrote: ``` ProcessPipes gnuplot () { __gshared ProcessPipes pipe; return pipe.pid ? pipe : (pipe = pipeProcess("/usr/local/bin/gnuplot")); } ``` user1234, Thanks! This is perfect, getting rid of the class altogether. Yes, as pointed out in your response, that class was rather useless. (For some unknown reason, I had been stuck on creating a singleton to avoid multiple gnuplot processes -- very unnecessary as I now see.). The ternary operator with the pipe id is much cleaner and leaner. Thanks again, for your time, energy and insight. Best Regards, James
Re: Singleton Object, calling member functions using UFCS (an "ugly?" example) ... better way?
On Wednesday, 1 September 2021 at 19:54:14 UTC, user1234 wrote: On Wednesday, 1 September 2021 at 16:02:47 UTC, james.p.leblanc wrote: Dear D-ers, For simple plotting using a gnuplot process, I have created a singleton object (a stripped down minimal working example is below.) [...] **However, those wrapper functions in the gnuplot_mod module looks a bit silly.** [...] Any suggestions on a better way are greatly appreciated. Best Regards, James hello, I'd suggest this: ```d shared static this() { get(); // cache instance before main(){} // to get rid of the synchronized() stmt } static Gnuplot get() { __gshared Gnuplot instance; return instance ? instance : (instance = new Gnuplot()); } ``` user1234, Thanks for your reply, I will need to look at it deeper. I also realize that my post was not so clear, to clarify: I needed to implement two wrapper functions ... that are **in** the module, but **outside** of the object, copied below: **void cmd(string txt){** **Gnuplot gp;** **gp = gp.get();** **gp.cmd(txt);** **}** **void plot(double[] x, string txt){** **Gnuplot gp;** **gp = gp.get();** **gp.plot(x, txt);** **}** These enable use of the UFCS in main() (without prefixing with instantiated object's name **gp** ). The gp prefix only needs to be in these wrappers that exist in the module, not in the main(). The question is if there is a way to enable UFCS without such wrapper (see example in main() in original posting). Thanks again, and now I need to play a bit with your suggestion to learn from it. Best Regards, James
Singleton Object, calling member functions using UFCS (an "ugly?" example) ... better way?
Dear D-ers, For simple plotting using a gnuplot process, I have created a singleton object (a stripped down minimal working example is below.) In the example, there are two plots calls: 1) First, call is made using the object member function "gp.plot(x, etc.)" 2) The second uses a wrapper to allow use of the UFCS (uniform function call syntax) The ability to use the UFCS has the usual UFCS advantages, additionally the coder doesn't need to care about the actual name of the object's instantiation. **However, those wrapper functions in the gnuplot_mod module looks a bit silly.** **Is there a more elegant way to do this?** First, the module: -- module gnuplot_mod; import std.stdio; import std.process; import std.conv : to; class Gnuplot { // modification of wiki.dlang.org/Low-Lock_Singleton_Pattern ProcessPipes pipe; private this() { this.pipe = pipeProcess("/usr/local/bin/gnuplot") ; } private static bool instantiated_; private __gshared Gnuplot instance_; static Gnuplot get() { if (!instantiated_) { synchronized(Gnuplot.classinfo) { if (!instance_) { instance_ = new Gnuplot(); } instantiated_ = true; } } return instance_; } void cmd(string txt) { this.pipe.stdin.writeln(txt); this.pipe.stdin.flush(); return; } void plot(double[] x, string txt = "ls 21 lw 2"){ this.pipe.stdin.writeln("plot '-' u 1:2 with lines " ~ txt); foreach( ind, val ; x) this.pipe.stdin.writeln( to!string(ind) ~ " " ~ to!string(val) ); this.pipe.stdin.writeln("e"); this.pipe.stdin.flush(); } } void cmd(string txt){ Gnuplot gp; gp = gp.get(); gp.cmd(txt); } void plot(double[] x, string txt){ Gnuplot gp; gp = gp.get(); gp.plot(x, txt); } --- Now, the main ... --- import gnuplot_mod; import std.stdio; void main(){ Gnuplot gp; gp = gp.get(); double[] x = [1.1, 0.2, 3.1, 2.2, 3.1, 0.6]; double[] y = [-1.1, 0.2, -3.1, 2.2, 3.1, -0.6]; writeln("\nusing singleton's member functions: plot and cmd"); gp.plot(x, "ls 31 lw 3"); gp.cmd("pause 2"); writeln("\nusing uniform function call syntax (UFCS): plot and cmd"); y.plot("ls 41 lw 8"); cmd("pause 2"); } Any suggestions on a better way are greatly appreciated. Best Regards, James
Re: pipeProcess, interactions with stderr ... I am missing something here
On Monday, 30 August 2021 at 16:51:12 UTC, Ali Çehreli wrote: In this case, converting your ~this to a named function solves the issue: // Was: ~this() void close() { // ... } // ... auto gp = new Gnuplot(); scope (exit) { gp.close(); } Ali Ali Ali, Yet again, you have helped me. Thanks for the keen eye and clear description of what was happening. I am enjoying this language **very** much, and the community has been incredibly helpful to my progress. Best Regards, James
pipeProcess, interactions with stderr ... I am missing something here
D-ers, I am attempting to use pipeProcess for interacting with an external process. My simplified routine can work somewhat. But, trying to print any messages that process writes to stderr yields the message: (master) gnuplot > gnuplot_example **core.exception.InvalidMemoryOperationError@src/core/exception.d(647): Invalid memory operation** Simplified code: import std.stdio; import std.process; class Gnuplot { ProcessPipes pipe; void cmd(string txt){ pipe.stdin.writeln(txt); pipe.stdin.flush(); } this(){ this.pipe = pipeProcess("/usr/local/bin/gnuplot", Redirect.stdin | Redirect.stdout | Redirect.stderr); } ~this(){ pipe.stdin.close(); pipe.stdout.flush(); pipe.stderr.flush(); foreach( line ; pipe.stdout.byLine ) writeln("stdout: ", line); foreach( line ; pipe.stderr.byLine ) writeln("stderr: ", line); } } void main(){ auto gp = new Gnuplot(); gp.cmd("plot sin(x)"); gp.cmd("pause 2"); gp.cmd("plot line contains error ... should create output to stderr"); gp.cmd("quit"); } Also, I have found a few examples on similar programs (for example in Adam Ruppe's D-Cookbook - page 107), which provide some very good information and examples. But, I do not understand what I am seeing in my program example. **Any pointers are gratefully received. ... especially tutorials or example code** Best Regards, James PS You may note that I do not have the line "scope (exit) wait pipe.pid". Two reasons for this are: I do not understand what this is supposed to do, and attempts to add this froze my program. PPS I have seen some of Steven Schveighoffers helpful descriptions about piped processes and child process hanging with excessive outputs ... this should not be the case here ... only a handful of bytes might possibly be written.
Re: Possible to overload assignment of struct field ??
On Tuesday, 24 August 2021 at 05:34:08 UTC, Ali Çehreli wrote: On 8/23/21 10:25 PM, james.p.leblanc wrote: So, you need a "property". Easy... :) 1) Rename the member e.g. as a_. 2) Write setter and getter functions named 'a'. struct Foo{ int a_; int a() const { return a_; } void a(int value) { a_ = value; } } void main(){ auto x = Foo(1); x.a = 100; assert(x.a == 100); } Ali Ali, Thank you ... yes! This is exactly what I needed, I have done something similar as you have shown for the "getter", but had a "brain-lock-up" when thinking about the setter. A bit embarassing for my, I admit. But, on the positive side ... the solution is now burned into my brain. Thanks again and Kind Regards, James
Possible to overload assignment of struct field ??
Greetings, With a struct, there are many overload possibilities available. However, I haven't been able to find how to overload assignment of **selected fields** of a struct. For example, suppose: struct Foo{ int a; int b; ... } void main(){ auto x = Foo( 1, 2); // so x now instantiates x.a = 100; // suppose I wish to enforce that a<5?? ... } (I understand this is basically a field "setter" idea that is most often associated with classes. So, another way to state the quesion might be: "How can a field setter be done on a **already instantiated** struct?) Best Regards, James
Re: Potential strategy for avoiding problems with copy of a struct (maybe??)
On Sunday, 22 August 2021 at 14:35:48 UTC, Ali Çehreli wrote: On 8/22/21 6:03 AM, james.p.leblanc wrote: > struct Foo { > int a, b, c; > Foo* myadd; > > this(int a, int b, int c) { > this.a = a; > this.b = b; > this.c = c; > this.myadd = &this; As Matthias Lang mentioned, keeping a reference to itself makes a struct object illegal in D. D sees structs as value types: It is supposed that any copy can be used in place of another copy. Ali Ali, You highlight am important point that I have not been completely aware of. Indeed, I did have a few "warning bells" going off in my brain when I began typing "this.myadd = &this;" into my program ... but, it compiled, so I continued (into the potential quicksand, admittedly!) So, thanks for illuminating this issue for me. Also, the "postblit" hint recently posted in this thread, may allow me to procede along a safer path. Kind Regards, James
Re: Potential strategy for avoiding problems with copy of a struct (maybe??)
On Sunday, 22 August 2021 at 13:37:50 UTC, jfondren wrote: this(this) { unique = null; } ~this() { pureFree(unique); } } Dear jfondren, I truly appreciate you taking the time to help me with my question! **This bit of magic with the postblit may hold the key to my issue.** (I have done some experiments based on your example code, am learning much, and it looks VERY encouraging! It is a bit scary how you guessed very closely what I am trying to do. I have a AVX aligned pointers (obtained from fftw_malloc), that I want to protect. To be a bit more specific. The code that reads/writes from to/from fftw routines is all pointer based. But, to allow use of standard dlang things such as "foreach" and friends, I've been cobbling together a (naive) wrapper. This allows me to use standard dlang syntax and operator overloads. I call my struct "fakeArray" ... since it is meant to behave either as a static array, or a dynamic array as needed. It **seems** to work pretty well ... but protecting the arrays from accidental programming mistakes (such as the "auto y=x") has been eluding me. In fact, I **can** do a legitimate data copy via "y = x", as long as y is already instantiated as a "fakeArray". I must steady more the example you kindly provided (learn more about the postblit, and pureFree, the const report function, etc...) Best Regards, James
Re: Potential strategy for avoiding problems with copy of a struct (maybe??)
On Sunday, 22 August 2021 at 11:10:33 UTC, jfondren wrote: On Sunday, 22 August 2021 at 07:58:12 UTC, james.p.leblanc wrote: Hello, If you don't get an answer that you like, I suggesting posting functional code and then stating your dissastisfactions with it. Mattias, jfondren, Thanks both for your replies, I always learn something from them. I've trimmed my code to a minimal example to give a better idea of my thinking on this. You will notice that to ensure that I "seed" x with its real address at initialization, I must add @disable this() to my struct. import std.stdio; struct Foo { int a, b, c; Foo* myadd; this(int a, int b, int c) { this.a = a; this.b = b; this.c = c; this.myadd = &this; } @ disable this(); } void main() { // x is original, we wish to protect auto x = Foo(1, 2, 3); // y is the "bad copy", do not want operation on y to pollute original x auto y=x; writeln("&x: ",&x,", x.myadd: ",x.myadd,", the 2 agree, we have original!"); writeln("&y: ",&y,", y.myadd: ",y.myadd,", these 2 disagree (must be a bad copy!"); } Produces output: &x: **7FFC65C02CC8**, x.myadd: **7FFC65C02CC8**, the 2 agree, we have original! &y: 7FFC65C02CE8, y.myadd: **7FFC65C02CC8**, these 2 disagree (must be a bad copy! So, as stated, in my struct overloading I can check if my two values agree or not (exposing whether or not I have the original, or a copy), and react appropriately. I understand that the language allows circumvention of this method... but I just want to catch minor mistakes in programming. Again, all comments and thoughts are welcome. Best Regards, James
Potential strategy for avoiding problems with copy of a struct (maybe??)
Hello, Question about a possible strategy to avoid problems with undesired/unintended copying of a structure: 1) We have a struct, call this **Foo**. 2) We instantiate it with, **x = Foo(a,b,c);** a. our constructor will initialize a field: **this.myadd = &this** b. this capture the address of our original "x" in x.myadd. 3) We wish to allow, any function calls using x, so we cannot disable Foo's this(this). 4) Our goal is to avoid problems with any accidental copying of x ... say by doing: **auto y=x;** 5) the copy of step 4 **does not use the constructor**, thus y.myadd would contain the address of x (and not y) 6) We can exploit that y.myadd does NOT contain its own address (but instead contains the address of x). This requires adding logic checks in any Foo opAssign, and other overloads. For example, we can disallow any such overloads by checking: if( &this != this.myadd ){ ... } 7) Needing to operate on x with other functions implies that private or const is not a solution. (I believe.) Some initial experiments lead me to believe this may acheive part of what I would like. But, it feels very "hackish" and ugly. Is there a better way? Best Regards, James
Re: classify a user struct as an "array" or "slice"
On Friday, 20 August 2021 at 15:38:04 UTC, Paul Backus wrote: The most straightforward way would be to change your functions from accepting only `T[]` to accepting either `T[]` or `fakeArray`. For example: ```d import std.traits: isDynamicArray; // assuming `fakeArray` is a template struct/class enum isFakeArray(T) = is(T == fakeArray!U, U); auto foo(Array)(Array x) if (isDynamicArray!Array || isFakeArray!Array) { // ... } ``` The `if (...)` part there is a [template constraint][1]. It means that the template can only be instantiated when the condition evaluates to `true`. [1]: https://dlang.org/spec/template.html#template_constraints Paul, This works like a charm! I just implemented it ... I am most thankful for your help again. Next, I imagine that need to add a few "static ifs" later in the function body of foo, wherein I can dig out what the element types of my arrays are ... (I need this to initialize some summers to the correct type, etc.) These past weeks are my first attempts at using templates. It is impressive how powerful they are. I have learned quite much from this forum. But, I obviously have quite a lot to learn. Best Regards, James
classify a user struct as an "array" or "slice"
Greetings, I have a user created struct, let's call this "**fakeArray**": For all intents and purposes fakeArray behaves like an array (or slice, I guess). (i.e. It has a number of operator overloadings, and *foreach* extensions implemented.) I have a fairly large number of function in a module that accept arrays (or slices). These are implemented as: **auto foo(T)(T[] x) { ... }** So, foo will accept "official" arrays and slices. What is the easiest way to coerce all my functions to also accept my fakeArray? Regards, James
Re: simple (I think) eponymous template question ... what is proper idimatic way ?
On Wednesday, 18 August 2021 at 06:53:51 UTC, Tejas wrote: void funcTemplate(T:int)(T a){ writeln("argument is int"); } void funcTemplate(T : long)(T a){ writeln("argument is long integer"); } void main(){ int a; long b; func(a); func(b); funcTemplate(a); funcTemplate(b); } ``` Domninikus, Tejas, and All, I see that I had been (stupidly) omitting the exclamation point after **"isIntegral"** in my clumsy attempts to use the traits ... thanks for your clear example helping me identify my error. Also, thanks for mentioning the words **"template specialization"** , I did not know what to call the use of **":"** in templates. Now, I have a search term I can use to learn more ...and find it is in Phillippe Signaud's informative "D-templates-tutorial". Thanks again, James PS Also, I am enjoying, a entertaining and educational tutorial that Phillippe has linked in his tutorial. Other may learn from this as well: http://www.semitwist.com/articles/EfficientAndFlexible/SinglePage/
Re: simple (I think) eponymous template question ... what is proper idimatic way ?
On Tuesday, 17 August 2021 at 20:28:20 UTC, Alexandru Ermicioi wrote: On Tuesday, 17 August 2021 at 19:53:52 UTC, james.p.leblanc wrote: Wow! That is absolutely beautiful ... I had never seen (or even imagined) a recursive template! This expands my mind in a good way ... and is going into my toolbox immediately. Best Regards, James Just don't over rely on it. It can cause compilation slowdowns, so avoid it if you can. I've been happily trying to absorb all the helpful concepts posted. A final related question in the quest for simplicity and robustness. If I wanted to ensure that a function accepts only arguments of byte, int, uint, long, etc. (i.e. integer-like types). Is the accepted way to do this like so?: **auto foo( T : long )(T a, T b){ ... }** I really wish I could find a good explanation of the ":" (colon) used in templates. I am sure one exists ...but haven't come upon it just yet. (I thought "isIntegral" in traits module would be helpful...but I failed in my experiments.) Thanks for patience with this question! Best Regards, James
Re: simple (I think) eponymous template question ... what is proper idimatic way ?
On Tuesday, 17 August 2021 at 20:13:59 UTC, Paul Backus wrote: FYI: in this particular case, you can use std.meta.staticIndexOf instead of writing the recursion out yourself: import std.meta: staticIndexOf; enum isAmong(T, S...) = staticIndexOf!(T, S) >= 0; Docs: https://phobos.dpldocs.info/std.meta.staticIndexOf.html All, Thanks again ... Paul, I will try this staticIndexOf as you mention. I had been receiving "circular reference to variable" error messages from the "isAmong" suggestion. (But, I very likely had misunderstood how to use this.) I would still be interested to learn what I have done wrong. So, below is my code: import std.stdio; import std.meta : AliasSeq; template isAmong(T, S...) { static if (S.length == 0) enum isAmong = false; else enum isAmong = is(T == S) || isAmong(T, S[1..$]); } alias MyTypes = AliasSeq!(int, float); auto myFunc(T)(T a, T b) if (isAmong!(T, MyTypes)) { writeln(" in myFunc "); return; } void main(){ writeln("started ..."); auto a = 1; auto b = 2; myFunc!(int)(a, b); return; } And, here are the error message: (master) Notes > dmd recursive_template.d recursive_template.d(9): Error: circular reference to variable `recursive_template.isAmong!(int, int, float).isAmong` recursive_template.d(17): Error: template instance `recursive_template.isAmong!(int, int, float)` error instantiating recursive_template.d(29):while looking for match for `myFunc!int` Can anyone see what is going on? Best Regards, James
Re: simple (I think) eponymous template question ... what is proper idimatic way ?
On Tuesday, 17 August 2021 at 19:44:29 UTC, H. S. Teoh wrote: You could use a helper template and an AliasSeq for this: template isAmong(T, S...) { static if (S.length == 0) enum isAmong = false; else enum isAmong = is(T == S) || isAmong(T, S[1..$]); } import std.meta : AliasSeq; alias MyTypes = AliasSeq!(int, float, MySpecialStruct); auto myFunc(T)(T a, T b) if (isAmong!(T, MyTypes)) { ... } T Dear H.S. Teoh, Wow! That is absolutely beautiful ... I had never seen (or even imagined) a recursive template! This expands my mind in a good way ... and is going into my toolbox immediately. Best Regards, James
Re: simple (I think) eponymous template question ... what is proper idimatic way ?
On Tuesday, 17 August 2021 at 18:28:53 UTC, Steven Schveighoffer wrote: On 8/17/21 2:11 PM, james.p.leblanc wrote: Evening All, [Template constraints](https://dlang.org/spec/template.html#template_constraints). -Steve Dear All, Thanks! I was aware of, and have used template constraints in simple ways. But, I should express my question a bit better: "... is there a more elegant way to expression these constraints?" Perhaps by extending Alexandru's "moo" concepts, with a list of allowed types: auto moo(T : (int || float || mySpecialStruct )(T myMoo) {•••} When re-using any such sets, it would be nice to define the set as follows: S = (int || float || mySpecialStruct) and then define "moo" more concisely as: auto moo(T < S)(T myMoo) {•••} ( where I have used "<" to mean "T is a member of S"). Possible? Best Regards, James
simple (I think) eponymous template question ... what is proper idimatic way ?
Evening All, Eponymous templates allow a nice calling syntax. For example, "foo" here can be called without needing the exclamation mark (!) at calling sites. We see that foo is restricting a, and b to be of the same type ... so far, so good. auto foo(T)(T a, T b) { ... } Now, suppose I need to restrict "T" only certain subsets of variable types. I can imagine putting in some "static if" statements in my function body, is one solution. (Also a bit ugly as the allowed types might grow). Is there a more elegant way, to do this? Regards, James PS Any violations should be caught at compile time.
Re: Getting a working example of opIndexAssign using opSlice ... have troubles ...
On Monday, 16 August 2021 at 10:48:19 UTC, Alexandru Ermicioi wrote: On Monday, 16 August 2021 at 06:36:02 UTC, james.p.leblanc wrote: To be honest, I am not exactly sure what is happening here. I am unfamiliar with the "(T : T[])" syntax ... need to read That is template argument secialization. You're saying that T can be accept only types that are arrays of T, where : reads as 'extends'. Now T : T[] might introduce cyclic reference, so more correct would be: foo(T : Z[], Z)(...) Here you say that T might accept only types that are arrays of Z elements. Regards, Alexandru. Alexandru, That is very helpful information. It also answers a nagging question I have been worried about. Specifically, that "T : T[]" bothered me even though I was unfamiliar with the syntax ... now I understand the situation better. Best Regards, James
Re: Getting a working example of opIndexAssign using opSlice ... have troubles ...
On Monday, 16 August 2021 at 06:42:48 UTC, Tejas wrote: If the code works, what's the problem? Hej Again, I was able to construct the working code shown above from help I obtained here in the forum and other resources. My original code was not working ... but updated code is working fine ... so there are no further problems. (Actually, I learned a fair amount in this endeavor!) Cheers! jpl
Re: Getting a working example of opIndexAssign using opSlice ... have troubles ...
On Monday, 16 August 2021 at 06:20:11 UTC, Tejas wrote: Maybe just write `T[]` in code rather than making it happen via the colon? I also have similar troubles, removing the default value always helped me. Can you show the code where you're trying to apply this? Hej Tejas, Sure, here is the code snippet, it resides within a struct along with various operator overloads. To be honest, I am not exactly sure what is happening here. I am unfamiliar with the "(T : T[])" syntax ... need to read up a bit on that. (However, not so eary searching for a ":") BR, jpl // --- cast overloading --- // T[] opCast(T : T[])(){ // this works T[] opCast(T[])(){ // yields: "Error: identifier expected for template value param" T[] x; x.length = this.length; for( int i = 0 ; i< this.length ; i++){ x[i] = this.ptr[i]; } return x; }
Re: Getting a working example of opIndexAssign using opSlice ... have troubles ...
On Monday, 16 August 2021 at 05:26:00 UTC, Tejas wrote: If you're finding the spec too hard, please try Ali's book. I'm sharing the part on operator overloading below: http://ddili.org/ders/d.en/operator_overloading.html Please ping if you still have problems; I'll then write a full program. Hej Tejas! Thanks for your message. I have it working now. Yes, Ali's book is a tremendously good reference. But, I had trouble digging out the "magic sauce" from the pages to get this working. I was able to find the sauce in a forum post by Adam Ruppe (his book is also an excellent place for ideas and code). With "opCast", my difficulty was the description of the type I wish to cast to uses a colon ":". Here is the line that allows it to function as desired: **>> T[] opCast(T : T[])(){... }** Best Regards, jpl
Re: Getting a working example of opIndexAssign using opSlice ... have troubles ...
On Sunday, 15 August 2021 at 21:28:53 UTC, james.p.leblanc wrote: On Sunday, 15 August 2021 at 21:15:02 UTC, Bastiaan Veelo wrote: On Sunday, 15 August 2021 at 20:41:51 UTC, james.p.leblanc — Bastiaan. Bastiaan, Thanks once again, James On Sunday, 15 August 2021 at 21:28:53 UTC, james.p.leblanc wrote: Okay! Great! Thanks everyone Bastiaan, ag0aep6g, and russhy ... I see more replies come in while I was typing. There is some excellent information here that I need to digest. I believe that I have what I need. This group has been great! BR, James
Re: Getting a working example of opIndexAssign using opSlice ... have troubles ...
On Sunday, 15 August 2021 at 21:15:02 UTC, Bastiaan Veelo wrote: On Sunday, 15 August 2021 at 20:41:51 UTC, james.p.leblanc — Bastiaan. Bastiaan, Thanks kindly for your response! Unfortunately, I do not see what the program does. I mean A is a structure that has only functions. So, how are any elements of this being set to the value of v? I tried extending the code mentioned by adding a member array, but no luck. I often have difficulties to understand the notations used in the spec, and only sometimes can I extend them to working examples. Would it be possible to add the last couple of details regarding an array member? I attempted but the values always remain zero even when I set v=4. import std; struct A { int[5] a; int opIndexAssign(int v) // overloads a[] = v { writeln(__FUNCTION__); return 42; } int opIndexAssign(int vh, size_t[2] x) // overloads a[i .. j] = v { writeln(__FUNCTION__); return 43; } int[2] opSlice(size_t x, size_t y) // overloads i .. j { writeln(__FUNCTION__); return [44, 45]; } } void main() { A a; int v=4; writeln(a); a[] = v; // same as a.opIndexAssign(v); writeln(a); a[3..4] = v; // same as a.opIndexAssign(v, a.opSlice(3,4)); writeln(a); } Thanks once again, James
Getting a working example of opIndexAssign using opSlice ... have troubles ...
Greetings, I have been trying to get a working example of slice assignment operator overloading ... and am befuddled. From the spec (section 20.6.2), the code below appears: struct A { int opIndexAssign(int v); // overloads a[] = v int opIndexAssign(int v, size_t[2] x); // overloads a[i .. j] = v int[2] opSlice(size_t x, size_t y); // overloads i .. j } void test() { A a; int v; a[] = v; // same as a.opIndexAssign(v); a[3..4] = v; // same as a.opIndexAssign(v, a.opSlice(3,4)); } I have hacked at this trying to get a simple working example. Could anyone guide me here please? Best Regards, James
Re: Looping over Template Types ... possible?
On Saturday, 14 August 2021 at 20:20:01 UTC, Stefan Koch wrote: On Saturday, 14 August 2021 at 20:07:21 UTC, james.p.leblanc wrote: mes it is possible look for `AliasSeq` in `std.meta` foreach(T; AliasSeq!(float, double)) { ... } Stefan, Thanks very much for your help here ... I had not understood that AliasSeq worked in this manner. I definitely need read the AliasSeq and try to understand how to use this. Best Regards, James
Looping over Template Types ... possible?
Good Evening/Day, Suppose I have a number of function templates that each take two types, say S and T. I would like to exercise my routines over the combinations of types: set of all S: ( double[], float[], Complex!double[], Complex!float[]) set of all T: ( double, float) Is something along the line of the following sketch possible? foreach( s in S){ foreach( t in T){ foo!(S,T)( T x, S y); biz!(S,T)( T x, S y); } } I have done some searching for hints about this, but I perhaps my search terms are not very good. All hint and pointers thankfully received. Best Regards, James
Re: aliasing functions with function arguments as well ??
On Friday, 13 August 2021 at 15:14:00 UTC, Steven Schveighoffer wrote: There isn't a way to alias it. You can wrap it though, and hope the inliner takes care of the difference: ```d auto foo(T)(T arg) { static if(is(T == int)) return bar(arg, 42.33); else return bar(7, arg); } ``` -Steve Steve, Thanks! Yes ... this templated wrapper should be perfect for me! Your help on my present question, as well as your continual contributions to the forum are greatly appreciated! Best Regards, James
aliasing functions with function arguments as well ??
Dear All, How does one use 'alias' to incorporate function arguments as well? (I believe this is possible, from some of the examples of aliasSeq, and the traits.Parameters documentation. However, I was unable to come up with anything that works.) What should replace the question marks (???) below? double bar( int a, double x){ return a*x: } template foo(T){ static if ( is(T==int) ){ alias ??? = ??? } else{ alias ??? = ??? } } // when T == int, I desire the aliasing to produce resulting code: foo( int a) = bar( int a, 42.33); // when T == double, I desire: foo( double x) = bar( 7, x); Thanks kindly for any information! James PS I am aware of the "struct holding a function allowing multiple dispatch concept" ... while that would fit quite okay here in my simple example, it isn't appropriate for my real use.
Re: nested templates using Complex! with slices, ... confused, I am!
On Monday, 9 August 2021 at 18:44:34 UTC, Paul Backus wrote: On Monday, 9 August 2021 at 18:35:56 UTC, james.p.leblanc wrote: ```d T[] foo_temp(Complex!T[])(T x, T y){ auto r = [x, x]; auto i = [y, y]; auto z = [ Complex!T(x, y), Complex!T(x,y) ]; return z; } ``` void main(){ auto yd = foo_double(1.1, 2.2); writeln(yd); ... } But, no ... I am WRONG! I get the message: qqq.d(18): Error: identifier expected for template value parameter I think what you want is: ```d Complex!T[] foo_temp(T)(T x, T y) { auto r = [x, x]; auto i = [y, y]; auto z = [ Complex!T(x, y), Complex!T(x,y) ]; return z; } ``` This is what I get when I take one of the non-template versions and replace `float` or `double` with `T`. H.S & Paul, Wow, thanks for the quick replies! It all seems so simple now ... but I just could not see it! I had been completely (and confidently, unfortunately) misunderstanding the syntax of that left most column. Thanks again, James
nested templates using Complex! with slices, ... confused, I am!
Suppose "foo_double" should return a complex double slice, with double input args. Similarly "foo_float" should return a float slice, with float input args. I thought it should be easy to parameterize with a template taking a SINGLE argument, either a"double" or "float" as follows: import std.stdio; import std.complex; Complex!double[] foo_double(double x, double y){ auto r = [x, x]; auto i = [y, y]; auto z = [ Complex!double(x, y), Complex!double(x,y) ]; return z; } Complex!float[] foo_float(float x, float y){ auto r = [x, x]; auto i = [y, y]; auto z = [ Complex!float(x, y), Complex!float(x,y) ]; return z; } **T[] foo_temp(Complex!T[])(T x, T y){ auto r = [x, x]; auto i = [y, y]; auto z = [ Complex!T(x, y), Complex!T(x,y) ]; return z; }** void main(){ auto yd = foo_double(1.1, 2.2); writeln(yd); ... } But, no ... I am WRONG! I get the message: qqq.d(18): Error: identifier expected for template value parameter Nested templates using Complex! really have me confused. How should I be thinking about such things in order to understand better? Best Regards, James
How elegantly "funnel" all operator overloads or interest through a struct?
I have a struct where I use a number of "invariant(){enforce( blah, blah ...);}" statements in the struct body to enforce certain conditions on a struct member. Since these "invariants" are only called when struct member functions are exercised, must I overload each individual operation that may lead to a violation? Or, is there any way to funnel all such operations, so my invariants are exercised? --- For example, struct member "x" is an integer slice, I can account for *some of* the operations that affect the slice slice via (such as the append operator): // overloaded to activate enforcements void opOpAssign(string op)(int a){mixin("this.x"~op~"= a;");} void opOpAssign(string op)(int[] a){mixin("this.x"~op~"= a;");} (since these are picked up as member function, they can exercise my "invariant"). But there are a number of slicing operation that I also need to be careful of. I must disallow any operation that changes the length of my slice, or the pointer associated with my slice. How should I account for all combinations of operations that might change size of slice member? Any elegant solutions here? Best Regards, James
Re: using "invariant" with structs ... possible to call when a field value is set??
On Sunday, 8 August 2021 at 11:36:51 UTC, FeepingCreature wrote: You can make a field set function like so: ``` struct S { private int x_; int x(int value) { return this.x_ = value; } int x() { return this.x_; } } ``` This will then run invariants. (boilerplate can automate that for you. https://code.dlang.org/packages/boilerplate cough self-advertisement cough) FC, Thanks! This is exactly what I had hoped might be possible! I had made some naive "newbie-D" attempts at something like this be couldn't get anything to work. Thanks for providing an exable of the exact code that would work. Much obliged! Best Regards, James PS Even more important than solving my immediate problem, I have gained a better understanding of the struct and its member functions.
using "invariant" with structs ... possible to call when a field value is set??
Hello, With structs, I understand that "invariant checking" is called (from dlang tour): It's called after the constructor has run and before the destructor is called. It's called before entering a member function invariant() is called after exiting a member function. But, is is possible to have the invariant checking be performed whenever a field is directly set? For example, suppose a struct "S", has a field "x". I would like to have invariance check in cases such as: S.x = 4; Maybe there is a hidden set field function that gets called that might be exploitable?? Thoughts on this? Possible? Better paths that I should consider? Best Regards, James
Re: Proper way to protect (lock) a struct field after initialization ??
On Sunday, 8 August 2021 at 10:40:51 UTC, Ali Çehreli wrote: I understand your question differently from jfondren. You may be looking for a 'const' (or 'immutable') member: struct S { const int i; this(int i) { // This will work because "first assignment is initialization" this.i = i; } } void main() { auto s = S(42); // This won't work s.i = 43; // This won't work either s = S(44); } Ali Hello Again Ali, Excellent! I had tried (an erroneous) variant of this idea earlier ... but also failed with my attempt. I am appreciating very much the example you have provided. I will try this approach as well for the problem I am working on. (Some details on my path forward remain unclear ...) Best Regards, James
Re: Proper way to protect (lock) a struct field after initialization ??
On Sunday, 8 August 2021 at 10:19:46 UTC, jfondren wrote: On Sunday, 8 August 2021 at 10:11:37 UTC, james.p.leblanc wrote: Hello All. Is there a standard way to protect a field of a struct after the struct has been initialized? Is this possible with a struct? If not, I suppose a class (object) would be needed? If so, are there any simple pointers to an example of this? Thanks in advance, James `private` works for structs the same as it does for classes. https://dlang.org/spec/attribute.html#visibility_attributes Perhaps you tried it, realized you could still access it within the same module, and concluded that it didn't work? Consider note #2 at that link: "Symbols with private visibility can only be accessed from within the same module." Import the struct into another module and test the visibility there and you'll get the behavior you're looking for. Hej JFondren, Wow, thanks for the quick response. I had read that about the modules ... but as my test example had failed, I thought that I had misunderstood the larger picture. Based on you kind reply, I went back over my example and found that I had been deceiving myself. With a quick fix-up edit, it indeed is working as your explanation. Now, I proceed onto the trickier part of my endeavor ... Thanks again, and Best Regards, James (Sorry for the noise...)
Proper way to protect (lock) a struct field after initialization ??
Hello All. Is there a standard way to protect a field of a struct after the struct has been initialized? Is this possible with a struct? If not, I suppose a class (object) would be needed? If so, are there any simple pointers to an example of this? Thanks in advance, James
Re: Setting a hard limit on slice size, is this possible?
On Sunday, 8 August 2021 at 02:00:26 UTC, Tejas wrote: On Saturday, 7 August 2021 at 19:07:04 UTC, Paul Backus wrote: On Saturday, 7 August 2021 at 15:41:24 UTC, Tejas wrote: On Saturday, 7 August 2021 at 15:21:01 UTC, Paul Backus wrote: [...] Oh wow, and here I thought I was being smart :( So, how can we work around this without assembly language magic? I'm illiterate at assembly. For stack allocations, you can use the workaround in [Vladimir Panteleev's comment][1] (ignoring the ASM part, which is unrelated to alignment). For heap allocations, I guess the easiest way would be to use [`AlignedMallocator`][2] from `std.experimental.allocator`. [1]: https://issues.dlang.org/show_bug.cgi?id=16098#c3 [2]: https://phobos.dpldocs.info/std.experimental.allocator.mallocator.AlignedMallocator.html Cool... thanks Thanks to everyone for all of the great discussion and hints on this topic! I have learned quite much, and have a gained an understanding on how to use D effectively. Fantastic forum here on a great language. Best Regards, James
Re: Setting a hard limit on slice size, is this possible?
On Saturday, 7 August 2021 at 12:08:00 UTC, Paul Backus wrote: On Saturday, 7 August 2021 at 07:32:04 UTC, Tejas wrote: And if it really is correct, then it seems once again that static arrays are the answer after all: ```d align(your_alignment) int[your_length] array; ``` No need for structs \\('_')/ The main advantage of the struct is that you can heap-allocate it: ```d auto array = new Aligned!(int[4], 16); ``` **First, thanks all for helping with this question!** The simple desire to arbitrarily align an array is certainly looking non-trivial. Below is a simple program of both the suggested "struct" and "align array" solutions. Unfortunately, neither is guaranteed to place the array with the desired alignnment. import std.stdio; enum ALIGNMENT=64; enum LENGTH=10; struct Aligned(T, size_t alignment) if (alignment >= T.alignof) { align(alignment) T payload; alias payload this; } void main() { writeln("ALIGNMENT: ", ALIGNMENT, ",\t\tLENGTH: ", LENGTH); int[23] junk; align(ALIGNMENT) int[LENGTH] z; writeln("\nusing 'align(ALIGNMENT) int[LENGTH] z;'"); writeln("\ncast(ulong) z.ptr%ALIGNMENT: ", cast(ulong) z.ptr%ALIGNMENT); writeln("int.alignof: ", int.alignof, ",\tint.sizeof: ", int.sizeof); writeln("&z[0]", &z[0]); writeln("&z[1]", &z[1]); writeln("&z[2]", &z[2]); writeln("\nusing: 'Aligned!(int, ALIGNMENT)[LENGTH] x;'"); Aligned!(int, ALIGNMENT)[LENGTH] x; writeln("x.sizeof: ", x.sizeof, "\t\tx.alignof: ", x.alignof); writeln("x: ", x); writeln("\nx.ptr: ", x.ptr); writeln("&x[0]", &x[0]); writeln("&x[1]", &x[1]); writeln("&x[2]", &x[2]); writeln("\ncast(ulong) x.ptr%ALIGNMENT: ", cast(ulong) x.ptr%ALIGNMENT); } --- and here is a sample output of a run: ALIGNMENT: 64, LENGTH: 10 using 'align(ALIGNMENT) int[LENGTH] z;' cast(ulong) z.ptr%ALIGNMENT: ***32*** int.alignof: 4,int.sizeof: 4 &z[0]78D05B60 &z[1]78D05B64 &z[2]78D05B68 using: 'Aligned!(int, ALIGNMENT)[LENGTH] x;' x.sizeof: 640 x.alignof: 64 x: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] x.ptr: 78D05B90 &x[0]78D05B90 &x[1]78D05BD0 &x[2]78D05C10 cast(ulong) x.ptr%ALIGNMENT: ***16*** --- Notice, that neither attempt yields an array starting address as zero modulo the alignment value ... Also, a bit weird is that the "align array" solution yields expected spacing between array elements, but the "struct" solution has wider separations ... -- **Again, I am very appreciative of your replies and help with this.** I have learned quite a bit from this discussion. However, I remain a bit stumped by all of this Any ideas out there? Best Regards, James
Re: Setting a hard limit on slice size, is this possible?
mes On Friday, 6 August 2021 at 17:25:24 UTC, Tejas wrote: Okay we were overthinking the solution. Just use a static array ```d int[your_max_length]/*or whatever type*/ var; ``` You're good to go! I almost feel stupid now lol Hello Tejas, Kind thanks for your replies ... all are appreciated. However, do NOT feel stupid ... the motivation behind why I cannot use a standard int[your_max_length] (in other words, use a static array), is because I need to do a specified memory alignment (known at compile time) on my slice, or array. I understand that neither a slice or an array is capable to doing an arbitrary memory alignment. (But, perhaps I am wrong about this ...) I believe structs can be aligned, but need to learn more about the speicific of that. In the meantime, I have written a way to get an aligned slice from a static array. Ugly beginner code is below. While I believe this basic idea should work, I would like to guarantee that my slice does not get moved in memory (destroying the alignment). Ugly code here: -- import std.stdio; enum MAXLENGTH = 1024; enum ALIGN = 128; void main(){ // static array to allow creation of aligned slice ubyte[MAXLENGTH+ALIGN] u; writeln("u.ptr: ", u.ptr); auto u_i = cast(ulong) u.ptr; auto u_excess = u_i%ALIGN; writeln("u_excess: ", u_excess); ulong mustadd; if(u_excess !=0){ mustadd = ALIGN-u_excess; } writeln("mustadd: ", mustadd); // create aligned pointer for our needed slice auto zp = cast(double*) (u.ptr + mustadd); // create slice double[] z = zp[0 .. MAXLENGTH]; writeln("z.ptr: ", z.ptr); writeln("z.length: ", z.length); auto z_i = cast(ulong) z.ptr; auto z_excess = z_i%ALIGN; writeln("z_excess: ", z_excess); }
Re: Setting a hard limit on slice size, is this possible?
On Friday, 6 August 2021 at 11:58:59 UTC, Paul Backus wrote: struct MySlice(T, size_t maxLength) { private T[] payload; invariant(payload.length <= maxLength); this(T[] slice) { payload = slice; } T opIndex(size_t i) { return payload[i]; } // etc. } ``` Paul, Thanks very much for your reply. I understand only a fraction of the suggested solution. I will need to digest this a bit, and do some more background reading on templates. My initial, naive attempts to use this in a simple main() were unsuccessful. I'll keep plugging at it ... Best Regards, James
Setting a hard limit on slice size, is this possible?
I am aware of the "capacity" concept with slices. But, I would like to know if it is possible to set a hard limit on a slice size. I prefer it to error and crash instead of a doing an extension or reallocation. I understand my question screams of "convoluted thinking". But, I need to align my slice according to certain criteria. (Alternatively, I could use an array ... if I could align that according to criteria known at compile time. Is this possible?). I have a working solution (ugly trick, maybe is a better description) to align my slice as desired. But, the solution would be more robust if I could guarantee that the slice is never moved in memory. Any thoughts, hints, etc are welcome! James
Re: alias using Complex!Double in module ... linker error??
On Wednesday, 4 August 2021 at 01:10:15 UTC, Mike Parker wrote: On Tuesday, 3 August 2021 at 21:40:09 UTC, james.p.leblanc wrote: [...] The alias to Complex!double is a template instantiation. A template instantiation creates a symbol that needs to be linked. So you need to compile my_module.d along with my_main.d. ``` dmd my_main.d my_module.d ``` Or alternatively: ``` dmd -i my_main.d ``` double is a built-in type, so that alias doesn't create any symbols that need linking. An alias in and of itself is a compile-time-only construct, but the symbols you assign it might require linking something. Mike, Aha... that makes sense now! Thanks kindly for helping me understand what was happening with your informative reply. The fact of template instantiations and symbols had escaped me completely. I appreciate it. Best Regards, James
alias using Complex!Double in module ... linker error??
I am getting linker errors with this stripped-down example: --- **my_main.d:** import std.stdio; import std.complex; import my_module; void main(){ my_TYPE xxx; writeln(xxx); } --- **my_module.d:** module my_module; import std.complex; alias my_TYPE = Complex!double;*// this causes link error: "undefined reference"* /* alias my_TYPE = double; */ *// this works fine* -- Why does the linker fail when I alias to the Complex!double ... but would work fine when alias to the double ?? Any help to understand what is greatly appreciated. James
Re: align dynamic array (for avx friendliness) hints? / possible??
On Tuesday, 3 August 2021 at 17:57:47 UTC, Ali Çehreli wrote: On 8/3/21 10:50 AM, james.p.leblanc wrote: > **Is there some highly visible place this is already documented? For what it's worth, it appears as "slice from pointer" in my index: http://ddili.org/ders/d.en/pointers.html#ix_pointers.slice%20from%20pointer Admittedly, one needs to know the concept first to think about that entry. :/ Ali Ali, Thanks for your message! (And even a bigger thanks for writing your book!) Your book was one of the first D programming books I read, and learned much from it. At the time of my reading, I was too much of a new-comer to the D-language to see the importance of the "slice from pointer". This concept is a hidden gem of the language IMHO! But, with my recent needs to mix and match native D with the FFTW C-functions in an avx friendly alignment, I was really searching for a way to keep the "best of both worlds". The "slice from pointer" concepts is a valuable one. I need to go back and read that section of book now! Best Regards, James
Re: align dynamic array (for avx friendliness) hints? / possible??
On Tuesday, 3 August 2021 at 16:32:34 UTC, kinke wrote: On Tuesday, 3 August 2021 at 12:33:56 UTC, james.p.leblanc wrote: Concise question: = I would like to use dynamic arrays, not for their dynamic sizing properties per se' (slicing, appending, etc). But, more for their memory protection and efficiencies (for example,using foreach). However, I must have the start of my array at an avx friendly 32 byte alignment. Is this easily acheivable? Background: === I am interfacing with fftw. If I use the fftw_malloc, then I am forced to either: 1) copy to/from the allocated arrays to/from my "standard" dlang dynamic arrays (loss of efficiency). or ... 2) use standard array/pointer mechanisms everywhere(loss of memory safely). My thinking is that I could forego the use of the fftw_malloc, and simply hand fftw functions my (properly aligned) pointer of my dlang dynamic array. All thoughts, comments, hints, greatly appreciated! James AFAIK, the GC only guarantees an alignment of 16. But you can turn any memory allocation into a slice, simply via ``` size_t length = ...; T* myPtr = cast(T*) fftw_malloc(length * T.sizeof); // or aligned_alloc, posix_memalign etc. T[] mySlice = myPtr[0 .. length]; foreach (ref e; mySlice) ... // free! ``` Dear Kinke, THANKS IMMENSELY! - This is exactly the kind of solution that I was hoping would be possible (elegant, simply, and clear). This really is the perfect solution, and opens up many possibilities for me. (Perhaps I had been using the wrong search terms, or perhaps everyone already knows how to use this "conversion of C arrays/pointers to D slices" solution... but I was stumped!) Again, thanks kindly **Is there some highly visible place this is already documented? If not, it would make a great blog post as it would be beneficial to any D newcomers bridging C/D and needing AVX alignments, etc.** Best Regards, James
align dynamic array (for avx friendliness) hints? / possible??
Concise question: = I would like to use dynamic arrays, not for their dynamic sizing properties per se' (slicing, appending, etc). But, more for their memory protection and efficiencies (for example,using foreach). However, I must have the start of my array at an avx friendly 32 byte alignment. Is this easily acheivable? Background: === I am interfacing with fftw. If I use the fftw_malloc, then I am forced to either: 1) copy to/from the allocated arrays to/from my "standard" dlang dynamic arrays (loss of efficiency). or ... 2) use standard array/pointer mechanisms everywhere(loss of memory safely). My thinking is that I could forego the use of the fftw_malloc, and simply hand fftw functions my (properly aligned) pointer of my dlang dynamic array. All thoughts, comments, hints, greatly appreciated! James
Initializing a complex dynamic array (with real part from one array, and imaginary from other array)?
I am trying to initialize a complex dynamic array, from two strictly real dynamic arrays (one to be the real part, the other to be the imaginary part. Here is simple sample of what I have tried: - import std.stdio; import std.math; import std.complex; void main(){ auto N=2; double[] x,y; x.length = N; y.length = N; x[0] = 1.1; x[1] = 2.2; y[0] = 3.3; y[1] = 4.4; Complex!double[] z; z.length=N; z[] = complex(x[],y[]); // z = complex(x,y); // also tried this, did not work } - The compile error message is: rdmd post.d post.d(22): Error: template `std.complex.complex` cannot deduce function from argument types `!()(double[], double[])`, candidates are: /home/leblanc/dmd2/linux/bin64/../../src/phobos/std/complex.d(46):`complex(R)(const R re)` /home/leblanc/dmd2/linux/bin64/../../src/phobos/std/complex.d(56):`complex(R, I)(const R re, const I im)` with `R = double[], I = double[]` whose parameters have the following constraints: `` ` > is(R : double) - is(I : double) ` `` post.d(22):All possible candidates are marked as `deprecated` or `@disable` Tip: not satisfied constraints are marked with `>` Failed: ["/home/leblanc/dmd2/linux/bin64/dmd", "-v", "-o-", "post.d", "-I."] --- I understand, I could write a simple function to do this...but was wondering if there is some "standard" way of doing this already? Thanks, James PS Is cdouble (and friends) really going to be deprecated?? I worry that the loss of the built-in complex types eventually might have a downside for syntax and writing. (But, I might very well be wrong about this!!).