www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - runtime numeric conversions

reply "Ben Hinkle" <bhinkle mathworks.com> writes:
Does anyone have a nice solution to the following problem? I have a TypeInfo 
ti from a vararg function and I have a template parameter type T and if T is 
a numeric type I want to allow the vararg parameter to be any numeric type 
that is convertable to T. The code I have so far looks pretty ugly and I 
have a feeling there is something nicer possible. I can't just do
T val;
if (ti is typeid(bit)) val = cast(T)va_arg!(bit)(_argptr);
else if (ti is typeid(byte)) val = cast(T)va_arg!(byte)(_argptr);
etc etc
since T might not be an integer type (eg char[]) and so I'd have to hide 
this stuff behind template specialization or something. Is there a standard 
way to do this? The solution above is very verbose.

-Ben 
May 05 2005
next sibling parent reply Sean Kelly <sean f4.ca> writes:
In article <d5drqh$1ovs$1 digitaldaemon.com>, Ben Hinkle says...
Does anyone have a nice solution to the following problem? I have a TypeInfo 
ti from a vararg function and I have a template parameter type T and if T is 
a numeric type I want to allow the vararg parameter to be any numeric type 
that is convertable to T. The code I have so far looks pretty ugly and I 
have a feeling there is something nicer possible. I can't just do
T val;
if (ti is typeid(bit)) val = cast(T)va_arg!(bit)(_argptr);
else if (ti is typeid(byte)) val = cast(T)va_arg!(byte)(_argptr);
etc etc
since T might not be an integer type (eg char[]) and so I'd have to hide 
this stuff behind template specialization or something. Is there a standard 
way to do this? The solution above is very verbose.

Either way, you're stuck checking the source type at run time, but I suppose that's bearable. You could speed that bit up using the process in std.doFormat, but that may be non-portable. I haven't done anything like this yet in D, but you could probably abstract the checking of type T like this: template isNumeric(T) { bit isNumeric = false; } template isNumeric(T:int) { bit isNumeric = true; } .. template assignIf(bit val) { bit assignIf(inout T val, TypeInfo ti, void* argptr) { if (ti is typeid(bit)) val = cast(T)va_arg!(bit)(_argptr); .. else return false; return true; } } template assignIf(bit val: false) { bit assignIf(inout T val, Typeinfo ti, void* argptr) { return false; } } .. if(assignIf!(isNumeric!(T))(val, ti, _argptr)) printf( "types match\n"); Sean
May 05 2005
parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
"Sean Kelly" <sean f4.ca> wrote in message 
news:d5dtri$1qr7$1 digitaldaemon.com...
 In article <d5drqh$1ovs$1 digitaldaemon.com>, Ben Hinkle says...
Does anyone have a nice solution to the following problem? I have a 
TypeInfo
ti from a vararg function and I have a template parameter type T and if T 
is
a numeric type I want to allow the vararg parameter to be any numeric type
that is convertable to T. The code I have so far looks pretty ugly and I
have a feeling there is something nicer possible. I can't just do
T val;
if (ti is typeid(bit)) val = cast(T)va_arg!(bit)(_argptr);
else if (ti is typeid(byte)) val = cast(T)va_arg!(byte)(_argptr);
etc etc
since T might not be an integer type (eg char[]) and so I'd have to hide
this stuff behind template specialization or something. Is there a 
standard
way to do this? The solution above is very verbose.

Either way, you're stuck checking the source type at run time, but I suppose that's bearable. You could speed that bit up using the process in std.doFormat, but that may be non-portable.

I don't get the doFormat suggestion - can you elaborate? Some more context of my problem: I'm updating MinTL and I'd like to add support to the add(...) function to allow values that are convertable to the container value type instead of just erroring like it does now. So my container value type is T and the argument to add(...) is the TypeInfo.
 I haven't done anything like this yet in D, but you could probably 
 abstract the
 checking of type T like this:

 template isNumeric(T) { bit isNumeric = false; }
 template isNumeric(T:int) { bit isNumeric = true; }
 ..
 template assignIf(bit val) {
 bit assignIf(inout T val, TypeInfo ti, void* argptr) {
 if (ti is typeid(bit)) val = cast(T)va_arg!(bit)(_argptr);
 ..
 else return false;
 return true;
 }
 }
 template assignIf(bit val: false) {
 bit assignIf(inout T val, Typeinfo ti, void* argptr) {
 return false;
 }
 }
 ..
 if(assignIf!(isNumeric!(T))(val, ti, _argptr)) printf( "types match\n");

That's pretty verbose, too. I'd have to define an assignIf for each numeric type, correct? Maybe I'll cut down on the permutations by just casting all int types to long or ulong and then down to T and float types to real and then down to T. That way I don't have to write templates to directly cast, say, a byte to a short.
May 05 2005
next sibling parent reply Sean Kelly <sean f4.ca> writes:
In article <d5e1us$1us6$1 digitaldaemon.com>, Ben Hinkle says...
 Either way, you're stuck checking the source type at run time, but I 
 suppose
 that's bearable.  You could speed that bit up using the process in 
 std.doFormat,
 but that may be non-portable.

I don't get the doFormat suggestion - can you elaborate?

doFormat uses what is basically a big switch statement on a character in the classinfo string, so determining the type from TypeInfo is more like an O(1) operation than an O(N) operation. I want to use this same method for unFormat, but pointer types still don't generate the correct classinfo data. I say it's non-portable because I haven't seen anything in the spec about a required format for this string, though it may well be added later.
Some more context 
of my problem: I'm updating MinTL and I'd like to add support to the 
add(...) function to allow values that are convertable to the container 
value type instead of just erroring like it does now. So my container value 
type is T and the argument to add(...) is the TypeInfo.

 I haven't done anything like this yet in D, but you could probably 
 abstract the
 checking of type T like this:

 template isNumeric(T) { bit isNumeric = false; }
 template isNumeric(T:int) { bit isNumeric = true; }
 ..
 template assignIf(bit val) {
 bit assignIf(inout T val, TypeInfo ti, void* argptr) {
 if (ti is typeid(bit)) val = cast(T)va_arg!(bit)(_argptr);
 ..
 else return false;
 return true;
 }
 }
 template assignIf(bit val: false) {
 bit assignIf(inout T val, Typeinfo ti, void* argptr) {
 return false;
 }
 }
 ..
 if(assignIf!(isNumeric!(T))(val, ti, _argptr)) printf( "types match\n");

That's pretty verbose, too. I'd have to define an assignIf for each numeric type, correct? Maybe I'll cut down on the permutations by just casting all int types to long or ulong and then down to T and float types to real and then down to T. That way I don't have to write templates to directly cast, say, a byte to a short.

Good question. The syntax of assignIf is pretty generic--it just casts a value of one type to another type. Assuming you want to cast any numeric value passed to add(...) to the numeric type of your array then the above code should do it. But if this array may contain values other than primitive numeric types or if you want to convert from such data, then the problem becomes more complicated. It might be simpler to just overload add() for all the types you care about, perhaps using a mixin to avoid code duplication. Sadly, this is a place where template member functions and implicit template instantiation is ideal. Doing this explicitly doesn't require a terrible amount of code however: class Array(T) { private: template add_(U){ void add_(U u) { foreach(inout T t; m_data) t+= u; } } public: alias add_!(byte) add; alias add_!(int) add; alias add_!(long) add; private: T[] m_data; }
May 05 2005
parent "Ben Hinkle" <ben.hinkle gmail.com> writes:
 I haven't done anything like this yet in D, but you could probably
 abstract the
 checking of type T like this:

 template isNumeric(T) { bit isNumeric = false; }
 template isNumeric(T:int) { bit isNumeric = true; }
 ..
 template assignIf(bit val) {
 bit assignIf(inout T val, TypeInfo ti, void* argptr) {
 if (ti is typeid(bit)) val = cast(T)va_arg!(bit)(_argptr);
 ..
 else return false;
 return true;
 }
 }
 template assignIf(bit val: false) {
 bit assignIf(inout T val, Typeinfo ti, void* argptr) {
 return false;
 }
 }
 ..
 if(assignIf!(isNumeric!(T))(val, ti, _argptr)) printf( "types match\n");

That's pretty verbose, too. I'd have to define an assignIf for each numeric type, correct? Maybe I'll cut down on the permutations by just casting all int types to long or ulong and then down to T and float types to real and then down to T. That way I don't have to write templates to directly cast, say, a byte to a short.

Good question. The syntax of assignIf is pretty generic--it just casts a value of one type to another type. Assuming you want to cast any numeric value passed to add(...) to the numeric type of your array then the above code should do it. But if this array may contain values other than primitive numeric types or if you want to convert from such data, then the problem becomes more complicated. It might be simpler to just overload add() for all the types you care about, perhaps using a mixin to avoid code duplication. Sadly, this is a place where template member functions and implicit template instantiation is ideal. Doing this explicitly doesn't require a terrible amount of code however: class Array(T) { private: template add_(U){ void add_(U u) { foreach(inout T t; m_data) t+= u; } } public: alias add_!(byte) add; alias add_!(int) add; alias add_!(long) add; private: T[] m_data; }

I've decided to only convert ints automatically so I've settled with: // define some templates to convert int to T if possible template MNumCls(T) {bit cls = false;T numcast(int x) {return T.init;}} template MNumCls(T:bit) {bit cls = true;T numcast(int x) {return x;}} template MNumCls(T:byte) {bit cls = true;T numcast(int x) {return x;}} template MNumCls(T:short) {bit cls = true;T numcast(int x) {return x;}} template MNumCls(T:int) {bit cls = true;T numcast(int x) {return x;}} template MNumCls(T:long) {bit cls = true;T numcast(int x) {return x;}} template MNumCls(T:ubyte) {bit cls = true;T numcast(int x) {return x;}} template MNumCls(T:ushort) {bit cls = true;T numcast(int x) {return x;}} template MNumCls(T:uint) {bit cls = true;T numcast(int x) {return x;}} template MNumCls(T:ulong) {bit cls = true;T numcast(int x) {return x;}} template MNumCls(T:float) {bit cls = true;T numcast(int x) {return x;}} template MNumCls(T:double) {bit cls = true;T numcast(int x) {return x;}} template MNumCls(T:real) {bit cls = true;T numcast(int x) {return x;}} void add(...) { va_list argptr = cast(va_list)_argptr; for (int k=0;k<_arguments.length;k++) { TypeInfo tiv = typeid(Value); TypeInfo tik = _arguments[k]; if (tik == tiv) { addTail(va_arg!(Value)(argptr)); } else if (tik == typeid(int) && MNumCls!(Value).cls) { addTail(MNumCls!(Value).numcast(va_arg!(int)(argptr))); } else { throw new Exception("Illegal item in mintl.share.add"); } } }
May 05 2005
prev sibling parent Sean Kelly <sean f4.ca> writes:
In article <d5e1us$1us6$1 digitaldaemon.com>, Ben Hinkle says...
That's pretty verbose, too. I'd have to define an assignIf for each numeric 
type, correct? Maybe I'll cut down on the permutations by just casting all 
int types to long or ulong and then down to T and float types to real and 
then down to T. That way I don't have to write templates to directly cast, 
say, a byte to a short. 

I gave this some thought and came up with a generic solution to the problem. This code is incomplete, as I wrote it on my commute home today, but it outlines a workable approach to the problem. Basically, you would define groups of types that you considered covertible between one another--you might want to create relatively specific lists such as IntegerTypes and FloatingTypes, or you might want to just define one big NumericTypes lists. This approach should work for any combination of types if you're willing to write a bit more generator code to handle the conversions. So far, I've only written the code to expand function definitions into a scope. The next step will be to write something that finds which type list T is in and generates functions for that list. struct Empty { } template TypeList( HeadType, TailType ) { struct TypeList { HeadType Head; TailType Tail; } } alias TypeList!(int,TypeList!(long,Empty)) Integers; alias TypeList!(float,TypeList!(double,Empty)) Floats; class Array1( T ) { template expandAdd( TL ) { void add( typeof( TL.Head ) val ) { // this is broken // //alias typeof( TL.Head ) type; //printf( "%.*s\n", typeid( type ).toString() ); } mixin expandAdd!( typeof( TL.Tail ) ); } template expandAdd( TL : Empty ) { } mixin expandAdd!( Integers ); } void main() { Array1!(int) a1 = new Array1!(int)(); a1.add(cast(int)1); a1.add(cast(long)1); a1.add(cast(ubyte)1); } Now the above code could definately be improved, but doing so is currently difficult without generating a compile error. I think this reflects compiler bugs and not language issues, but even so... I'm trying to get something like the following working so you don't need to define your function so oddly, but so far this won't compile: template expand1( alias Fn, TL ) { mixin Fn!( typeof( TL.Head ) ); mixin .expand1!( typeof( TL.Tail ) ); } template expand1( Fn, TL : Empty ) { } class Array2( T ) { template add( T ) { void add( T val ) { } } mixin expand1!( add, Integers ); } So far, I haven't found a syntax for passing a function (Fn) that DMD likes. An alias doesn't work either, nor does changing 'add' to a class. Also, I don't think typeof should be necessary where it's used, but it is :p I'll keep playing with this and probably file some bug reports, but I think the general approach is sound. And this is much easier to do than expanding through inheritance as you would with C++. Sean
May 05 2005
prev sibling next sibling parent "Andrew Fedoniouk" <news terrainformatica.com> writes:
The best thing is to extend TypeInfo by members

class TypeInfo
{
    uint getHash(void *p);
    int equals(void *p1, void *p2);
    int compare(void *p1, void *p2);
    int tsize();
    void swap(void *p1, void *p2);

    // toPrimitive members
    bool toString(void* p, out char[] s);
    bool toInteger(void* p, out long number);
    bool toReal(void* p, out real number);
}

Having this you may write something like this:

template toNumeric(NT)
{
   NT cvt(void *p,out )
   {
       long n;
       typeid(NT).toInteger(p,n);
       return cast(NT)n;
    }
}

int val = toNumeric(int).cvt( argptr );


In any case having toPrimitive feature in D whould be nice.

Andrew.


"Ben Hinkle" <bhinkle mathworks.com> wrote in message 
news:d5drqh$1ovs$1 digitaldaemon.com...
 Does anyone have a nice solution to the following problem? I have a 
 TypeInfo ti from a vararg function and I have a template parameter type T 
 and if T is a numeric type I want to allow the vararg parameter to be any 
 numeric type that is convertable to T. The code I have so far looks pretty 
 ugly and I have a feeling there is something nicer possible. I can't just 
 do
 T val;
 if (ti is typeid(bit)) val = cast(T)va_arg!(bit)(_argptr);
 else if (ti is typeid(byte)) val = cast(T)va_arg!(byte)(_argptr);
 etc etc
 since T might not be an integer type (eg char[]) and so I'd have to hide 
 this stuff behind template specialization or something. Is there a 
 standard way to do this? The solution above is very verbose.

 -Ben
 

May 05 2005
prev sibling parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
I guess this is what you are looking for:

-----------------------
void write(...)
{
 for (int i = 0; i < _arguments.length; )
{
  TypeInfo ti = _arguments[i++];

    int v = 0;
          Cast!(int, TL!(uint,int,char,wchar,bit) )(ti, _argptr, v);
    char c = 0;
          Cast!(char, TL!(uint,int,char,wchar,bit) )(ti, _argptr, c);

    writef("int=%d char=%d\n", v,c);

    _argptr = _argptr + ((ti.tsize + int.sizeof - 1) & ~(int.sizeof - 1));
  }
}

void main()
{
    write(  'a', 1, 12.34,  "hello world" );
}

---------------
Will output :

int=0 char=97
int=1 char=0
int=0 char=0
int=0 char=0



-- full source : -------------------------------------------

import Thor.typelist;
import Thor.meta;
import std.stdio;

template Cast(TDST, TL_ : TypeList)
{
    void Cast(TypeInfo ti, void *p,inout TDST v)
    {
        if(typeid(TDST) is ti)
           v = *cast(TDST*)p;
        else
          .Cast!(TDST,TL_.T)(ti,p,v);
    }
}

template Cast(TDST, T : NullT) // ground
{
    void Cast(TypeInfo ti, void *p,inout TDST v) { }
}

void write(...)
{
 for (int i = 0; i < _arguments.length; )
    {
  TypeInfo ti = _arguments[i++];

  int v = 0;
  char c = 0;
  Cast!(int, TL!(uint,int,char,wchar,bit) )(ti, _argptr, v);
  Cast!(char, TL!(uint,int,char,wchar,bit) )(ti, _argptr, c);

  writef("int=%d char=%d\n", v,c);

  _argptr = _argptr + ((ti.tsize + int.sizeof - 1) & ~(int.sizeof - 1));
  }
}

void main()
{
    write('a',1,12.34, "hello world");
}



"Ben Hinkle" <bhinkle mathworks.com> wrote in message 
news:d5drqh$1ovs$1 digitaldaemon.com...
 Does anyone have a nice solution to the following problem? I have a 
 TypeInfo ti from a vararg function and I have a template parameter type T 
 and if T is a numeric type I want to allow the vararg parameter to be any 
 numeric type that is convertable to T. The code I have so far looks pretty 
 ugly and I have a feeling there is something nicer possible. I can't just 
 do
 T val;
 if (ti is typeid(bit)) val = cast(T)va_arg!(bit)(_argptr);
 else if (ti is typeid(byte)) val = cast(T)va_arg!(byte)(_argptr);
 etc etc
 since T might not be an integer type (eg char[]) and so I'd have to hide 
 this stuff behind template specialization or something. Is there a 
 standard way to do this? The solution above is very verbose.

 -Ben
 

May 05 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
oops, forgot to include link to the Thor library
(meta.d, traits.d, typelist.d)

http://rsdn.ru/File/28948/Thor.zip

Author nickname is 'uv' on RSDN (Russian Software Developers Network).
This is everything what I know about him so far.
His statement was:
"В качестве proof-of-concept я как-то давно реализовывал шаблоны для работы 
со списками типов на D"
(Long ago I implemented templates for dealing with typelists in D as a 
proof-of-concept, here is a link...)

Andrew. 
May 05 2005
parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
Nice stuff - thanks. Plus the code is public domain just like MinTL so I can 
use it (hooray). Since MinTL is a "template library" it wouldn't be out of 
place to document it as part of the library (with proper credit of course).

"Andrew Fedoniouk" <news terrainformatica.com> wrote in message 
news:d5et8h$2lgq$1 digitaldaemon.com...
 oops, forgot to include link to the Thor library
 (meta.d, traits.d, typelist.d)

 http://rsdn.ru/File/28948/Thor.zip

 Author nickname is 'uv' on RSDN (Russian Software Developers Network).
 This is everything what I know about him so far.
 His statement was:
 "В качестве proof-of-concept я как-то давно реализовывал шаблоны для 
 работы со списками типов на D"
 (Long ago I implemented templates for dealing with typelists in D as a 
 proof-of-concept, here is a link...)

 Andrew.
 

May 06 2005
parent reply "Andrew Fedoniouk" <news terrainformatica.com> writes:
Ben, I've got a response from the author of the Thor -
Aleksey Bobnev <aleksey.bobnev gmail.com>

Attached are his updated sources.
If Thor will be included in MinTL he is willing
to update style of comments to make them
consistent with MinTL.

Andrew.
http://terrainformatica.com



"Ben Hinkle" <ben.hinkle gmail.com> wrote in message 
news:d5fmpg$dm5$1 digitaldaemon.com...
 Nice stuff - thanks. Plus the code is public domain just like MinTL so I 
 can
 use it (hooray). Since MinTL is a "template library" it wouldn't be out of
 place to document it as part of the library (with proper credit of 
 course).

 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:d5et8h$2lgq$1 digitaldaemon.com...
 oops, forgot to include link to the Thor library
 (meta.d, traits.d, typelist.d)

 http://rsdn.ru/File/28948/Thor.zip

 Author nickname is 'uv' on RSDN (Russian Software Developers Network).
 This is everything what I know about him so far.
 His statement was:
 "В качестве proof-of-concept я как-то давно реализовывал шаблоны для
 работы со списками типов на D"
 (Long ago I implemented templates for dealing with typelists in D as a
 proof-of-concept, here is a link...)

 Andrew.


May 08 2005
parent "Ben Hinkle" <ben.hinkle gmail.com> writes:
Thanks. Since Burton's box code does numeric conversions I've switched to 
using that. So I technically don't need the TypeList stuff for MinTL 
anymore. It's very tempting to include it but I'd like to see where Walter 
goes with the template stuff. I have a feeling he will eventually look for a 
better meta-programming style than TypeLists etc. I have no idea what such a 
feature would look like but who knows. I'll keep Thor around - and Aleksey's 
contact info.

"Andrew Fedoniouk" <news terrainformatica.com> wrote in message 
news:d5mdli$2qmv$1 digitaldaemon.com...
 Ben, I've got a response from the author of the Thor -
 Aleksey Bobnev <aleksey.bobnev gmail.com>

 Attached are his updated sources.
 If Thor will be included in MinTL he is willing
 to update style of comments to make them
 consistent with MinTL.

 Andrew.
 http://terrainformatica.com



 "Ben Hinkle" <ben.hinkle gmail.com> wrote in message 
 news:d5fmpg$dm5$1 digitaldaemon.com...
 Nice stuff - thanks. Plus the code is public domain just like MinTL so I 
 can
 use it (hooray). Since MinTL is a "template library" it wouldn't be out 
 of
 place to document it as part of the library (with proper credit of 
 course).

 "Andrew Fedoniouk" <news terrainformatica.com> wrote in message
 news:d5et8h$2lgq$1 digitaldaemon.com...
 oops, forgot to include link to the Thor library
 (meta.d, traits.d, typelist.d)

 http://rsdn.ru/File/28948/Thor.zip

 Author nickname is 'uv' on RSDN (Russian Software Developers Network).
 This is everything what I know about him so far.
 His statement was:
 "В качестве proof-of-concept я как-то давно реализовывал шаблоны для
 работы со списками типов на D"
 (Long ago I implemented templates for dealing with typelists in D as a
 proof-of-concept, here is a link...)

 Andrew.



May 08 2005