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


```


Template shenannigans with multiple datatypes

2022-05-13 Thread Chris Katko via Digitalmars-d-learn
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.


This all works fine if you have a single template type. But what 
if I want ... multiple graphs? I cannot do

D
class intrinsicGraph(T???)
{
(void*) dataSources[];
}

and have it become whatever datatype I want. Even if I'm always 
storing the values in a float buffer, the dataSources themselves 
cannot be multiple types.


Basically I'm wondering if there's a way to have
D
int FPS;
float frameTime;
//
graph myGraph;
myGraph.add();
myGraph.add();

and it enumerates through its dataSources array and adds to the 
relevant buffers.


There is a key that might help, they're all types that can 
resolve to integer or float. I'm not trying to add support for 
adding myRandomClass or networkPacket. Only things that can 
resolve down to float in some form.


Is there some kind of clue in having an array of Object (the 
fundamental superclass?)?


I don't think this is necessarily a "run time" reflection 
problem. Because I could make a graph at compile time, and know 
its of type, say, (T V U). Say, float, double, uint. Some sort of 
vardiac template.


But then how would you store that, unless you use some sort of 
mixins to write separate variables. (float\* dataSource0 and 
double\* dataSource1)


Or, wrap each pointer in some sort of fat pointer class that 
stores the type and a void*, and have an array of those fat 
pointers and and use some compile time voodoo to cast back  
cast(float)dataSource[0] (zero is always float), 
cast(uint)dataSource[2] (index 2 has cast(uint) put in).


Additional questions:

This may sound strange but is there a way to avoid having to 
specify the template type twice?

```D
instrinsicGraph!float testGraph;
instrinsicGraph!ulong testGraph2;
// later
testGraph = new intrinsic_graph!float(units[0].x, 100, 300, 
COLOR(1,0,0,1));
testGraph2 = new intrinsic_graph!ulong(g.stats.fps, 100, 500, 
COLOR(1,0,0,1));

```
It'd be nice if I only had to specify the type once.

It'd also be kinda nice if I could hide the fact I need to 
specify the type at all and have it automatically become whatever 
type the passed in value is:


D
instrinsicGraph testGraph(g.stats.fps) //automatically stores an 
integer buffer.