Jump to page: 1 2 3
Thread overview
Appending static arrays
Jul 17
Nordlöw
Jul 17
ag0aep6g
Jul 17
Nordlöw
Jul 17
ag0aep6g
Jul 17
Nordlöw
Jul 17
Nordlöw
Jul 17
Nordlöw
Jul 17
Nordlöw
Jul 17
Nordlöw
Jul 17
Nordlöw
Jul 17
Nordlöw
Jul 17
Nordlöw
Jul 18
Nordlöw
Jul 17
Nordlöw
July 17
I'm want to define a specialization of `append()` that takes only static arrays as inputs and returns a static array being the sum of the lengths of the inputs.

Have anybody already implemented this?

If not, I'm specifically interested in how to most conveniently infer the length (as an enum) of the returned static array from the `.length`s of inputs (which of course must be enum-values too).
July 17
On 07/17/2017 07:38 PM, Nordlöw wrote:
> I'm want to define a specialization of `append()` that takes only static arrays as inputs and returns a static array being the sum of the lengths of the inputs.
> 
> Have anybody already implemented this?
> 
> If not, I'm specifically interested in how to most conveniently infer the length (as an enum) of the returned static array from the `.length`s of inputs (which of course must be enum-values too).

Like so?

int[n + m] append(size_t n, size_t m)(int[n] a, int[m] b)
{
    int[n + m] result = a ~ b;
    return result;
}
July 17
On Monday, 17 July 2017 at 17:46:42 UTC, ag0aep6g wrote:
> Like so?
>
> int[n + m] append(size_t n, size_t m)(int[n] a, int[m] b)
> {
>     int[n + m] result = a ~ b;
>     return result;
> }

Thanks, but I'm talking about the variadic case where the number of input arguments are unknown (>= 2) where the function header looks something like

import std.traits : allSatisfy, isStaticArray;

auto append(R, Args...)(auto ref Args args)
    if (args.length >= 2 &&
        allSatisfy!(isStaticArray, Args))
    // TODO all ElementTypes have CommonType
{
    // ...
}

July 17
On Monday, 17 July 2017 at 17:46:42 UTC, ag0aep6g wrote:
>     int[n + m] result = a ~ b;

Further, the expression `a ~ b` here will allocate and create a copy on the GC-heap before writing `result`.

Maybe LDC optimizes away this now or in the future but DMD cannot.

Yeah I know, kind of dumb but that's how it is currently.
July 17
On Monday, 17 July 2017 at 17:38:23 UTC, Nordlöw wrote:
> I'm want to define a specialization of `append()` that takes only static arrays as inputs and returns a static array being the sum of the lengths of the inputs.
>
> Have anybody already implemented this?
>
> If not, I'm specifically interested in how to most conveniently infer the length (as an enum) of the returned static array from the `.length`s of inputs (which of course must be enum-values too).

I just realized that I can use `std.meta.staticMap` to get the lengths but I still need to reduce them and there is no variant of `reduce` in `std.meta`. Why? Hasn't it been written yet?

I know I can always write yet another recursive CT-function, say `SumOfLengths`, but I thought I'd try to reuse `std.meta` this time. :)
July 17
On Monday, 17 July 2017 at 18:38:16 UTC, Nordlöw wrote:
> On Monday, 17 July 2017 at 17:46:42 UTC, ag0aep6g wrote:
>>     int[n + m] result = a ~ b;
>
> Further, the expression `a ~ b` here will allocate and create a copy on the GC-heap before writing `result`.
>
> Maybe LDC optimizes away this now or in the future but DMD cannot.
>
> Yeah I know, kind of dumb but that's how it is currently.

we have special code in the compiler to optimize a ~ b ~ c.
So all you need to do make it so
auto cat(T[]...)(T args)
{
    T[] result;
    mixin(() {
      string mix  = `result = `;
      foreach(i;args.length)
      {
        mix ~= `args[` ~ itos(i) ~ `] ~`;
      }
      mix[$-1] = ';';
      return mix;
    }());

    return result;
}

that should do it :)
July 17
On Mon, Jul 17, 2017 at 05:38:23PM +0000, Nordlöw via Digitalmars-d-learn wrote:
> I'm want to define a specialization of `append()` that takes only static arrays as inputs and returns a static array being the sum of the lengths of the inputs.
> 
> Have anybody already implemented this?
> 
> If not, I'm specifically interested in how to most conveniently infer
> the length (as an enum) of the returned static array from the
> `.length`s of inputs (which of course must be enum-values too).

Hmm. What about:

	template sumOfLengths(A...)
		if (A.length > 0)
	{
		static if (A.length == 1)
			enum sumOfLengths = A[0].length;
		else
			enum sumOfLengths = A[0].length + sumOfLengths!(A[1 .. $]);
	}

	T[sumOfLengths!StaticArrays] append(StaticArrays...)(StaticArrays arrays)
		if (/* insert static array constraints here */)
	{
		typeof(return) result = void;
		size_t offset = 0;
		foreach (a; arrays)
		{
			result[offset .. offset + a.length] = a[];
		}
		return result;
	}


T

-- 
IBM = I'll Buy Microsoft!
July 17
On Mon, Jul 17, 2017 at 12:01:48PM -0700, H. S. Teoh via Digitalmars-d-learn wrote: [...]
> 	T[sumOfLengths!StaticArrays] append(StaticArrays...)(StaticArrays arrays)
> 		if (/* insert static array constraints here */)
> 	{
> 		typeof(return) result = void;
> 		size_t offset = 0;
> 		foreach (a; arrays)
> 		{
> 			result[offset .. offset + a.length] = a[];

Argh, forgot this important line:

			offset += a.length;


> 		}
> 		return result;
> 	}
[...]


T

-- 
Marketing: the art of convincing people to pay for what they didn't need before which you fail to deliver after.
July 17
On 07/17/2017 08:35 PM, Nordlöw wrote:
> Thanks, but I'm talking about the variadic case where the number of input arguments are unknown (>= 2) where the function header looks something like
> 
> import std.traits : allSatisfy, isStaticArray;
> 
> auto append(R, Args...)(auto ref Args args)
>      if (args.length >= 2 &&
>          allSatisfy!(isStaticArray, Args))
>      // TODO all ElementTypes have CommonType
> {
>      // ...
> }
> 

I see. Here's what I could come up with:

----
import std.traits : allSatisfy, isStaticArray;

auto append(Args...)(auto ref Args args)
    if (args.length >= 2 &&
        allSatisfy!(isStaticArray, Args))
{
    import std.algorithm : sum;
    import std.meta : staticMap;
    import std.range: ElementType;
    import std.traits : CommonType;

    enum staticArrayLength(A : E[n], E, size_t n) = n;

    alias E = ElementType!(Args[0]);
    static assert(is(CommonType!(staticMap!(ElementType, Args)) : E));
    enum lengths = staticMap!(staticArrayLength, Args);

    E[sum([lengths])] result;
    foreach (i, length; lengths)
    {
        enum offset = sum!(size_t[])([lengths[0 .. i]]);
        result[offset .. offset + length] = args[i];
    }
    return result;
}

@nogc unittest
{
    int[3] a = [1, 2, 3];
    const int[4] b = [4, 5, 6, 7];
    immutable int[5] c = [8, 9, 10, 11, 12];

    auto r = append(a, b, c);
    assert(r == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
    static assert(is(typeof(r) == int[12]));
}
----
July 17
On Mon, Jul 17, 2017 at 12:01:48PM -0700, H. S. Teoh via Digitalmars-d-learn wrote: [...]
> 	template sumOfLengths(A...)
> 		if (A.length > 0)
> 	{
> 		static if (A.length == 1)
> 			enum sumOfLengths = A[0].length;
> 		else
> 			enum sumOfLengths = A[0].length + sumOfLengths!(A[1 .. $]);
> 	}
> 
> 	T[sumOfLengths!StaticArrays] append(StaticArrays...)(StaticArrays arrays)
> 		if (/* insert static array constraints here */)
> 	{
> 		typeof(return) result = void;
> 		size_t offset = 0;
> 		foreach (a; arrays)
> 		{
> 			result[offset .. offset + a.length] = a[];
> 		}
> 		return result;
> 	}
[...]

Hmm, since we already have sumOfLengths available at compile-time, what about:

 	T[sumOfLengths!StaticArrays] append(StaticArrays...)(StaticArrays arrays)
 		if (allSatisfy!(isStaticArray, StaticArrays))
 	{
 		typeof(return) result = void;
 		foreach (i, a; 0 .. arrays.length)
 		{
			enum offset = sumOfLengths!(arrays[0 .. i]);
 			result[offset .. offset + a.length] = a[];
 		}
 		return result;
 	}


T

-- 
People say I'm indecisive, but I'm not sure about that. -- YHL, CONLANG
« First   ‹ Prev
1 2 3