www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Non-recursive maxSizeOf

reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
Is it possible to implement

template maxSizeOf(T...)
{
     static if (T.length == 1)
         enum size_t maxSizeOf = T[0].sizeof;
     else
     {
         enum size_t firstSize = T[0].sizeof;
         enum size_t maxSizeRest = maxSizeOf!(T[1 .. $]);
         enum size_t maxSizeOf = firstSize >= maxSizeRest ? 
firstSize : maxSizeRest;
     }
}

in a non-recursive way?
Aug 05 2020
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/5/20 5:58 PM, Per Nordl=C3=B6w wrote:
 Is it possible to implement
=20
 template maxSizeOf(T...)
 {
  =C2=A0=C2=A0=C2=A0 static if (T.length =3D=3D 1)
  =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 enum size_t maxSizeOf =3D T=
[0].sizeof;
  =C2=A0=C2=A0=C2=A0 else
  =C2=A0=C2=A0=C2=A0 {
  =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 enum size_t firstSize =3D T=
[0].sizeof;
  =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 enum size_t maxSizeRest =3D=
maxSizeOf!(T[1 .. $]);
  =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 enum size_t maxSizeOf =3D f=
irstSize >=3D maxSizeRest ? firstSize :=20
 maxSizeRest;
  =C2=A0=C2=A0=C2=A0 }
 }
=20
 in a non-recursive way?
Boring in D. :p template maxSizeOf(T...) { enum maxSizeOf =3D compute(); auto compute() { size_t result; static foreach (t; T) { if (t.sizeof > result) { result =3D t.sizeof; } } return result; } } void main() { pragma(msg, maxSizeOf!(double, char, string)); } Ali
Aug 05 2020
next sibling parent Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Thursday, 6 August 2020 at 01:13:28 UTC, Ali Çehreli wrote:
 Boring in D. :p

 template maxSizeOf(T...) {
   enum maxSizeOf = compute();

   auto compute() {
     size_t result;
     static foreach (t; T) {
       if (t.sizeof > result) {
         result = t.sizeof;
       }
     }
     return result;
   }
 }
I forgot to say that I was looking for a solution that used `static foreach` but doesn't trigger CTFE...
Aug 05 2020
prev sibling parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Thursday, 6 August 2020 at 01:13:28 UTC, Ali Çehreli wrote:
 Boring in D. :p

 template maxSizeOf(T...) {
   enum maxSizeOf = compute();

   auto compute() {
     size_t result;
     static foreach (t; T) {
       if (t.sizeof > result) {
         result = t.sizeof;
       }
     }
     return result;
   }
 }
Thanks. I'm gonna benchmark this against my templated solution.
Aug 06 2020
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/6/20 4:44 AM, Per Nordl=C3=B6w wrote:
 On Thursday, 6 August 2020 at 01:13:28 UTC, Ali =C3=87ehreli wrote:
 Boring in D. :p

 template maxSizeOf(T...) {
 =C2=A0 enum maxSizeOf =3D compute();

 =C2=A0 auto compute() {
 =C2=A0=C2=A0=C2=A0 size_t result;
 =C2=A0=C2=A0=C2=A0 static foreach (t; T) {
 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (t.sizeof > result) {
 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 result =3D t.sizeof;
 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
 =C2=A0=C2=A0=C2=A0 }
 =C2=A0=C2=A0=C2=A0 return result;
 =C2=A0 }
 }
=20 Thanks. I'm gonna benchmark this against my templated solution.
I guess an anonymous function would remove the need for that creative=20 name. :) enum maxSizeOf =3D { // ... }(); Ali
Aug 06 2020
prev sibling next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 6 August 2020 at 00:58:39 UTC, Per Nordlöw wrote:
 Is it possible to implement

 in a non-recursive way?
It is very easy too... just write an ordinary function: size_t maxSizeOf(T...)() { size_t max = 0; foreach(t; T) if(t.sizeof > max) max = t.sizeof; return max; } pragma(msg, maxSizeOf!(int, char, long));
Aug 05 2020
next sibling parent reply lithium iodate <whatdoiknow doesntexist.net> writes:
On Thursday, 6 August 2020 at 01:13:41 UTC, Adam D. Ruppe wrote:
 size_t maxSizeOf(T...)() {
         size_t max = 0;
         foreach(t; T)
                 if(t.sizeof > max)
                         max = t.sizeof;
         return max;
 }

 pragma(msg, maxSizeOf!(int, char, long));
more love for phobos pls template maxSizeOf(T...) { template sizeOf(T) { // doesn't exist in phobos? enum sizeOf = T.sizeof; } enum size_t maxSizeOf = maxElement([staticMap!(sizeOf, T)]); }
Aug 05 2020
next sibling parent Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Thursday, 6 August 2020 at 01:17:51 UTC, lithium iodate wrote:
 more love for phobos pls

 template maxSizeOf(T...)
 {
     template sizeOf(T) { // doesn't exist in phobos?
         enum sizeOf = T.sizeof;
     }
     enum size_t maxSizeOf = maxElement([staticMap!(sizeOf, T)]);
 }
`std.meta.staticMap` is defined recursively....
Aug 05 2020
prev sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 6 August 2020 at 01:17:51 UTC, lithium iodate wrote:
 more love for phobos pls
That would add a lot to the cost and bring no real benefit....
Aug 05 2020
prev sibling parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Thursday, 6 August 2020 at 01:13:41 UTC, Adam D. Ruppe wrote:
 It is very easy too... just write an ordinary function:

 size_t maxSizeOf(T...)() {
         size_t max = 0;
         foreach(t; T)
                 if(t.sizeof > max)
                         max = t.sizeof;
         return max;
 }

 pragma(msg, maxSizeOf!(int, char, long));
How does the memory usage and speed of this code compare to the variant that uses template instantiations? In general? Any experiences on this?
Aug 05 2020
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 6 August 2020 at 01:23:33 UTC, Per Nordlöw wrote:
 How does the memory usage and speed of this code compare to the 
 variant that uses template instantiations?
I haven't tested this specifically, but similar tests have come in at like 1/10th the memory and compile time cost. There is one template instance here per argument list though, and that template includes the implementation function. The eponymous version Ali posted will perform a bit better than my version because the compiler can see it will never need code generation. Still for small argument lists the Phobos one might do better, but for larger ones, the ctfe version should be much better. So on average Ali's version is almost certain to win in my experience.
Aug 05 2020
prev sibling parent reply H. S. Teoh <hsteoh quickfur.ath.cx> writes:
On Thursday, 6 August 2020 at 00:58:39 UTC, Per Nordlöw wrote:
 Is it possible to implement

 template maxSizeOf(T...)
 {
     static if (T.length == 1)
         enum size_t maxSizeOf = T[0].sizeof;
     else
     {
         enum size_t firstSize = T[0].sizeof;
         enum size_t maxSizeRest = maxSizeOf!(T[1 .. $]);
         enum size_t maxSizeOf = firstSize >= maxSizeRest ? 
 firstSize : maxSizeRest;
     }
 }

 in a non-recursive way?
Of course. In fact, it's trivial: ------ template maxSizeOf(T...) { align(1) union Impl { T t; } enum maxSizeOf = Impl.sizeof; } ------ To check that this does what we expect: ------ pragma(msg, maxSizeOf!(char)); // 1LU pragma(msg, maxSizeOf!(char, short, ubyte)); // 2LU pragma(msg, maxSizeOf!(char, long, ubyte)); // 8LU align(1) struct S { long l; ubyte b; } pragma(msg, maxSizeOf!(long, S)); // 9LU pragma(msg, maxSizeOf!(int, ubyte[7])); // 7LU pragma(msg, maxSizeOf!(int, ubyte[3])); // 4LU ------ Why bother with recursion and all of that fancy gobbledygook when the compiler already knows how to compute the maximum size of something? ;-)
Aug 06 2020
next sibling parent Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Thursday, 6 August 2020 at 12:51:22 UTC, H. S. Teoh wrote:
 Of course. In fact, it's trivial:

 ------
 template maxSizeOf(T...)
 {
 	align(1) union Impl {
 		T t;
 	}
 	enum maxSizeOf = Impl.sizeof;
 }
Clever. Thanks
Aug 06 2020
prev sibling parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Thursday, 6 August 2020 at 12:51:22 UTC, H. S. Teoh wrote:
 Of course. In fact, it's trivial:

 ------
 template maxSizeOf(T...)
 {
 	align(1) union Impl {
 		T t;
 	}
 	enum maxSizeOf = Impl.sizeof;
 }
I originally copied my original version of `maxSizeOf` from `std.variant.maxSize` currently being template maxSize(T...) { static if (T.length == 1) { enum size_t maxSize = T[0].sizeof; } else { import std.algorithm.comparison : max; enum size_t maxSize = max(T[0].sizeof, maxSize!(T[1 .. $])); } } . It should be updated to use this trick. However, your solution template maxSize(T...) { align(1) union Impl { T t; } enum maxSize = Impl.sizeof; } fails as variable `std.variant.maxSize!(void, string).Impl.__t_field_0` variables cannot be of type `void` because one of the instances of `maxSize` in std.variant has `void` as a member `T...`. Do you have any simple solution to this, H. S. Teoh?
Aug 06 2020
next sibling parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Thursday, 6 August 2020 at 13:07:14 UTC, Per Nordlöw wrote:
 Do you have any simple solution to this, H. S. Teoh?
I also tried template maxSize(Ts...) { align(1) union Impl { // See_Also: https://forum.dlang.org/thread/wbpnncxepehgcswhuazl forum.dlang.org?page=1 static foreach (T; Ts) { static if (!is(T == void)) { pragma(msg, T.stringof ~ " _store" ~ T.mangleof ~ ";"); mixin(T.stringof ~ " _store" ~ T.mangleof ~ ";"); } } } enum maxSize = Impl.sizeof; } but that fails because of types not being defined in scope such as Cat _storeS3std7variant17__unittest_L96_C7FNfZ3Cat; /home/per/Work/phobos/std/variant.d-mixin-88(88,5): Error: undefined identifier `Cat` Can somebody find a better alternative?
Aug 06 2020
next sibling parent Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Thursday, 6 August 2020 at 13:18:40 UTC, Per Nordlöw wrote:
 Can somebody find a better alternative?
Let's continue discussion at https://github.com/dlang/phobos/pull/7582
Aug 06 2020
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 6 August 2020 at 13:18:40 UTC, Per Nordlöw wrote:
                 mixin(T.stringof ~ " _store" ~ T.mangleof ~
Never ever use mixin(T.stringof). Always just use mixin("T") instead. mixin("T _store", T.mangleof /* or just idx is gonna be better */,";"); Though I doubt this is going to win a benchmark anyway getting this complicated.
Aug 06 2020
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/6/20 9:23 AM, Adam D. Ruppe wrote:
 On Thursday, 6 August 2020 at 13:18:40 UTC, Per Nordlöw wrote:
                 mixin(T.stringof ~ " _store" ~ T.mangleof ~
Never ever use mixin(T.stringof). Always just use mixin("T") instead. mixin("T _store", T.mangleof /* or just idx is gonna be better */,";"); Though I doubt this is going to win a benchmark anyway getting this complicated.
Well, one *could* do: static if(is(union { Ts t; })) and use the union for "normal" cases. I think the CTFE solution is cleaner. Is there a good reason to avoid it? -Steve
Aug 06 2020
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Aug 06, 2020 at 01:07:14PM +0000, Per Nordlöw via Digitalmars-d-learn
wrote:
[...]
 However, your solution
 
 template maxSize(T...)
 {
     align(1) union Impl { T t; }
  	enum maxSize = Impl.sizeof;
 }
 
 fails as
 
 variable `std.variant.maxSize!(void, string).Impl.__t_field_0`
 variables cannot be of type `void`
 
 because one of the instances of `maxSize` in std.variant has `void` as
 a member `T...`.
Ugh, apparently `void` is one of those nasty inconsistent things that has all sorts of ad hoc behaviour: - void cannot be used to instantiate variables (behaves sortof like a bottom type); - But in spite of that, void.sizeof == 1, rather than the expected 0. My guess is that this has to do with the hack to make the size of void[] equal to its length; - void in void[] is a top type (but only in that context -- but its .sizeof is inconsistent with this); - void is a unit type when specified as a function return type (but in spite of that cannot be instantiated, contrary to a true unit type, and this contradicts its being a top type in void[]); IOW, void is a mishmash of ad hoc things thrown together in a way that isn't even self-consistent. A chimera of exceptions that, it would seem, always require special-casing to handle.
 Do you have any simple solution to this, H. S. Teoh?
Unfortunately, no. :-( Why does std.variant even support storing void in the first place?! T -- People tell me that I'm paranoid, but they're just out to get me.
Aug 06 2020