Re: Template shenannigans with multiple datatypes

2022-05-13 Thread zjh via Digitalmars-d-learn

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

2022-05-13 Thread Ali Çehreli via Digitalmars-d-learn

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

2022-05-13 Thread frame via Digitalmars-d-learn

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

2022-05-13 Thread vit via Digitalmars-d-learn

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

2022-05-13 Thread zjh via Digitalmars-d-learn

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

2022-05-13 Thread vit via Digitalmars-d-learn

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

2022-05-13 Thread Chris Katko via Digitalmars-d-learn

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

2022-05-13 Thread vit via Digitalmars-d-learn

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));


```