Re: Template shenannigans with multiple datatypes
On Friday, 13 May 2022 at 13:06:32 UTC, vit wrote: On Friday, 13 May 2022 at 11:58:15 UTC, zjh wrote: Thank you for your detail explain.
Re: Template shenannigans with multiple datatypes
On 5/13/22 00:32, Chris Katko wrote: > Luckily, because I'm painting them to the screen, the > buffers only really need to be float even if they started as a boolean, > int, or double. However, if I'm keeping a list of pointers to things I > want to snoop when I call onTick(), I can't think of a way to support > multiple types: I think this is a classic example of OOP. You abstract data collection to classes that know how to deal with their own data type. The comments should explain it: import std.algorithm; import std.conv; import std.range; import std.random; import std.stdio; interface DataSource { // Represents "reporting" of data points to the graph. float[] dataPoints(); // Represents a collection of data. void collect(); } // A templatized implementation of DataSource that would // work with fundamental types like 'int'. class SimpleDataSource(T) : DataSource { T[] data;// All collected data size_t next; // The beginning of data for next dataPoints() // Converts data to float[], the uniform representation. float[] dataPoints() { auto result = data[next..$].map!(to!float).array; next = data.length; return result; } void collect() { // Random number of random values const n = uniform(3, 10); iota(n).each!(i => data ~= uniform(10, 20)); } } // Converted to a 'struct'. Could stay 'class'. struct intrinsicGraph { DataSource[] dataSources; // Same type collectors float[] buffer;// Same type data void onTick() { // Go through all sources to update 'buffer'. dataSources.each!(source => buffer ~= source.dataPoints()); } } void main() { // Independent collectors. auto source1 = new SimpleDataSource!int(); auto source2 = new SimpleDataSource!double(); auto g = intrinsicGraph(); // This part is the "registration" of data sources, // which could be like g.register(source1). g.dataSources ~= source1; g.dataSources ~= source2; // Represents a time slice. foreach (i; 0 .. 3) { source1.collect(); source2.collect(); g.onTick(); } // It works! :) writeln(g.buffer); } Ali
Re: Template shenannigans with multiple datatypes
On Friday, 13 May 2022 at 07:32:16 UTC, Chris Katko wrote: This is a kinda "dynamic language" feature but it feels like this information is theoretically, knowable at static, compile-time. I know what the variable types will be at compile-time, but I don't know how to put them all in one class and reference them automatically. Like `std.json.JSONValue` or `std.variant.Variant` you can also use a struct with a type flag and possible data types that fit for you. Boolean and Integer may share the same memory location via `union` for example. Or just use the built one `Variant` type. In case you only store the pointers to the data, you just need `void*[]` and proper casting.
Re: Template shenannigans with multiple datatypes
On Friday, 13 May 2022 at 11:58:15 UTC, zjh wrote: On Friday, 13 May 2022 at 08:28:56 UTC, vit wrote: ... ```d ... this(DataSources dataSources){ this.dataSources = dataSources; } ... return new MultiGraph!(staticMap!(PointerTarget, Ts))(ts);//ts ``` How is `ts` convert to `DataSources`? `ts` have same type like `DataSources`: ```d import std.meta : staticMap, allSatisfy; import std.traits : PointerTarget, isPointer; import std.conv : to; alias Pointer(T) = T*; class MultiGraph(Ts...){// Ts == (float, double, int) alias DataSources = staticMap!(Pointer, Ts); // (float, double, int) -> (float*, double*, int*) DataSources dataSources;// -> (float*, double*, int*) float[][DataSources.length] buffers;// -> float[][3] this(DataSources dataSources){ // dataSources == (float*, double*, int*) this.dataSources = dataSources; } void onTick() { //grab datasource data and do something. foreach(enum i, alias d; dataSources) buffers[i] ~= to!float(*d); //or whatever } } auto multiGraph(Ts...)(Ts ts) // Ts == (float*, double*, int*) if(allSatisfy!(isPointer, Ts)){ //all types in Ts are pointers alias DataSources = staticMap!(PointerTarget, Ts); // (float*, double*, int*) -> (float, double, int) return new MultiGraph!(DataSources)(ts); } void main(){ float myFloat; double myDouble; int myInteger; auto g = multiGraph(, , ); } ```
Re: Template shenannigans with multiple datatypes
On Friday, 13 May 2022 at 08:28:56 UTC, vit wrote: ... ```d ... this(DataSources dataSources){ this.dataSources = dataSources; } ... return new MultiGraph!(staticMap!(PointerTarget, Ts))(ts);//ts ``` How is `ts` convert to `DataSources`?
Re: Template shenannigans with multiple datatypes
On Friday, 13 May 2022 at 07:32:16 UTC, Chris Katko wrote: On Friday, 13 May 2022 at 07:05:36 UTC, vit wrote: On Friday, 13 May 2022 at 06:43:39 UTC, Chris Katko wrote: I have an intrinsicGraph(T) class that is given a pointer to a T dataSource and automatically polls that variable every frame to add it to the graph, whether it's a float, double, integer, and maybe bool. [...] I dont understand first qestion but second question has a solution: ```d intrinsic_graph!T make_graph(T, Args...)(auto ref T val, auto ref Args args){ return new intrinsic_graph!T(val, args); } instrinsicGraph!float testGraph; instrinsicGraph!ulong testGraph2; // later testGraph = make_graph(units[0].x, 100, 300, COLOR(1,0,0,1)); testGraph2 = make_graph(g.stats.fps, 100, 500, COLOR(1,0,0,1)); ``` Okay, to clarify just in case I'm very confusing because I'm up late. If I wanted a "multipleGraph". A graph that takes multiple values and plots them on the same graph. I need to store a buffer for each dataSource. Luckily, because I'm painting them to the screen, the buffers only really need to be float even if they started as a boolean, int, or double. However, if I'm keeping a list of pointers to things I want to snoop when I call onTick(), I can't think of a way to support multiple types: ```D class intrinsicGraph(T) { T* dataSource; float[] buffer; void onTick() { //grab datasource data and do something. buffer ~= to!float(*datasource); } } auto g = intrinsicGraph!float(); ``` But what if there's multiple types? ```D class multiGraph(???) { ???[] dataSources; float[] buffers; void onTick() { //grab datasource data and do something. foreach(d, i; dataSources) buffers[i] ~= to!float(*d); //or whatever } } auto g = multiGraph!???(, , ); ``` This is a kinda "dynamic language" feature but it feels like this information is theoretically, knowable at static, compile-time. I know what the variable types will be at compile-time, but I don't know how to put them all in one class and reference them automatically. Try variadic templates: ```d import std.meta : staticMap, allSatisfy; import std.traits : PointerTarget, isPointer; import std.conv : to; alias Pointer(T) = T*; class MultiGraph(Ts...){ alias DataSources = staticMap!(Pointer, Ts); DataSources dataSources; float[][DataSources.length] buffers; this(DataSources dataSources){ this.dataSources = dataSources; } void onTick() { //grab datasource data and do something. foreach(enum i, ref d; dataSources) buffers[i] ~= to!float(*d); //or whatever } } auto multiGraph(Ts...)(Ts ts) if(allSatisfy!(isPointer, Ts)){ return new MultiGraph!(staticMap!(PointerTarget, Ts))(ts); } void main(){ float myFloat; double myDouble; int myInteger; auto g = multiGraph(, , ); } ```
Re: Template shenannigans with multiple datatypes
On Friday, 13 May 2022 at 07:05:36 UTC, vit wrote: On Friday, 13 May 2022 at 06:43:39 UTC, Chris Katko wrote: I have an intrinsicGraph(T) class that is given a pointer to a T dataSource and automatically polls that variable every frame to add it to the graph, whether it's a float, double, integer, and maybe bool. [...] I dont understand first qestion but second question has a solution: ```d intrinsic_graph!T make_graph(T, Args...)(auto ref T val, auto ref Args args){ return new intrinsic_graph!T(val, args); } instrinsicGraph!float testGraph; instrinsicGraph!ulong testGraph2; // later testGraph = make_graph(units[0].x, 100, 300, COLOR(1,0,0,1)); testGraph2 = make_graph(g.stats.fps, 100, 500, COLOR(1,0,0,1)); ``` Okay, to clarify just in case I'm very confusing because I'm up late. If I wanted a "multipleGraph". A graph that takes multiple values and plots them on the same graph. I need to store a buffer for each dataSource. Luckily, because I'm painting them to the screen, the buffers only really need to be float even if they started as a boolean, int, or double. However, if I'm keeping a list of pointers to things I want to snoop when I call onTick(), I can't think of a way to support multiple types: ```D class intrinsicGraph(T) { T* dataSource; float[] buffer; void onTick() { //grab datasource data and do something. buffer ~= to!float(*datasource); } } auto g = intrinsicGraph!float(); ``` But what if there's multiple types? ```D class multiGraph(???) { ???[] dataSources; float[] buffers; void onTick() { //grab datasource data and do something. foreach(d, i; dataSources) buffers[i] ~= to!float(*d); //or whatever } } auto g = multiGraph!???(, , ); ``` This is a kinda "dynamic language" feature but it feels like this information is theoretically, knowable at static, compile-time. I know what the variable types will be at compile-time, but I don't know how to put them all in one class and reference them automatically.
Re: Template shenannigans with multiple datatypes
On Friday, 13 May 2022 at 06:43:39 UTC, Chris Katko wrote: I have an intrinsicGraph(T) class that is given a pointer to a T dataSource and automatically polls that variable every frame to add it to the graph, whether it's a float, double, integer, and maybe bool. [...] I dont understand first qestion but second question has a solution: ```d intrinsic_graph!T make_graph(T, Args...)(auto ref T val, auto ref Args args){ return new intrinsic_graph!T(val, args); } instrinsicGraph!float testGraph; instrinsicGraph!ulong testGraph2; // later testGraph = make_graph(units[0].x, 100, 300, COLOR(1,0,0,1)); testGraph2 = make_graph(g.stats.fps, 100, 500, COLOR(1,0,0,1)); ```