Re: in / out for C++ programmers
On Friday, March 23, 2012 23:37:27 Ali Çehreli wrote: > 'in' is the same as 'const scope'. const part is easy to understand but > I don't know what 'scope' does. I could not understand what the spec > means with "references in the parameter cannot be escaped (e.g. assigned > to a global variable)" for scope: > >http://dlang.org/function.html You mean that you don't understand what it means for a reference to escape a function? One example of this with pointers would be int* func() { int a; return &a; } A pointer to a local variable has escaped the function. That pointer is invalid. A case this simple gets caught by the compiler, but it's very easy to get around that (e.g. passing &a to a function which returns it and then return the result of that function rather than &a directly). In the case of scope, it means that what you pass in cannot be assigned to a global or static variable, and it cannot be returned from that function. So, for instance. int[] foo(const int[] a) { ... } could not assign a to a global or static variable and cannot return it. This can allow some additional optimizations as well as improve safety in some cases. For instance, if you pass int[5] b; to foo, then you know that no slice of that static array will escape, since something like int[] bar() { int[5] c; return c; } is just as bad as the case with &a. I believe that scope is used primarily with delegates however (particularly, since you often _want_ to be able to return a slice of an array passed to a function). It guarantees that the the delegate's context won't escape the function and can make it so that the delegate's context doesn't have to be allocated on the heap, which improves efficiency. scope is pointless with types which aren't pointers or references though. - Jonathan M Davis
Re: in / out for C++ programmers
On 03/23/2012 11:28 PM, Dan wrote: > When would you use in / out parameters instead of ref & const keywords? I am just about finished translating a chapter exactly on that topic. I've just realized that I have some questions myself. :) 'out' is the equivalent of a reference in C++, with additionally initializing the out parameter upon entry to the function. void foo(out int i) { assert(i == 0); // regardless of what it was before the call } 'in' is the same as 'const scope'. const part is easy to understand but I don't know what 'scope' does. I could not understand what the spec means with "references in the parameter cannot be escaped (e.g. assigned to a global variable)" for scope: http://dlang.org/function.html 'ref' is the same as a C++ reference. Ali
Re: in / out for C++ programmers
On Saturday, March 24, 2012 07:28:08 Dan wrote: > When would you use in / out parameters instead of ref & const > keywords? out sets the variable to its init value, so you don't run into issues with the behavior of the function changing based on the value of the variable that you passed in. out is intended for variables that are for returning an extra value from the function, not passing one in. You use ref if you want to actually use the value that you pass in. in is the same as const scope and has nothing to do with ref at all. - Jonathan M Davis
in / out for C++ programmers
When would you use in / out parameters instead of ref & const keywords? Thanks.
Re: Map with maintained insertion order
On Saturday, 24 March 2012 at 01:07:56 UTC, Jonathan M Davis wrote: On Friday, March 23, 2012 23:48:51 Andrej Mitrovic wrote: Does someone have a map implementation that maintains the insertion order of the keys? E.g.: string[string] map; map["foo"] = "x"; map["bar"] = "y"; When iterating over map keys I want to visit "foo" first, then "bar", and so on. I can't think of any data structure that does that off the top of my head, though there may very well be one. If you don't mind the extra memory overhead, it wouldn't be all that hard to do it with multiple maps wrapped in a single type. You could do something like class InsertedOrderMap { string[string] _map; RedBlackTree!(Tuple!(int, string), "a[0] < b[0]") _insertionOrder; ... } _map holds the normal map and _insertionOrder holds pairs of the insertion ordered and the key to _map. You can then have your range iterate over _insertionOrder and use the keys to return either the keys, values, or pairs of keys and values from _map, depending on what you want to iterate over. That _does_ require having two data structures in one, and there may a be a better way to do it, but just off the top of my head, that's the best that I can come up with. I don't know how you could have a data structure where it's efficient to index by both insertion order and key without effectively having two data structures. But I really should go reread my data structures books. It's been too long since I studied that stuff. - Jonathan M Davis Ruby's Hash in 1.9 maintains insertion order. It does it using a linked list between the nodes as they are created (so yes, essentially two data structures). Regards, Brad Anderson
Re: Map with maintained insertion order
On 3/24/12, Andrej Mitrovic wrote: > Correction, it's: > template isValue(T) > { > enum bool isValue = is(typeof( { Value v; T t; v = t; } )) > || is(typeof( { BaseElement!Value v; T t; v = t; } )) > || is(BaseElement!Value == T); > } Last check not needed, so: > template isValue(T) > { > enum bool isValue = is(typeof( { Value v; T t; v = t; } )) > || is(typeof( { BaseElement!Value v; T t; v = t; } )); > } Anyway I'll stop spamming.
Re: Map with maintained insertion order
On 3/24/12, Andrej Mitrovic wrote: > static if (isArray!Value) > { > template isValue(T) > { >enum bool isValue = is(typeof( { Value v; T t; v = t; } )) || > is(BaseElement!Value == T); > } > } Correction, it's: template isValue(T) { enum bool isValue = is(typeof( { Value v; T t; v = t; } )) || is(typeof( { BaseElement!Value v; T t; v = t; } )) || is(BaseElement!Value == T); } Complicated beast, but I have to take into acount both 'alias this' tricks and the fact that ~= works when RHS is either an element type or an array.
Re: Map with maintained insertion order
On 3/24/12, Andrej Mitrovic wrote: > On 3/23/12, Andrej Mitrovic wrote: >> Does someone have a map implementation that maintains the insertion >> order of the keys? > > Here's a sloppy implementation: I forgot to make opIndex ref, but also the isValue check fails on structs with alias this, it's better to use is(typeof()) instead of directly checking the type. The fix would be: static if (isArray!Value) { template isValue(T) { enum bool isValue = is(typeof( { Value v; T t; v = t; } )) || is(BaseElement!Value == T); } } else { template isValue(T) { enum bool isValue = is(typeof( { Value v; T t; v = t; } )); } }
Re: Map with maintained insertion order
On Fri, Mar 23, 2012 at 06:33:54PM -0700, H. S. Teoh wrote: > On Fri, Mar 23, 2012 at 06:07:42PM -0700, Jonathan M Davis wrote: > > On Friday, March 23, 2012 23:48:51 Andrej Mitrovic wrote: > > > Does someone have a map implementation that maintains the insertion > > > order of the keys? > > > > > > E.g.: > > > > > > string[string] map; > > > map["foo"] = "x"; > > > map["bar"] = "y"; > > > > > > When iterating over map keys I want to visit "foo" first, then > > > "bar", and so on. > > > > I can't think of any data structure that does that off the top of my > > head, though there may very well be one. > [...] > > Yes there is one. It's called a B-tree. And it's probably total overkill > for what you need. :-) But also, B-trees have O(log n) access time, not > O(1). :-( [...] Actually, nevermind that. B-trees are probably not what you're looking for at all, and they aren't really suited to the task anyway (you want to sort by insertion order, not key order). What you *could* do is implement a hash augmented with next/prev pointers in each slot, IOW, a linked list. The hash itself stores a pointer to the head and tail of the list. When a new slot is created, the tail of the list is updated to link to it. When a slot is deleted, its neighbours are updated. This will maintain O(1) performance of the hash. In fact, you could use the current AA implementation if you wrap your data in a struct that contains the extra pointers, and wrap around the AA operations to update these pointers as needed. T -- Valentine's Day: an occasion for florists to reach into the wallets of nominal lovers in dire need of being reminded to profess their hypothetical love for their long-forgotten.
Re: Map with maintained insertion order
On Fri, Mar 23, 2012 at 06:07:42PM -0700, Jonathan M Davis wrote: > On Friday, March 23, 2012 23:48:51 Andrej Mitrovic wrote: > > Does someone have a map implementation that maintains the insertion > > order of the keys? > > > > E.g.: > > > > string[string] map; > > map["foo"] = "x"; > > map["bar"] = "y"; > > > > When iterating over map keys I want to visit "foo" first, then > > "bar", and so on. > > I can't think of any data structure that does that off the top of my > head, though there may very well be one. [...] Yes there is one. It's called a B-tree. And it's probably total overkill for what you need. :-) But also, B-trees have O(log n) access time, not O(1). :-( T -- Right now I'm having amnesia and deja vu at the same time. I think I've forgotten this before.
Re: Map with maintained insertion order
On 3/24/12, Jonathan M Davis wrote: > I can't think of any data structure that does that off the top of my head Java has it and they call it a LinkedHashMap: http://docs.oracle.com/javase/1.4.2/docs/api/java/util/LinkedHashMap.html > That _does_ require having two data structures in one, and there may a be a > better way to do it, but just off the top of my head, that's the best that I > can come up with. I don't know how you could have a data structure where > it's efficient to index by both insertion order and key without effectively > having two data structures. Yeah it's not efficient, but in my use-case I'm not looking so much for efficiency but convenience. Sometimes I have to look up a key based on a name to modify some values, and I have to keep the order of the keys.
Re: Map with maintained insertion order
On 3/23/12, Andrej Mitrovic wrote: > Does someone have a map implementation that maintains the insertion > order of the keys? Here's a sloppy implementation: module test; import std.stdio; import std.traits; template KeyType(V : V[K], K) if (isAssociativeArray!(V[K])) { alias K KeyType; } template ValueType(V : V[K], K) if (isAssociativeArray!(V[K])) { alias V ValueType; } template BaseElement(T : U[], U) { alias U BaseElement; } struct LinkedHash(T) if (isAssociativeArray!T) { alias KeyType!T Key; alias ValueType!T Value; static if (isArray!Value) template isValue(T) { enum bool isValue = (is(T == Value) || is(BaseElement!Value == T)); } else template isValue(T) { enum bool isValue = is(T == Value); } Value[] payload; size_t[Key] keyToIndex; Key[size_t] indexToKey; size_t lastIndex; size_t getNewIndex() { payload.length = payload.length + 1; return lastIndex++; } size_t* getKeyIndex(string key) { if (auto index = key in keyToIndex) return index; else return null; } Value opIndex(in Key key) { if (auto index = getKeyIndex(key)) return payload[*index]; else assert(0, "Key '" ~ key ~ "' not found."); } void opIndexAssign(V)(V value, Key key) if (isValue!V) { if (auto index = getKeyIndex(key)) payload[*index] = value; else { auto index = getNewIndex(); payload[index] = value; keyToIndex[key] = index; indexToKey[index] = key; } } void opIndexOpAssign(string op, V)(V value, Key key) if (isValue!V) { if (auto index = getKeyIndex(key)) mixin("payload[*index] " ~ op ~ "= value;"); else { auto index = getNewIndex(); mixin("payload[index] " ~ op ~ "= value;"); keyToIndex[key] = index; indexToKey[index] = key; } } int opApply(scope int delegate(ref Key, ref Value) dg) { foreach (index; 0 .. lastIndex) { auto result = dg(indexToKey[index], payload[index]); if (result) return result; } return 0; } } void main() { auto names = ["1", "2", "3", "4", "5", "6", "7", "8"]; LinkedHash!(string[string]) stringMap; foreach (name; names) stringMap[name] ~= "test"; foreach (key, val; stringMap) writefln("%s: %s", key, val); LinkedHash!(string[][string]) stringArrMap; stringArrMap["100"] = ["foo"]; stringArrMap["101"] ~= "bar"; foreach (name; names) stringArrMap[name] ~= "test"; foreach (key, val; stringArrMap) writefln("%s: %s", key, val); }
Re: Map with maintained insertion order
On Friday, March 23, 2012 23:48:51 Andrej Mitrovic wrote: > Does someone have a map implementation that maintains the insertion > order of the keys? > > E.g.: > > string[string] map; > map["foo"] = "x"; > map["bar"] = "y"; > > When iterating over map keys I want to visit "foo" first, then "bar", and > so on. I can't think of any data structure that does that off the top of my head, though there may very well be one. If you don't mind the extra memory overhead, it wouldn't be all that hard to do it with multiple maps wrapped in a single type. You could do something like class InsertedOrderMap { string[string] _map; RedBlackTree!(Tuple!(int, string), "a[0] < b[0]") _insertionOrder; ... } _map holds the normal map and _insertionOrder holds pairs of the insertion ordered and the key to _map. You can then have your range iterate over _insertionOrder and use the keys to return either the keys, values, or pairs of keys and values from _map, depending on what you want to iterate over. That _does_ require having two data structures in one, and there may a be a better way to do it, but just off the top of my head, that's the best that I can come up with. I don't know how you could have a data structure where it's efficient to index by both insertion order and key without effectively having two data structures. But I really should go reread my data structures books. It's been too long since I studied that stuff. - Jonathan M Davis
Re: Freeing memory allocated at C function
On Fri, Mar 23, 2012 at 3:43 AM, Ali Çehreli wrote: > You can register on GC if you wrap the resources in a class. Then the > class object's destructor would call the clean up code. The problem is, it > is undeterministic when the destructor will be called, or will it be called > at all! > > Or you can wrap in a struct which has deterministic destruction like in > C++, when leaving scopes. > The object is long lived, so the class wrapper is the way to go. Thanks
Re: Confused by refusal to expand template
On 03/23/2012 11:58 PM, David wrote: Am 23.03.2012 23:52, schrieb H. S. Teoh: Code: struct S { int f(K)(K x) { return 1; } void func(K)(inout(K) x) { auto h = f(x); } } void main() { S s; s.func("abc"); // This is line 44 } This refuses to compile: test2.d(44): Error: template test2.S.func(K) does not match any function template declaration test2.d(44): Error: template test2.S.func(K) cannot deduce template function from argument types !()(string) Removing 'inout' fixes the problem. But I don't understand why. T I've never really used inout, but don't you need it also for the return-type? Not any more (DMD 2.059). See http://d.puremagic.com/issues/show_bug.cgi?id=7105 Furthermore you don't the the inout here, since this template does match const/immutable/nothing anyways. His intention probably is to prevent multiple instantiation of a template based on different constness.
Re: Confused by refusal to expand template
Am 23.03.2012 23:52, schrieb H. S. Teoh: Code: struct S { int f(K)(K x) { return 1; } void func(K)(inout(K) x) { auto h = f(x); } } void main() { S s; s.func("abc");// This is line 44 } This refuses to compile: test2.d(44): Error: template test2.S.func(K) does not match any function template declaration test2.d(44): Error: template test2.S.func(K) cannot deduce template function from argument types !()(string) Removing 'inout' fixes the problem. But I don't understand why. T I've never really used inout, but don't you need it also for the return-type? Furthermore you don't the the inout here, since this template does match const/immutable/nothing anyways.
Re: Confused by refusal to expand template
On 03/23/2012 11:52 PM, H. S. Teoh wrote: Code: struct S { int f(K)(K x) { return 1; } void func(K)(inout(K) x) { auto h = f(x); } } void main() { S s; s.func("abc");// This is line 44 } This refuses to compile: test2.d(44): Error: template test2.S.func(K) does not match any function template declaration test2.d(44): Error: template test2.S.func(K) cannot deduce template function from argument types !()(string) Removing 'inout' fixes the problem. But I don't understand why. T You already brought this up IIRC. The IFTI matching algorithm is too weak. I think it should work.
Confused by refusal to expand template
Code: struct S { int f(K)(K x) { return 1; } void func(K)(inout(K) x) { auto h = f(x); } } void main() { S s; s.func("abc"); // This is line 44 } This refuses to compile: test2.d(44): Error: template test2.S.func(K) does not match any function template declaration test2.d(44): Error: template test2.S.func(K) cannot deduce template function from argument types !()(string) Removing 'inout' fixes the problem. But I don't understand why. T -- Perhaps the most widespread illusion is that if we were in power we would behave very differently from those who now hold it---when, in truth, in order to get power we would have to become very much like them. -- Unknown
Map with maintained insertion order
Does someone have a map implementation that maintains the insertion order of the keys? E.g.: string[string] map; map["foo"] = "x"; map["bar"] = "y"; When iterating over map keys I want to visit "foo" first, then "bar", and so on.
Re: Template constraint and specializations
On 3/23/12, Philippe Sigaud wrote: > It works for me Yes but check the isA template. It seems there's something causing a nested variadic template to fail. This won't work in a template constraint (it returns false): template isA(alias Foo) { template isA(T) { enum bool isA = __traits(compiles, { void tester(Args...)(Foo!(Args) args); tester(T.init); }); } } alias isA!Foo isFoo; But if you change "Args..." to "Args" then it works, although only for single-type templates.. I'm not sure what's going on..
Re: Template constraint and specializations
On Fri, Mar 23, 2012 at 21:27, Andrej Mitrovic wrote: > That can't work. For a Foo!int your code will expand like so: > See for yourself: ? It works for me: template isBar(T) { enum isBar = __traits(compiles, { void tester(Args...)(Bar!Args arg) {} tester(T.init); }); } template isFoo(T) { enum isFoo = __traits(compiles, { void tester(Arg)(Foo!Arg arg) {} tester(T.init); }); } struct Foo(T) { } struct Bar(T...) {} void useFoo(T)(T t) if (isFoo!T) { } void useBar(T)(T t) if (isBar!T) { } void main() { Foo!int foo; useFoo(foo); Bar!(int, string, double) bar; useBar(bar); }
Re: string[] to char**
On 3/23/12, bearophile wrote: > This is one way to do it: > immutable(char)** p = array(map!toStringz(data)).ptr; This is asked so frequently that I think we could consider adding it to Phobos.
Re: Template constraint and specializations
On 3/23/12, Philippe Sigaud wrote: > testFoo is a function that accepts any Foo!( ... ) for any ... The > second line tests it on a value of type T (T.init). That can't work. For a Foo!int your code will expand like so: // original code void tester(Args...)(Foo!Args args); tester(T.init); void tester(Args...)(Foo!Args args); tester((Foo!int).init); // T is a template instance void tester(Foo!int)(Foo!(Foo!int) args); // Args.. becomes the template instance type tester((Foo!int).init); See for yourself: template isA(alias Foo) { template isA(T) { //~ pragma(msg, T.init); enum bool isA = __traits(compiles, { void tester(Args...)(Foo!Args args); tester(T.init); }); } } struct Foo(T) { } alias isA!Foo isFoo; void useFoo(T)(T t) if (isFoo!T) // no-go { } void main() { Foo!int foo; useFoo(foo); }
Re: string[] to char**
On 03/23/2012 11:23 AM, Ali Çehreli wrote: On 03/23/2012 08:48 AM, simendsjo wrote: > What's the best way to convert char** from string[]? In C, char** communicates transfer of ownership. Ok, I once again misunderstood the question. :( My question in the comment remains. Thank you, Ali
Re: string[] to char**
On 03/23/2012 08:48 AM, simendsjo wrote: > What's the best way to convert char** from string[]? In C, char** communicates transfer of ownership. Is that what you are trying to do? Are you going to pass a slice to a C function to be filled in by that C function? Such functions usually assign to *str. In that case you can use the "make slice from raw pointer" method below. I hope others will answer my concern in the comment below: import std.stdio; import std.c.stdlib; import std.c.string; void C_func_with_an_out_parameter(char ** str) { *str = cast(char*)calloc(1, 10); (*str)[0] = 'A'; (*str)[1] = '\0'; } void main() { char * p; C_func_with_an_out_parameter(&p); char[] slice = p[0..strlen(p)]; // <-- make a D slice /* * Note: I don't think that the memory that * std.stdlib.calloc() returns is managed by the GC. For * that reason, I don't think it will be safe to share the * element with another slice and expect normal behavior * of element-sharing between slices. * * In other words, this would be risky: * * char[] anotherSlice = slice; */ writeln(slice); free(p); } Ali
Re: Template constraint and specializations
On Fri, Mar 23, 2012 at 10:17, Ed McCardell wrote: >>> Is there a way to write a template constraint that matches any >>> >>> specialization of a given type? >> >> >> Nope. But there are simple workarounds: >> >> class Foo(bool feature1, bool feature2) { enum _isFoo = true; } >> >> template isFoo(T) { >> enum bool isFoo = __traits(hasMember, T, "_isFoo"); >> } Another solution that does not require you to add an _isFoo member: use template function instantiation: template isFoo(T) { enum bool isFoo = __traits(compiles, { void testFoo(Args...)(Foo!Args arg); testFoo(T.init); }); } testFoo is a function that accepts any Foo!( ... ) for any ... The second line tests it on a value of type T (T.init). This can be generalized even further, to create any template-testing function: template isA(alias Foo) { template isA(T) { enum bool isA = __traits(compiles, { void tester(Args...)(Foo!Args args); tester(T.init);}); } } usage: alias isA!Foo isFoo; template useFoo(T) if (isFoo!T) { }
Re: string[] to char**
On Friday, 23 March 2012 at 15:48:12 UTC, simendsjo wrote: What's the best way to convert char** from string[]? This is one way to do it: import std.algorithm, std.array, std.string, core.stdc.stdio; void main() { auto data = ["red", "yellow", "green"]; immutable(char)** p = array(map!toStringz(data)).ptr; printf("%s %s %s\n", p[0], p[1], p[2]); } Note: the pointer array is managed by the D GC. With DMD 2.059: immutable(char)** p = data.map!toStringz().array().ptr; Bye, bearophile
string[] to char**
What's the best way to convert char** from string[]?
Re: Calling c shared library
On Fri, 23 Mar 2012 15:04:48 +0100, simendsjo wrote: Forgive my programming 101 question :) I want to call a method from a precompiled shared library: // c header void f(void); // my d file extern(C) void f(); void main() {} $ dmd mydfile.d libphobos2.a(deh2_33a_525.o): In function `_D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable': src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0x4): undefined reference to `_deh_beg' src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0xc): undefined reference to `_deh_beg' src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0x13): undefined reference to `_deh_end' src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0x37): undefined reference to `_deh_end' collect2: ld returned 1 exit status --- errorlevel 1 Is there a way to do the above, or do I have to manually load the shared library and use alias'es for the functions? Stupidity has a new name, and it's simendsjo! I actually had extern(C): at the top of my file, but extern(C) void main() was nowhere to be found :)
Re: Vector operations optimization.
On Friday, 23 March 2012 at 11:20:59 UTC, Trass3r wrote: The flags you want are -O, -inline -release. If you don't have those, then that might explain some of the slow down on slicing, since -release drops a ton of runtime checks. -noboundscheck option can also speed up things. dmd is anyway very slow, ldc2 was better, but still not fast enough.
Re: Vector operations optimization.
On Friday, 23 March 2012 at 10:48:55 UTC, Dmitry Olshansky wrote: On 23.03.2012 9:57, Comrad wrote: On Thursday, 22 March 2012 at 10:43:35 UTC, Trass3r wrote: What is the status at the moment? What compiler and with which compiler flags I should use to achieve maximum performance? In general gdc or ldc. Not sure how good vectorization is though, esp. auto-vectorization. On the other hand the so called vector operations like a[] = b[] + c[]; are lowered to hand-written SSE assembly even in dmd. I had such a snippet to test: 1 import std.stdio; 2 void main() 3 { 4 double[2] a=[1.,0.]; 5 double[2] a1=[1.,0.]; 6 double[2] a2=[1.,0.]; 7 double[2] a3=[0.,0.]; Here is a culprit, the array ops [] are tuned for arbitrary long(!) arrays, they are not plain 1 simd SEE op. They are handcrafted loops(!) on SSE ops, cool and fast for arrays in general, not fixed pairs/trios/etc. I believe it might change in future, if compiler is able to deduce that size is fixed, and use more optimal code for small sizes. So currently there is no such an optimization exists for any d compiler?
Calling c shared library
Forgive my programming 101 question :) I want to call a method from a precompiled shared library: // c header void f(void); // my d file extern(C) void f(); void main() {} $ dmd mydfile.d libphobos2.a(deh2_33a_525.o): In function `_D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable': src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0x4): undefined reference to `_deh_beg' src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0xc): undefined reference to `_deh_beg' src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0x13): undefined reference to `_deh_end' src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0x37): undefined reference to `_deh_end' collect2: ld returned 1 exit status --- errorlevel 1 Is there a way to do the above, or do I have to manually load the shared library and use alias'es for the functions?
Re: Template constraint and specializations
Andrej Mitrovic: Nope. But there are simple workarounds: Why isn't something similar to this working? import std.traits: Unqual; class Foo(bool feature1, bool feature2) {} template isFoo(T) { static if (is(Unqual!T Unused : Foo!Features, Features...)) { enum isFoo = true; } else { enum isFoo = false; } } void main() { auto f1 = new Foo!(true, false)(); static assert(isFoo!(typeof(f1))); } Bye, bearophile
Re: Vector operations optimization.
The flags you want are -O, -inline -release. If you don't have those, then that might explain some of the slow down on slicing, since -release drops a ton of runtime checks. -noboundscheck option can also speed up things.
Re: Vector operations optimization.
On 23.03.2012 9:57, Comrad wrote: On Thursday, 22 March 2012 at 10:43:35 UTC, Trass3r wrote: What is the status at the moment? What compiler and with which compiler flags I should use to achieve maximum performance? In general gdc or ldc. Not sure how good vectorization is though, esp. auto-vectorization. On the other hand the so called vector operations like a[] = b[] + c[]; are lowered to hand-written SSE assembly even in dmd. I had such a snippet to test: 1 import std.stdio; 2 void main() 3 { 4 double[2] a=[1.,0.]; 5 double[2] a1=[1.,0.]; 6 double[2] a2=[1.,0.]; 7 double[2] a3=[0.,0.]; Here is a culprit, the array ops [] are tuned for arbitrary long(!) arrays, they are not plain 1 simd SEE op. They are handcrafted loops(!) on SSE ops, cool and fast for arrays in general, not fixed pairs/trios/etc. I believe it might change in future, if compiler is able to deduce that size is fixed, and use more optimal code for small sizes. 8 foreach(i;0..10) 9 a3[]+=a[]+a1[]*a2[]; 10 writeln(a3); 11 } And I compared with the following d code: 1 import std.stdio; 2 void main() 3 { 4 double[2] a=[1.,0.]; 5 double[2] a1=[1.,0.]; 6 double[2] a2=[1.,0.]; 7 double[2] a3=[0.,0.]; 8 foreach(i;0..10) 9 { 10 a3[0]+=a[0]+a1[0]*a2[0]; 11 a3[1]+=a[1]+a1[1]*a2[1]; 12 } 13 writeln(a3); 14 } And with the following c code: 1 #include 2 int main() 3 { 4 double a[2]={1.,0.}; 5 double a1[2]={1.,0.}; 6 double a2[2]={1.,0.}; 7 double a3[2]; 8 unsigned i; 9 for(i=0;i<10;++i) 10 { 11 a3[0]+=a[0]+a1[0]*a2[0]; 12 a3[1]+=a[1]+a1[1]*a2[1]; 13 } 14 printf("%f %f\n",a3[0],a3[1]); 15 return 0; 16 } The last one I compiled with gcc two previous with dmd and ldc. C code with -O2 was the fastest and as fast as d without slicing compiled with ldc. d code with slicing was 3 times slower (ldc compiler). I tried to compile with different optimization flags, that didn't help. Maybe I used the wrong ones. Can someone comment on this? -- Dmitry Olshansky
Re: Template constraint and specializations
On 03/23/2012 04:14 AM, Andrej Mitrovic wrote: On 3/23/12, Ed McCardell wrote: Is there a way to write a template constraint that matches any specialization of a given type? Nope. But there are simple workarounds: class Foo(bool feature1, bool feature2) { enum _isFoo = true; } template isFoo(T) { enum bool isFoo = __traits(hasMember, T, "_isFoo"); } Thanks! I was tempted to try something hacky for the constraint, like if (T.stringof == "Foo") but tagging the type with an enum works better all around. --Ed
Re: Template constraint and specializations
On 3/23/12, Ed McCardell wrote: > Is there a way to write a template constraint that matches any > specialization of a given type? Nope. But there are simple workarounds: class Foo(bool feature1, bool feature2) { enum _isFoo = true; } template isFoo(T) { enum bool isFoo = __traits(hasMember, T, "_isFoo"); } void useFoo(T)(T foo) if (isFoo!T) { // call methods of foo that don't change based on feature1/feature2 } void main() { Foo!(true, false) foo; useFoo(foo); }
Template constraint and specializations
Is there a way to write a template constraint that matches any specialization of a given type? For example can the following be done without having to write out every combination of feature1 and feature2: class Foo(bool feature1, bool feature2) { ... } void useFoo(T)(T foo) if (is(T == Foo!(false, false)) || is(T == Foo!(false, true)) || is(T == Foo!(true, false)) || is(T == Foo!(true, true))) { // call methods of foo that don't change based on feature1/feature2 } Thanks, --Ed