digitalmars.D.learn - Initializing static array with contents of (static and dynamic)
- Johannes Loher (44/44) Jul 04 2016 In a project I am currently working on, I have lot's of code of the
- ZombineDev (6/51) Jul 04 2016 You should be able to use
- Johannes Loher (3/69) Jul 04 2016 I just tried that, but it does not work for arrays, which can not be
- =?UTF-8?Q?Ali_=c3=87ehreli?= (39/57) Jul 04 2016 Here's an option that overlays a struct on top of the bytes:
- Johannes Loher (4/76) Jul 04 2016 This looks really nice, but I have several occurences of this, with
- Rene Zwanenburg (4/7) Jul 04 2016 You can use a template to remove the boilerplate. Here's a quick
- Johannes Loher (2/10) Jul 05 2016 I tried this, but it does not work correctly with slices.
- Rene Zwanenburg (7/8) Jul 05 2016 The length of a slice is a runtime value, which is why it can't
- Johannes Loher (35/46) Jul 05 2016 I would like to be able, to accept any slice. In the example in my first
- Johannes Loher (3/57) Jul 05 2016 Well, I just realized my method does not work in the case that I want to
- Marc =?UTF-8?B?U2Now7x0eg==?= (42/42) Jul 05 2016 auto concat(T : E[n], E, size_t n)(const E[][] args...) @nogc
- Johannes Loher (2/54) Jul 05 2016 This seems to be exactly what I was looking for. Thanks a lot!
In a project I am currently working on, I have lot's of code of the following form: static immutable ubyte[4] sigma0 = [101, 120, 112, 97]; static immutable ubyte[4] sigma1 = [110, 100, 32, 51]; static immutable ubyte[4] sigma2 = [ 50, 45, 98, 121]; static immutable ubyte[4] sigma3 = [116, 101, 32, 107]; void func(in ubyte[32] key, in ubyte[16] n) { ubyte[64] buf; buf[0..4] = sigma0; buf[4..20] = key[0..16]; buf[20..24] = sigma1; buf[24..40] = n; buf[40..44] = sigma2; buf[44..60] = key[16..$]; buf[60..64] = sigma3; /* do something with buf */ } This looks really bad to me. I would like to initialize buf with the corresponding values (the way it's done now, it is impossible to make buf immutable...). One option for this would be to use ~ to concatenate the arrays. But this obviously results in GC allocations, which I want to avoid here, because the functions get called very often. Another option would be to to manually expand the arrays and initialize buf with that: ubyte[64] buf = [sigma0[0], sigma0[1], /* ... */, sigma3[3]]; This is obviously very annoying and error prone. Whe searching for a solution, I found this thread about automatic expanding of arrays: http://forum.dlang.org/thread/hwellpcaomwbpnpofzlx forum.dlang.org?page=1 This would result in the following code for me: ubyte[64] buf = [ expand!sigma0, expand!key[0..16], expand!sigma1, expand!n, expand!sigma2, expand!key[16..$], expand!sigma3 ]; Is this the suggested solution (is it robust)? Is there anything like this in Phobos? Thanks for your help!
Jul 04 2016
On Monday, 4 July 2016 at 14:31:41 UTC, Johannes Loher wrote:In a project I am currently working on, I have lot's of code of the following form: static immutable ubyte[4] sigma0 = [101, 120, 112, 97]; static immutable ubyte[4] sigma1 = [110, 100, 32, 51]; static immutable ubyte[4] sigma2 = [ 50, 45, 98, 121]; static immutable ubyte[4] sigma3 = [116, 101, 32, 107]; void func(in ubyte[32] key, in ubyte[16] n) { ubyte[64] buf; buf[0..4] = sigma0; buf[4..20] = key[0..16]; buf[20..24] = sigma1; buf[24..40] = n; buf[40..44] = sigma2; buf[44..60] = key[16..$]; buf[60..64] = sigma3; /* do something with buf */ } This looks really bad to me. I would like to initialize buf with the corresponding values (the way it's done now, it is impossible to make buf immutable...). One option for this would be to use ~ to concatenate the arrays. But this obviously results in GC allocations, which I want to avoid here, because the functions get called very often. Another option would be to to manually expand the arrays and initialize buf with that: ubyte[64] buf = [sigma0[0], sigma0[1], /* ... */, sigma3[3]]; This is obviously very annoying and error prone. Whe searching for a solution, I found this thread about automatic expanding of arrays: http://forum.dlang.org/thread/hwellpcaomwbpnpofzlx forum.dlang.org?page=1 This would result in the following code for me: ubyte[64] buf = [ expand!sigma0, expand!key[0..16], expand!sigma1, expand!n, expand!sigma2, expand!key[16..$], expand!sigma3 ]; Is this the suggested solution (is it robust)? Is there anything like this in Phobos? Thanks for your help!You should be able to use http://dlang.org/phobos-prerelease/std_meta#aliasSeqOf for this. I think it should work with the same syntax as expand, but with added bonus that it also handles ranges like those in std.range and std.algorithm.
Jul 04 2016
Am 04.07.2016 um 19:24 schrieb ZombineDev:On Monday, 4 July 2016 at 14:31:41 UTC, Johannes Loher wrote:I just tried that, but it does not work for arrays, which can not be read at compile time.In a project I am currently working on, I have lot's of code of the following form: static immutable ubyte[4] sigma0 = [101, 120, 112, 97]; static immutable ubyte[4] sigma1 = [110, 100, 32, 51]; static immutable ubyte[4] sigma2 = [ 50, 45, 98, 121]; static immutable ubyte[4] sigma3 = [116, 101, 32, 107]; void func(in ubyte[32] key, in ubyte[16] n) { ubyte[64] buf; buf[0..4] = sigma0; buf[4..20] = key[0..16]; buf[20..24] = sigma1; buf[24..40] = n; buf[40..44] = sigma2; buf[44..60] = key[16..$]; buf[60..64] = sigma3; /* do something with buf */ } This looks really bad to me. I would like to initialize buf with the corresponding values (the way it's done now, it is impossible to make buf immutable...). One option for this would be to use ~ to concatenate the arrays. But this obviously results in GC allocations, which I want to avoid here, because the functions get called very often. Another option would be to to manually expand the arrays and initialize buf with that: ubyte[64] buf = [sigma0[0], sigma0[1], /* ... */, sigma3[3]]; This is obviously very annoying and error prone. Whe searching for a solution, I found this thread about automatic expanding of arrays: http://forum.dlang.org/thread/hwellpcaomwbpnpofzlx forum.dlang.org?page=1 This would result in the following code for me: ubyte[64] buf = [ expand!sigma0, expand!key[0..16], expand!sigma1, expand!n, expand!sigma2, expand!key[16..$], expand!sigma3 ]; Is this the suggested solution (is it robust)? Is there anything like this in Phobos? Thanks for your help!You should be able to use http://dlang.org/phobos-prerelease/std_meta#aliasSeqOf for this. I think it should work with the same syntax as expand, but with added bonus that it also handles ranges like those in std.range and std.algorithm.
Jul 04 2016
On 07/04/2016 07:31 AM, Johannes Loher wrote:In a project I am currently working on, I have lot's of code of the following form: static immutable ubyte[4] sigma0 = [101, 120, 112, 97]; static immutable ubyte[4] sigma1 = [110, 100, 32, 51]; static immutable ubyte[4] sigma2 = [ 50, 45, 98, 121]; static immutable ubyte[4] sigma3 = [116, 101, 32, 107]; void func(in ubyte[32] key, in ubyte[16] n) { ubyte[64] buf; buf[0..4] = sigma0; buf[4..20] = key[0..16]; buf[20..24] = sigma1; buf[24..40] = n; buf[40..44] = sigma2; buf[44..60] = key[16..$]; buf[60..64] = sigma3; /* do something with buf */ }Here's an option that overlays a struct on top of the bytes: struct Buf { union { struct { ubyte[4] sigma0 = [101, 120, 112, 97]; ubyte[16] keyBeg; ubyte[4] sigma1 = [110, 100, 32, 51]; ubyte[16] n; ubyte[4] sigma2 = [ 50, 45, 98, 121]; ubyte[16] keyEnd; ubyte[4] sigma3 = [116, 101, 32, 107]; } ubyte[64] bytes; } this(const ubyte[] key, const ubyte[] n) { this.keyBeg = key[0..16]; this.keyEnd = key[16..$]; this.n = n; } } static assert(Buf.sizeof == 64); void func(in ubyte[] key, in ubyte[] n) { auto buf = Buf(key, n); writeln(buf.bytes); } import std.stdio; import std.range; import std.array; void main() { func(ubyte(32).iota.array, ubyte(16).iota.array); } Prints: [101, 120, 112, 97, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 110, 100, 32, 51, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 50, 45, 98, 121, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 116, 101, 32, 107] Ali
Jul 04 2016
Am 04.07.2016 um 20:33 schrieb Ali Çehreli:On 07/04/2016 07:31 AM, Johannes Loher wrote:This looks really nice, but I have several occurences of this, with different arrays (and lengths), so i would need to create several of those structs. But it looks really clean :)In a project I am currently working on, I have lot's of code of the following form: static immutable ubyte[4] sigma0 = [101, 120, 112, 97]; static immutable ubyte[4] sigma1 = [110, 100, 32, 51]; static immutable ubyte[4] sigma2 = [ 50, 45, 98, 121]; static immutable ubyte[4] sigma3 = [116, 101, 32, 107]; void func(in ubyte[32] key, in ubyte[16] n) { ubyte[64] buf; buf[0..4] = sigma0; buf[4..20] = key[0..16]; buf[20..24] = sigma1; buf[24..40] = n; buf[40..44] = sigma2; buf[44..60] = key[16..$]; buf[60..64] = sigma3; /* do something with buf */ }Here's an option that overlays a struct on top of the bytes: struct Buf { union { struct { ubyte[4] sigma0 = [101, 120, 112, 97]; ubyte[16] keyBeg; ubyte[4] sigma1 = [110, 100, 32, 51]; ubyte[16] n; ubyte[4] sigma2 = [ 50, 45, 98, 121]; ubyte[16] keyEnd; ubyte[4] sigma3 = [116, 101, 32, 107]; } ubyte[64] bytes; } this(const ubyte[] key, const ubyte[] n) { this.keyBeg = key[0..16]; this.keyEnd = key[16..$]; this.n = n; } } static assert(Buf.sizeof == 64); void func(in ubyte[] key, in ubyte[] n) { auto buf = Buf(key, n); writeln(buf.bytes); } import std.stdio; import std.range; import std.array; void main() { func(ubyte(32).iota.array, ubyte(16).iota.array); } Prints: [101, 120, 112, 97, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 110, 100, 32, 51, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 50, 45, 98, 121, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 116, 101, 32, 107] Ali
Jul 04 2016
On Monday, 4 July 2016 at 19:22:52 UTC, Johannes Loher wrote:This looks really nice, but I have several occurences of this, with different arrays (and lengths), so i would need to create several of those structs. But it looks really clean :)You can use a template to remove the boilerplate. Here's a quick example: https://dpaste.dzfl.pl/43b379992648
Jul 04 2016
Am 05.07.2016 um 00:41 schrieb Rene Zwanenburg:On Monday, 4 July 2016 at 19:22:52 UTC, Johannes Loher wrote:I tried this, but it does not work correctly with slices.This looks really nice, but I have several occurences of this, with different arrays (and lengths), so i would need to create several of those structs. But it looks really clean :)You can use a template to remove the boilerplate. Here's a quick example: https://dpaste.dzfl.pl/43b379992648
Jul 05 2016
On Tuesday, 5 July 2016 at 12:34:20 UTC, Johannes Loher wrote:I tried this, but it does not work correctly with slices.The length of a slice is a runtime value, which is why it can't be used to set static array size. What were you trying to achieve? Avoid copying the input arrays, or accepting any slice? In case of the first, you can put ref in front of the Args: auto combineArrays(Args...)(ref Args args) The second case will be a bit harder to solve nicely..
Jul 05 2016
Am 05.07.2016 um 16:39 schrieb Rene Zwanenburg:On Tuesday, 5 July 2016 at 12:34:20 UTC, Johannes Loher wrote:I would like to be able, to accept any slice. In the example in my first post, I need this for key[0..16] and key[16..$] (which are slices). Strangely enough, the solution I am leaning towards at the moment also uses length, but it does work for slices of static arrays (i.e. key[0..16]): template expand(alias A) { auto ref M(alias I)() property { return A[I]; } mixin(q{alias expand = TypeTuple!(} ~ iota(A.length).map!(a => "M!" ~ a.to!string).join(",") ~ q{);}); } ubyte[64] buf = [expand!sigma0, expand!key[0..16], expand!sigma1, expand!n, expand!sigma2, expand!key[16..$], expand!sigma3]; I suppose this is because the length of those slices is actually known at copiletime, but it looks a bit strange to me... I was trying to write another template that takes several arrays and expands all of them: template expand(Args...) { mixin(q{alias expand = TypeTuple!(} ~ iota(Args.length).map!(a => "expand!(Args[" ~ a.to!string ~ "])").join(",") ~ q{);}); } It works for static arrays, but not for slices, because the template parameters are not alias parameters, so the length is then not "known" at compile time (at least that's what I think why it fails). Is there a way to specify variadic templates taking any number of alias template parameters?I tried this, but it does not work correctly with slices.The length of a slice is a runtime value, which is why it can't be used to set static array size. What were you trying to achieve? Avoid copying the input arrays, or accepting any slice? In case of the first, you can put ref in front of the Args: auto combineArrays(Args...)(ref Args args) The second case will be a bit harder to solve nicely..
Jul 05 2016
Am 05.07.2016 um 17:12 schrieb Johannes Loher:Am 05.07.2016 um 16:39 schrieb Rene Zwanenburg:Well, I just realized my method does not work in the case that I want to use expand on static arrays, which are returned from template functions...On Tuesday, 5 July 2016 at 12:34:20 UTC, Johannes Loher wrote:I would like to be able, to accept any slice. In the example in my first post, I need this for key[0..16] and key[16..$] (which are slices). Strangely enough, the solution I am leaning towards at the moment also uses length, but it does work for slices of static arrays (i.e. key[0..16]): template expand(alias A) { auto ref M(alias I)() property { return A[I]; } mixin(q{alias expand = TypeTuple!(} ~ iota(A.length).map!(a => "M!" ~ a.to!string).join(",") ~ q{);}); } ubyte[64] buf = [expand!sigma0, expand!key[0..16], expand!sigma1, expand!n, expand!sigma2, expand!key[16..$], expand!sigma3]; I suppose this is because the length of those slices is actually known at copiletime, but it looks a bit strange to me... I was trying to write another template that takes several arrays and expands all of them: template expand(Args...) { mixin(q{alias expand = TypeTuple!(} ~ iota(Args.length).map!(a => "expand!(Args[" ~ a.to!string ~ "])").join(",") ~ q{);}); } It works for static arrays, but not for slices, because the template parameters are not alias parameters, so the length is then not "known" at compile time (at least that's what I think why it fails). Is there a way to specify variadic templates taking any number of alias template parameters?I tried this, but it does not work correctly with slices.The length of a slice is a runtime value, which is why it can't be used to set static array size. What were you trying to achieve? Avoid copying the input arrays, or accepting any slice? In case of the first, you can put ref in front of the Args: auto combineArrays(Args...)(ref Args args) The second case will be a bit harder to solve nicely..
Jul 05 2016
auto concat(T : E[n], E, size_t n)(const E[][] args...) nogc { size_t offset = 0; T result = void; foreach(arr; args) { result[offset .. offset+arr.length] = arr; offset += arr.length; } assert(offset == result.length); return result; } static immutable ubyte[4] sigma0 = [101, 120, 112, 97]; static immutable ubyte[4] sigma1 = [110, 100, 32, 51]; static immutable ubyte[4] sigma2 = [ 50, 45, 98, 121]; static immutable ubyte[4] sigma3 = [116, 101, 32, 107]; void func(in ref ubyte[32] key, in ref ubyte[16] n) nogc { ubyte[64] buf; buf[0..4] = sigma0; buf[4..20] = key[0..16]; buf[20..24] = sigma1; buf[24..40] = n; buf[40..44] = sigma2; buf[44..60] = key[16..$]; buf[60..64] = sigma3; auto buf2 = concat!(ubyte[64])(sigma0, key[0..16], sigma1, n, sigma2, key[16..$], sigma3); assert(buf == buf2); } void main() { ubyte[32] key = [0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1]; ubyte[16] n = key[0..16]; func(key, n); } Some remarks: * I added `ref` to `func`'s parameters, because the arrays are relatively large, so passing them by value might be costly (you should measure it if you care). * The `void` initialization in `concat` is an optimization that is valid only for POD types. * Returning the array is cheap because of NRVO.
Jul 05 2016
Am 05.07.2016 um 17:22 schrieb Marc Schütz:auto concat(T : E[n], E, size_t n)(const E[][] args...) nogc { size_t offset = 0; T result = void; foreach(arr; args) { result[offset .. offset+arr.length] = arr; offset += arr.length; } assert(offset == result.length); return result; } static immutable ubyte[4] sigma0 = [101, 120, 112, 97]; static immutable ubyte[4] sigma1 = [110, 100, 32, 51]; static immutable ubyte[4] sigma2 = [ 50, 45, 98, 121]; static immutable ubyte[4] sigma3 = [116, 101, 32, 107]; void func(in ref ubyte[32] key, in ref ubyte[16] n) nogc { ubyte[64] buf; buf[0..4] = sigma0; buf[4..20] = key[0..16]; buf[20..24] = sigma1; buf[24..40] = n; buf[40..44] = sigma2; buf[44..60] = key[16..$]; buf[60..64] = sigma3; auto buf2 = concat!(ubyte[64])(sigma0, key[0..16], sigma1, n, sigma2, key[16..$], sigma3); assert(buf == buf2); } void main() { ubyte[32] key = [0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1]; ubyte[16] n = key[0..16]; func(key, n); } Some remarks: * I added `ref` to `func`'s parameters, because the arrays are relatively large, so passing them by value might be costly (you should measure it if you care). * The `void` initialization in `concat` is an optimization that is valid only for POD types. * Returning the array is cheap because of NRVO.This seems to be exactly what I was looking for. Thanks a lot!
Jul 05 2016